[DOCKER][MAIL] Setup docker mail server
This commit is contained in:
parent
250235b1be
commit
bc1d85de56
13
dockermail/.env
Normal file
13
dockermail/.env
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
MYSQL_DATABASE=mailserver
|
||||||
|
MYSQL_USER=mailserver
|
||||||
|
MYSQL_PASSWORD=changeme
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme
|
||||||
|
MAILNAME=mail.example.com
|
||||||
|
POSTMASTER=postmaster@example.com
|
||||||
|
RELAYHOST=false
|
||||||
|
FILTER_MIME=false
|
||||||
|
FILTER_VIRUS=true
|
||||||
|
ENABLE_IMAP=true
|
||||||
|
ENABLE_POP3=true
|
||||||
|
CONTROLLER_PASSWORD=changeme
|
||||||
|
WAITSTART_TIMEOUT=2m
|
21
dockermail/LICENSE
Normal file
21
dockermail/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Jeffrey Boehm
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -1,6 +1,9 @@
|
|||||||
To start, run setup.sh choose name and domain and create the first email account. Then open mailserver/ and run 'docker-compose up'
|
POP3 STARTTLS 127.0.0.1:110
|
||||||
To change settings read mailserver/env-mailserver
|
POP3S 127.0.0.1:995
|
||||||
|
IMAP STARTTLS 127.0.0.1:143
|
||||||
To update, run update.sh
|
IMAPS 127.0.0.1:993
|
||||||
|
SMTP 127.0.0.1:25
|
||||||
Add more accounts with add_account.sh and send mails with send_mail.sh
|
Mail Submission STARTTLS 127.0.0.1:587
|
||||||
|
Management Interface 127.0.0.1:81/manager/
|
||||||
|
Webmail 127.0.0.1:81/webmail/
|
||||||
|
Rspamd interface 127.0.0.1:81/rspamd/
|
@ -1,8 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
read -p "EMAIL: " user
|
|
||||||
read -s -p "PASS: " password
|
|
||||||
printf "\n"
|
|
||||||
|
|
||||||
bash mailserver/setup.sh email add "$user" "$password"
|
|
||||||
|
|
10
dockermail/db/Dockerfile
Normal file
10
dockermail/db/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
FROM mysql:5.7
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
|
||||||
|
ENV MYSQL_DATABASE=mailserver \
|
||||||
|
MYSQL_USER=mailserver \
|
||||||
|
MYSQL_PASSWORD=changeme \
|
||||||
|
MYSQL_ROOT_PASSWORD=changeme
|
||||||
|
|
||||||
|
COPY rootfs/ /
|
||||||
|
VOLUME /run/mysqld
|
@ -0,0 +1,82 @@
|
|||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
|
||||||
|
# Export von Tabelle mail_aliases
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `mail_aliases`;
|
||||||
|
|
||||||
|
CREATE TABLE `mail_aliases` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`domain_id` int(11) DEFAULT NULL,
|
||||||
|
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
`destination` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `alias_idx` (`domain_id`,`name`,`destination`),
|
||||||
|
KEY `IDX_85AF3A56115F0EE5` (`domain_id`),
|
||||||
|
CONSTRAINT `FK_5F12BB39115F0EE5` FOREIGN KEY (`domain_id`) REFERENCES `mail_domains` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
# Export von Tabelle mail_domains
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `mail_domains`;
|
||||||
|
|
||||||
|
CREATE TABLE `mail_domains` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `UNIQ_56C63EF25E237E06` (`name`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||||
|
|
||||||
|
# Export von Tabelle mail_users
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `mail_users`;
|
||||||
|
|
||||||
|
CREATE TABLE `mail_users` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`domain_id` int(11) DEFAULT NULL,
|
||||||
|
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
`password` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `user_idx` (`name`,`domain_id`),
|
||||||
|
KEY `IDX_20400786115F0EE5` (`domain_id`),
|
||||||
|
CONSTRAINT `FK_1483A5E9115F0EE5` FOREIGN KEY (`domain_id`) REFERENCES `mail_domains` (`id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
# Export von Tabelle migration_versions
|
||||||
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `migration_versions`;
|
||||||
|
|
||||||
|
CREATE TABLE `migration_versions` (
|
||||||
|
`version` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
|
||||||
|
PRIMARY KEY (`version`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||||
|
|
||||||
|
LOCK TABLES `migration_versions` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `migration_versions` DISABLE KEYS */;
|
||||||
|
|
||||||
|
INSERT INTO `migration_versions` (`version`)
|
||||||
|
VALUES
|
||||||
|
('20180320164351'),
|
||||||
|
('20180320171339');
|
||||||
|
|
||||||
|
/*!40000 ALTER TABLE `migration_versions` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
226
dockermail/db/rootfs/docker-entrypoint-initdb.d/002_webmail.sql
Normal file
226
dockermail/db/rootfs/docker-entrypoint-initdb.d/002_webmail.sql
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
-- Roundcube Webmail initial database structure
|
||||||
|
|
||||||
|
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
|
||||||
|
-- Table structure for table `session`
|
||||||
|
|
||||||
|
CREATE TABLE `session` (
|
||||||
|
`sess_id` varchar(128) NOT NULL,
|
||||||
|
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
`ip` varchar(40) NOT NULL,
|
||||||
|
`vars` mediumtext NOT NULL,
|
||||||
|
PRIMARY KEY(`sess_id`),
|
||||||
|
INDEX `changed_index` (`changed`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `users`
|
||||||
|
|
||||||
|
CREATE TABLE `users` (
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`username` varchar(128) BINARY NOT NULL,
|
||||||
|
`mail_host` varchar(128) NOT NULL,
|
||||||
|
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
`last_login` datetime DEFAULT NULL,
|
||||||
|
`failed_login` datetime DEFAULT NULL,
|
||||||
|
`failed_login_counter` int(10) UNSIGNED DEFAULT NULL,
|
||||||
|
`language` varchar(5),
|
||||||
|
`preferences` longtext,
|
||||||
|
PRIMARY KEY(`user_id`),
|
||||||
|
UNIQUE `username` (`username`, `mail_host`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `cache`
|
||||||
|
|
||||||
|
CREATE TABLE `cache` (
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`cache_key` varchar(128) BINARY NOT NULL,
|
||||||
|
`expires` datetime DEFAULT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
PRIMARY KEY (`user_id`, `cache_key`),
|
||||||
|
CONSTRAINT `user_id_fk_cache` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `expires_index` (`expires`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `cache_shared`
|
||||||
|
|
||||||
|
CREATE TABLE `cache_shared` (
|
||||||
|
`cache_key` varchar(255) BINARY NOT NULL,
|
||||||
|
`expires` datetime DEFAULT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
PRIMARY KEY (`cache_key`),
|
||||||
|
INDEX `expires_index` (`expires`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `cache_index`
|
||||||
|
|
||||||
|
CREATE TABLE `cache_index` (
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`mailbox` varchar(255) BINARY NOT NULL,
|
||||||
|
`expires` datetime DEFAULT NULL,
|
||||||
|
`valid` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
CONSTRAINT `user_id_fk_cache_index` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `expires_index` (`expires`),
|
||||||
|
PRIMARY KEY (`user_id`, `mailbox`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `cache_thread`
|
||||||
|
|
||||||
|
CREATE TABLE `cache_thread` (
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`mailbox` varchar(255) BINARY NOT NULL,
|
||||||
|
`expires` datetime DEFAULT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
CONSTRAINT `user_id_fk_cache_thread` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `expires_index` (`expires`),
|
||||||
|
PRIMARY KEY (`user_id`, `mailbox`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `cache_messages`
|
||||||
|
|
||||||
|
CREATE TABLE `cache_messages` (
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`mailbox` varchar(255) BINARY NOT NULL,
|
||||||
|
`uid` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
||||||
|
`expires` datetime DEFAULT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
`flags` int(11) NOT NULL DEFAULT '0',
|
||||||
|
CONSTRAINT `user_id_fk_cache_messages` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `expires_index` (`expires`),
|
||||||
|
PRIMARY KEY (`user_id`, `mailbox`, `uid`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `contacts`
|
||||||
|
|
||||||
|
CREATE TABLE `contacts` (
|
||||||
|
`contact_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
`del` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`name` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`email` text NOT NULL,
|
||||||
|
`firstname` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`surname` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`vcard` longtext NULL,
|
||||||
|
`words` text NULL,
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
PRIMARY KEY(`contact_id`),
|
||||||
|
CONSTRAINT `user_id_fk_contacts` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `user_contacts_index` (`user_id`,`del`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
-- Table structure for table `contactgroups`
|
||||||
|
|
||||||
|
CREATE TABLE `contactgroups` (
|
||||||
|
`contactgroup_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
`del` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`name` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
PRIMARY KEY(`contactgroup_id`),
|
||||||
|
CONSTRAINT `user_id_fk_contactgroups` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `contactgroups_user_index` (`user_id`,`del`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
CREATE TABLE `contactgroupmembers` (
|
||||||
|
`contactgroup_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`contact_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
PRIMARY KEY (`contactgroup_id`, `contact_id`),
|
||||||
|
CONSTRAINT `contactgroup_id_fk_contactgroups` FOREIGN KEY (`contactgroup_id`)
|
||||||
|
REFERENCES `contactgroups`(`contactgroup_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
CONSTRAINT `contact_id_fk_contacts` FOREIGN KEY (`contact_id`)
|
||||||
|
REFERENCES `contacts`(`contact_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `contactgroupmembers_contact_index` (`contact_id`)
|
||||||
|
) /*!40000 ENGINE=INNODB */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `identities`
|
||||||
|
|
||||||
|
CREATE TABLE `identities` (
|
||||||
|
`identity_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
|
||||||
|
`del` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`standard` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
`name` varchar(128) NOT NULL,
|
||||||
|
`organization` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`email` varchar(128) NOT NULL,
|
||||||
|
`reply-to` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`bcc` varchar(128) NOT NULL DEFAULT '',
|
||||||
|
`signature` longtext,
|
||||||
|
`html_signature` tinyint(1) NOT NULL DEFAULT '0',
|
||||||
|
PRIMARY KEY(`identity_id`),
|
||||||
|
CONSTRAINT `user_id_fk_identities` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
INDEX `user_identities_index` (`user_id`, `del`),
|
||||||
|
INDEX `email_identities_index` (`email`, `del`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `dictionary`
|
||||||
|
|
||||||
|
CREATE TABLE `dictionary` (
|
||||||
|
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, -- redundant, for compat. with Galera Cluster
|
||||||
|
`user_id` int(10) UNSIGNED DEFAULT NULL, -- NULL here is for "shared dictionaries"
|
||||||
|
`language` varchar(5) NOT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
CONSTRAINT `user_id_fk_dictionary` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
UNIQUE `uniqueness` (`user_id`, `language`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Table structure for table `searches`
|
||||||
|
|
||||||
|
CREATE TABLE `searches` (
|
||||||
|
`search_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`type` int(3) NOT NULL DEFAULT '0',
|
||||||
|
`name` varchar(128) NOT NULL,
|
||||||
|
`data` text,
|
||||||
|
PRIMARY KEY(`search_id`),
|
||||||
|
CONSTRAINT `user_id_fk_searches` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users`(`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
UNIQUE `uniqueness` (`user_id`, `type`, `name`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
-- Table structure for table `filestore`
|
||||||
|
|
||||||
|
CREATE TABLE `filestore` (
|
||||||
|
`file_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||||
|
`user_id` int(10) UNSIGNED NOT NULL,
|
||||||
|
`context` varchar(32) NOT NULL,
|
||||||
|
`filename` varchar(128) NOT NULL,
|
||||||
|
`mtime` int(10) NOT NULL,
|
||||||
|
`data` longtext NOT NULL,
|
||||||
|
PRIMARY KEY (`file_id`),
|
||||||
|
CONSTRAINT `user_id_fk_filestore` FOREIGN KEY (`user_id`)
|
||||||
|
REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||||
|
UNIQUE `uniqueness` (`user_id`, `context`, `filename`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
-- Table structure for table `system`
|
||||||
|
|
||||||
|
CREATE TABLE `system` (
|
||||||
|
`name` varchar(64) NOT NULL,
|
||||||
|
`value` mediumtext,
|
||||||
|
PRIMARY KEY(`name`)
|
||||||
|
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
|
||||||
|
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=1 */;
|
||||||
|
|
||||||
|
INSERT INTO `system` (`name`, `value`) VALUES ('roundcube-version', '2019092900');
|
125
dockermail/docker-compose.yml
Normal file
125
dockermail/docker-compose.yml
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
version: '3.5'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Creates self signed tls certificates. Remove if you
|
||||||
|
# use your own.
|
||||||
|
ssl:
|
||||||
|
image: jeboehm/mailserver-ssl:latest
|
||||||
|
build: ./ssl
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-tls:/media/tls:rw
|
||||||
|
|
||||||
|
# Responsible for storing users and their aliases. Remove
|
||||||
|
# if you already have a MySQL server.
|
||||||
|
db:
|
||||||
|
image: jeboehm/mailserver-db:latest
|
||||||
|
build: ./db
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-db:/var/lib/mysql
|
||||||
|
|
||||||
|
# The Mail Transfer Agent (Postfix) receives incoming mail
|
||||||
|
# on TCP port 25.
|
||||||
|
mta:
|
||||||
|
image: jeboehm/mailserver-mta:latest
|
||||||
|
build: ./mta
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-tls:/media/tls:ro
|
||||||
|
# For using external certificates uncomment the following lines
|
||||||
|
# and change the path on the left side of the colon.
|
||||||
|
# - /home/user/certs/mail.example.com.crt:/media/tls/mailserver.crt:ro
|
||||||
|
# - /home/user/certs/mail.example.com.key:/media/tls/mailserver.key:ro
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:25:25"
|
||||||
|
|
||||||
|
# The Mail Delivery Agent (Dovecot) is responsible for storing
|
||||||
|
# incoming mail into a users mailbox and also delivers them
|
||||||
|
# via POP3 or IMAP4.
|
||||||
|
mda:
|
||||||
|
image: jeboehm/mailserver-mda:latest
|
||||||
|
build: ./mda
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-mail:/var/vmail
|
||||||
|
- data-tls:/media/tls:ro
|
||||||
|
# For using external certificates uncomment the following lines
|
||||||
|
# and change the path on the left side of the colon.
|
||||||
|
# - /home/user/certs/mail.example.com.crt:/media/tls/mailserver.crt:ro
|
||||||
|
# - /home/user/certs/mail.example.com.key:/media/tls/mailserver.key:ro
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:143:143"
|
||||||
|
- "0.0.0.0:993:993"
|
||||||
|
- "0.0.0.0:110:110"
|
||||||
|
- "0.0.0.0:995:995"
|
||||||
|
- "0.0.0.0:587:587"
|
||||||
|
|
||||||
|
# The admin (mailserver-admin) and webmail (roundcube) interfaces
|
||||||
|
# live here. Can be removed if not needed.
|
||||||
|
web:
|
||||||
|
image: jeboehm/mailserver-web:latest
|
||||||
|
build: ./web
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-dkim:/media/dkim
|
||||||
|
# For use with jwilder/nginx-proxy.
|
||||||
|
# environment:
|
||||||
|
# - VIRTUAL_HOST=mail.example.com
|
||||||
|
ports:
|
||||||
|
- "0.0.0.0:81:80"
|
||||||
|
|
||||||
|
# Incoming spam is (hopefully) filtered by rspamd which runs
|
||||||
|
# in this service.
|
||||||
|
filter:
|
||||||
|
image: jeboehm/mailserver-filter:latest
|
||||||
|
build: ./filter
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-filter:/var/lib/rspamd
|
||||||
|
- data-dkim:/media/dkim
|
||||||
|
links:
|
||||||
|
- virus:virus.local
|
||||||
|
|
||||||
|
# Incoming viruses or malware is detected and rejected by
|
||||||
|
# this service. Can be removed if FILTER_VIRUS is set to false.
|
||||||
|
virus:
|
||||||
|
image: jeboehm/mailserver-virus:latest
|
||||||
|
build: ./virus
|
||||||
|
restart: on-failure:5
|
||||||
|
env_file: .env
|
||||||
|
volumes:
|
||||||
|
- data-virusdb:/var/lib/clamav
|
||||||
|
|
||||||
|
# If you want unhealthy containers to be restarted automatically
|
||||||
|
# just uncomment the following lines.
|
||||||
|
# autoheal:
|
||||||
|
# image: willfarrell/autoheal:latest
|
||||||
|
# restart: always
|
||||||
|
# networks: []
|
||||||
|
# volumes:
|
||||||
|
# - /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
# environment:
|
||||||
|
# - AUTOHEAL_CONTAINER_LABEL=de.ressourcenkonflikt.docker-mailserver.autoheal
|
||||||
|
|
||||||
|
# Optional service: extend ClamAV (used in the virus service)
|
||||||
|
# by downloading additional databases provided by different
|
||||||
|
# companys. Run it regulary.
|
||||||
|
# virus_unof_sig_updater:
|
||||||
|
# build: ./virus/contrib/unofficial-sigs
|
||||||
|
# env_file: .env
|
||||||
|
# volumes:
|
||||||
|
# - data-virusdb:/var/lib/clamav
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
data-db:
|
||||||
|
data-dkim:
|
||||||
|
data-mail:
|
||||||
|
data-tls:
|
||||||
|
data-filter:
|
||||||
|
data-virusdb:
|
45
dockermail/filter/Dockerfile
Normal file
45
dockermail/filter/Dockerfile
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
ARG DOCKERIZE_VER=0.6.0
|
||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM jwilder/dockerize:${DOCKERIZE_VER} AS dockerize
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"
|
||||||
|
|
||||||
|
ENV FILTER_VIRUS=false \
|
||||||
|
FILTER_VIRUS_HOST=virus.local \
|
||||||
|
WAITSTART_TIMEOUT=1m \
|
||||||
|
CONTROLLER_PASSWORD=changeme
|
||||||
|
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
openssl \
|
||||||
|
rspamd \
|
||||||
|
rspamd-client \
|
||||||
|
rspamd-controller \
|
||||||
|
rspamd-proxy && \
|
||||||
|
mkdir /run/rspamd && \
|
||||||
|
touch \
|
||||||
|
/etc/rspamd/local.d/antivirus.conf \
|
||||||
|
/etc/rspamd/local.d/worker-controller.inc && \
|
||||||
|
chown -R rspamd \
|
||||||
|
/run/rspamd \
|
||||||
|
/var/lib/rspamd \
|
||||||
|
/etc/rspamd/local.d/antivirus.conf \
|
||||||
|
/etc/rspamd/local.d/worker-controller.inc && \
|
||||||
|
wget -O /usr/share/rspamd/bayes.spam.sqlite https://rspamd.com/rspamd_statistics/bayes.spam.sqlite && \
|
||||||
|
wget -O /usr/share/rspamd/bayes.ham.sqlite https://rspamd.com/rspamd_statistics/bayes.ham.sqlite && \
|
||||||
|
apk --no-cache del \
|
||||||
|
openssl
|
||||||
|
|
||||||
|
COPY --from=dockerize /usr/local/bin/dockerize /usr/local/bin
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
EXPOSE 11332 11334
|
||||||
|
USER rspamd
|
||||||
|
|
||||||
|
VOLUME ["/var/lib/rspamd"]
|
||||||
|
|
||||||
|
HEALTHCHECK CMD wget -O- -T 10 http://127.0.0.1:11334/stat
|
||||||
|
CMD ["/usr/local/bin/entrypoint.sh"]
|
@ -0,0 +1,11 @@
|
|||||||
|
{{ $filter_virus := eq (or ($.Env.FILTER_VIRUS) "") "true" }}
|
||||||
|
|
||||||
|
{{ if $filter_virus }}
|
||||||
|
clamav {
|
||||||
|
scan_mime_parts = false;
|
||||||
|
symbol = "CLAM_VIRUS";
|
||||||
|
type = "clamav";
|
||||||
|
action = "reject";
|
||||||
|
servers = "{{$.Env.FILTER_VIRUS_HOST}}:3310";
|
||||||
|
}
|
||||||
|
{{ end }}
|
@ -0,0 +1 @@
|
|||||||
|
autolearn = true;
|
@ -0,0 +1,2 @@
|
|||||||
|
path = "/media/dkim/$domain.$selector.key";
|
||||||
|
selector_map = "/media/dkim/dkim_selectors.map";
|
1
dockermail/filter/rootfs/etc/rspamd/local.d/logging.inc
Normal file
1
dockermail/filter/rootfs/etc/rspamd/local.d/logging.inc
Normal file
@ -0,0 +1 @@
|
|||||||
|
type = console
|
11
dockermail/filter/rootfs/etc/rspamd/local.d/metrics.conf
Normal file
11
dockermail/filter/rootfs/etc/rspamd/local.d/metrics.conf
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
group "rbl" {
|
||||||
|
symbol "RBL_NIXSPAM_BAD" {
|
||||||
|
weight = 7.0;
|
||||||
|
description = "From address is listed in ix.dnsbl.manitu.net BL";
|
||||||
|
}
|
||||||
|
|
||||||
|
symbol "RBL_NIXSPAM" {
|
||||||
|
weight = 0.0;
|
||||||
|
description = "Unrecognised result from ix.dnsbl.manitu.net BL";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
extended_spam_headers = true;
|
7
dockermail/filter/rootfs/etc/rspamd/local.d/options.inc
Normal file
7
dockermail/filter/rootfs/etc/rspamd/local.d/options.inc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
dns {
|
||||||
|
timeout = 1s;
|
||||||
|
sockets = 16;
|
||||||
|
retransmits = 2;
|
||||||
|
nameserver = [ "8.8.8.8:53", "8.8.4.4:53", "1.1.1.1:53", "1.0.0.1:53" ];
|
||||||
|
}
|
||||||
|
|
9
dockermail/filter/rootfs/etc/rspamd/local.d/rbl.conf
Normal file
9
dockermail/filter/rootfs/etc/rspamd/local.d/rbl.conf
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
rbls {
|
||||||
|
nixspam {
|
||||||
|
symbol = "RBL_NIXSPAM";
|
||||||
|
rbl = "ix.dnsbl.manitu.net";
|
||||||
|
returncodes {
|
||||||
|
RBL_NIXSPAM_BAD = "127.0.0.2";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
bind_socket = "*:11334";
|
||||||
|
secure_ip = "127.0.0.1";
|
||||||
|
secure_ip = "::1";
|
||||||
|
secure_ip = "172.16.0.0/12";
|
||||||
|
password = "{{$.Env.CONTROLLER_PASSWORD_ENC}}"
|
@ -0,0 +1 @@
|
|||||||
|
bind_socket = "*:11332";
|
32
dockermail/filter/rootfs/usr/local/bin/entrypoint.sh
Normal file
32
dockermail/filter/rootfs/usr/local/bin/entrypoint.sh
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
FILTER_VIRUS_ARGS=""
|
||||||
|
if [ ${FILTER_VIRUS} == "true" ]
|
||||||
|
then
|
||||||
|
FILTER_VIRUS_ARGS="-wait tcp://${FILTER_VIRUS_HOST}:3310"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -f /var/lib/rspamd/bayes.spam.sqlite ]
|
||||||
|
then
|
||||||
|
cp /usr/share/rspamd/bayes.spam.sqlite /var/lib/rspamd/bayes.spam.sqlite
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -f /var/lib/rspamd/bayes.ham.sqlite ]
|
||||||
|
then
|
||||||
|
cp /usr/share/rspamd/bayes.ham.sqlite /var/lib/rspamd/bayes.ham.sqlite
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${CONTROLLER_PASSWORD}" == "changeme" ]
|
||||||
|
then
|
||||||
|
# q1 is disabled in rspamd.
|
||||||
|
export CONTROLLER_PASSWORD_ENC="q1"
|
||||||
|
else
|
||||||
|
export CONTROLLER_PASSWORD_ENC=`rspamadm pw -e -p ${CONTROLLER_PASSWORD}`
|
||||||
|
fi
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-template /etc/rspamd/local.d/antivirus.conf.templ:/etc/rspamd/local.d/antivirus.conf \
|
||||||
|
-template /etc/rspamd/local.d/worker-controller.inc.templ:/etc/rspamd/local.d/worker-controller.inc \
|
||||||
|
${FILTER_VIRUS_ARGS} \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT} \
|
||||||
|
/usr/sbin/rspamd -c /etc/rspamd/rspamd.conf -f
|
47
dockermail/mda/Dockerfile
Normal file
47
dockermail/mda/Dockerfile
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
ARG DOCKERIZE_VER=0.6.0
|
||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM jwilder/dockerize:${DOCKERIZE_VER} AS dockerize
|
||||||
|
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"
|
||||||
|
|
||||||
|
ENV MYSQL_HOST=db \
|
||||||
|
MYSQL_USER=root \
|
||||||
|
MYSQL_PASSWORD=changeme \
|
||||||
|
MYSQL_DATABASE=mailserver \
|
||||||
|
MAILNAME=mail.example.com \
|
||||||
|
POSTMASTER=postmaster@example.com \
|
||||||
|
SUBMISSION_HOST=mta \
|
||||||
|
ENABLE_POP3=true \
|
||||||
|
ENABLE_IMAP=true \
|
||||||
|
SSL_CERT=/media/tls/mailserver.crt \
|
||||||
|
SSL_KEY=/media/tls/mailserver.key \
|
||||||
|
WAITSTART_TIMEOUT=1m
|
||||||
|
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
curl \
|
||||||
|
dovecot \
|
||||||
|
dovecot-lmtpd \
|
||||||
|
dovecot-mysql \
|
||||||
|
dovecot-pigeonhole-plugin \
|
||||||
|
dovecot-pop3d \
|
||||||
|
dovecot-submissiond && \
|
||||||
|
adduser -h /var/vmail -u 5000 -D vmail && \
|
||||||
|
rm -rf /etc/ssl/dovecot && \
|
||||||
|
openssl dhparam -out /etc/dovecot/dh.pem 2048
|
||||||
|
|
||||||
|
COPY --from=dockerize /usr/local/bin/dockerize /usr/local/bin
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
RUN sievec /etc/dovecot/sieve/global/spam-to-folder.sieve && \
|
||||||
|
sievec /etc/dovecot/sieve/global/learn-ham.sieve && \
|
||||||
|
sievec /etc/dovecot/sieve/global/learn-spam.sieve
|
||||||
|
|
||||||
|
EXPOSE 2003 4190 143 110 993 995
|
||||||
|
VOLUME ["/var/vmail"]
|
||||||
|
|
||||||
|
HEALTHCHECK CMD echo "? LOGOUT" | nc 127.0.0.1 143 | grep "Dovecot ready."
|
||||||
|
CMD ["/usr/local/bin/entrypoint.sh"]
|
3
dockermail/mda/rootfs/etc/dovecot/conf.d/10-auth.conf
Normal file
3
dockermail/mda/rootfs/etc/dovecot/conf.d/10-auth.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
auth_mechanisms = plain login
|
||||||
|
|
||||||
|
!include auth-sql.conf.ext
|
2
dockermail/mda/rootfs/etc/dovecot/conf.d/10-logging.conf
Normal file
2
dockermail/mda/rootfs/etc/dovecot/conf.d/10-logging.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
log_path = /dev/stderr
|
||||||
|
info_log_path = /dev/stdout
|
10
dockermail/mda/rootfs/etc/dovecot/conf.d/10-mail.conf
Normal file
10
dockermail/mda/rootfs/etc/dovecot/conf.d/10-mail.conf
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
mail_location = maildir:/var/vmail/%d/%n/Maildir
|
||||||
|
mail_home = /var/vmail/%d/%n
|
||||||
|
mail_uid = vmail
|
||||||
|
mail_gid = vmail
|
||||||
|
mail_privileged_group = vmail
|
||||||
|
mail_plugins = $mail_plugins quota
|
||||||
|
|
||||||
|
namespace inbox {
|
||||||
|
inbox = yes
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
protocols = lmtp submission
|
||||||
|
|
||||||
|
{{ $enable_pop3 := eq (or ($.Env.ENABLE_POP3) "") "true" }}
|
||||||
|
{{ $enable_imap := eq (or ($.Env.ENABLE_IMAP) "") "true" }}
|
||||||
|
|
||||||
|
{{ if $enable_imap }}
|
||||||
|
service imap-login {
|
||||||
|
inet_listener imap {
|
||||||
|
#port = 143
|
||||||
|
}
|
||||||
|
|
||||||
|
inet_listener imaps {
|
||||||
|
#port = 993
|
||||||
|
#ssl = yes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service imap {
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols = $protocols imap
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $enable_pop3 }}
|
||||||
|
service pop3-login {
|
||||||
|
inet_listener pop3 {
|
||||||
|
#port = 110
|
||||||
|
}
|
||||||
|
|
||||||
|
inet_listener pop3s {
|
||||||
|
#port = 995
|
||||||
|
#ssl = yes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service pop3 {
|
||||||
|
}
|
||||||
|
|
||||||
|
protocols = $protocols pop3
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
service submission-login {
|
||||||
|
inet_listener submission {
|
||||||
|
#port = 587
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service submission {
|
||||||
|
#process_limit = 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
service lmtp {
|
||||||
|
inet_listener lmtp {
|
||||||
|
port = 2003
|
||||||
|
}
|
||||||
|
}
|
4
dockermail/mda/rootfs/etc/dovecot/conf.d/10-ssl.conf
Normal file
4
dockermail/mda/rootfs/etc/dovecot/conf.d/10-ssl.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
ssl = yes
|
||||||
|
ssl_cert = </media/tls/mailserver.crt
|
||||||
|
ssl_key = </media/tls/mailserver.key
|
||||||
|
ssl_dh = </etc/dovecot/dh.pem
|
@ -0,0 +1,5 @@
|
|||||||
|
postmaster_address = {{ .Env.POSTMASTER }}
|
||||||
|
hostname = {{ .Env.MAILNAME }}
|
||||||
|
submission_host = {{ .Env.SUBMISSION_HOST }}
|
||||||
|
lda_mailbox_autosubscribe = yes
|
||||||
|
recipient_delimiter = -
|
24
dockermail/mda/rootfs/etc/dovecot/conf.d/15-mailboxes.conf
Normal file
24
dockermail/mda/rootfs/etc/dovecot/conf.d/15-mailboxes.conf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace inbox {
|
||||||
|
mailbox Drafts {
|
||||||
|
auto = subscribe
|
||||||
|
special_use = \Drafts
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox Junk {
|
||||||
|
auto = subscribe
|
||||||
|
special_use = \Junk
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox Trash {
|
||||||
|
auto = subscribe
|
||||||
|
special_use = \Trash
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox Sent {
|
||||||
|
special_use = \Sent
|
||||||
|
}
|
||||||
|
|
||||||
|
mailbox "Sent Messages" {
|
||||||
|
special_use = \Sent
|
||||||
|
}
|
||||||
|
}
|
3
dockermail/mda/rootfs/etc/dovecot/conf.d/20-imap.conf
Normal file
3
dockermail/mda/rootfs/etc/dovecot/conf.d/20-imap.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
protocol imap {
|
||||||
|
mail_plugins = $mail_plugins imap_sieve imap_quota
|
||||||
|
}
|
3
dockermail/mda/rootfs/etc/dovecot/conf.d/20-lmtp.conf
Normal file
3
dockermail/mda/rootfs/etc/dovecot/conf.d/20-lmtp.conf
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
protocol lmtp {
|
||||||
|
mail_plugins = $mail_plugins sieve
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
protocols = $protocols sieve
|
||||||
|
|
||||||
|
service managesieve-login {
|
||||||
|
inet_listener sieve {
|
||||||
|
port = 4190
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
submission_relay_host = {{ .Env.SUBMISSION_HOST }}
|
||||||
|
submission_relay_port = 25
|
||||||
|
submission_relay_trusted = yes
|
||||||
|
|
||||||
|
protocol submission {
|
||||||
|
}
|
4
dockermail/mda/rootfs/etc/dovecot/conf.d/90-quota.conf
Normal file
4
dockermail/mda/rootfs/etc/dovecot/conf.d/90-quota.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
plugin {
|
||||||
|
quota = maildir:User quota
|
||||||
|
quota_exceeded_message = "Benutzer %u hat das Speichervolumen überschritten. / User %u has exhausted allowed storage space."
|
||||||
|
}
|
20
dockermail/mda/rootfs/etc/dovecot/conf.d/90-sieve.conf
Normal file
20
dockermail/mda/rootfs/etc/dovecot/conf.d/90-sieve.conf
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
plugin {
|
||||||
|
sieve_plugins = sieve_imapsieve sieve_extprograms
|
||||||
|
sieve_global_extensions = +vnd.dovecot.pipe
|
||||||
|
sieve = file:~/sieve;active=~/.dovecot.sieve
|
||||||
|
sieve_before = /etc/dovecot/sieve/global/spam-to-folder.sieve
|
||||||
|
sieve_pipe_bin_dir = /usr/lib/dovecot/sieve
|
||||||
|
sieve_pipe_exec_timeout = 60s
|
||||||
|
recipient_delimiter = -
|
||||||
|
|
||||||
|
# From somewhere to junk folder
|
||||||
|
imapsieve_mailbox1_name = Junk
|
||||||
|
imapsieve_mailbox1_causes = COPY
|
||||||
|
imapsieve_mailbox1_before = file:/etc/dovecot/sieve/global/learn-spam.sieve
|
||||||
|
|
||||||
|
# From junk folder to elsewhere
|
||||||
|
imapsieve_mailbox2_name = *
|
||||||
|
imapsieve_mailbox2_from = Junk
|
||||||
|
imapsieve_mailbox2_causes = COPY
|
||||||
|
imapsieve_mailbox2_before = file:/etc/dovecot/sieve/global/learn-ham.sieve
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
passdb {
|
||||||
|
driver = sql
|
||||||
|
args = /etc/dovecot/dovecot-sql.conf.ext
|
||||||
|
}
|
||||||
|
|
||||||
|
userdb {
|
||||||
|
driver = sql
|
||||||
|
args = /etc/dovecot/dovecot-sql.conf.ext
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
driver = mysql
|
||||||
|
connect = host={{ .Env.MYSQL_HOST }} dbname={{ .Env.MYSQL_DATABASE }} user={{ .Env.MYSQL_USER }} password={{ .Env.MYSQL_PASSWORD }}
|
||||||
|
default_pass_scheme = SHA256-CRYPT
|
||||||
|
password_query = SELECT mail_users.name AS user, mail_domains.name AS domain, password FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id WHERE mail_users.name = '%n' AND mail_domains.name = '%d' AND enabled = 1 AND NOT (send_only = 1 AND "%s" in ('imap', 'pop3'));
|
||||||
|
user_query = SELECT concat('*:storage=', quota, 'M') AS quota_rule FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id WHERE mail_users.name = '%n' AND mail_domains.name = '%d';
|
||||||
|
iterate_query = SELECT mail_users.name AS username, mail_domains.name AS domain FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id;
|
@ -0,0 +1,2 @@
|
|||||||
|
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
|
||||||
|
pipe :copy "rspamc" ["learnham"];
|
@ -0,0 +1,2 @@
|
|||||||
|
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
|
||||||
|
pipe :copy "rspamc" ["learnspam"];
|
@ -0,0 +1,6 @@
|
|||||||
|
require ["fileinto","mailbox"];
|
||||||
|
|
||||||
|
if header :contains "X-Spam" "YES" {
|
||||||
|
fileinto :create "Junk";
|
||||||
|
stop;
|
||||||
|
}
|
5
dockermail/mda/rootfs/usr/lib/dovecot/sieve/rspamc
Normal file
5
dockermail/mda/rootfs/usr/lib/dovecot/sieve/rspamc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
ACTION=${1}
|
||||||
|
|
||||||
|
curl -q -s --connect-timeout 60 --data-binary @- http://filter:11334/${ACTION}
|
11
dockermail/mda/rootfs/usr/local/bin/dh.sh
Normal file
11
dockermail/mda/rootfs/usr/local/bin/dh.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
openssl dhparam -out /etc/dovecot/dh.pem.tmp 4096
|
||||||
|
mv /etc/dovecot/dh.pem.tmp /etc/dovecot/dh.pem
|
||||||
|
touch /etc/dovecot/dh.pem.created
|
||||||
|
|
||||||
|
echo "The Diffie Hellman file was generated."
|
||||||
|
echo "YOU SHOULD RESTART THIS CONTAINER NOW."
|
||||||
|
|
||||||
|
exit 0
|
20
dockermail/mda/rootfs/usr/local/bin/entrypoint.sh
Normal file
20
dockermail/mda/rootfs/usr/local/bin/entrypoint.sh
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if ! [ -r /etc/dovecot/dh.pem.created ]
|
||||||
|
then
|
||||||
|
echo "Using pre-generated Diffie Hellman parameters until the new one is generated."
|
||||||
|
/usr/local/bin/dh.sh &
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f /run/dovecot/master.pid
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-template /etc/dovecot/conf.d/10-master.conf.templ:/etc/dovecot/conf.d/10-master.conf \
|
||||||
|
-template /etc/dovecot/conf.d/15-lda.conf.templ:/etc/dovecot/conf.d/15-lda.conf \
|
||||||
|
-template /etc/dovecot/conf.d/20-submission.conf.templ:/etc/dovecot/conf.d/20-submission.conf \
|
||||||
|
-template /etc/dovecot/dovecot-sql.conf.ext.templ:/etc/dovecot/dovecot-sql.conf.ext \
|
||||||
|
-wait tcp://${MYSQL_HOST}:3306 \
|
||||||
|
-wait file://${SSL_CERT} \
|
||||||
|
-wait file://${SSL_KEY} \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT} \
|
||||||
|
/usr/sbin/dovecot -F
|
66
dockermail/mta/Dockerfile
Normal file
66
dockermail/mta/Dockerfile
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
ARG DOCKERIZE_VER=0.6.0
|
||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM jwilder/dockerize:${DOCKERIZE_VER} AS dockerize
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"
|
||||||
|
|
||||||
|
ENV MAILNAME=mail.example.com \
|
||||||
|
MYNETWORKS=127.0.0.0/8\ 10.0.0.0/8\ 172.16.0.0/12\ 192.168.0.0/16 \
|
||||||
|
MYSQL_HOST=db \
|
||||||
|
MYSQL_USER=root \
|
||||||
|
MYSQL_PASSWORD=changeme \
|
||||||
|
MYSQL_DATABASE=mailserver \
|
||||||
|
FILTER_MIME=false \
|
||||||
|
RSPAMD_HOST=filter \
|
||||||
|
MDA_HOST=mda \
|
||||||
|
MTA_HOST=mta \
|
||||||
|
RELAYHOST=false \
|
||||||
|
SSL_CERT=/media/tls/mailserver.crt \
|
||||||
|
SSL_KEY=/media/tls/mailserver.key \
|
||||||
|
WAITSTART_TIMEOUT=1m
|
||||||
|
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
postfix-mysql \
|
||||||
|
postfix \
|
||||||
|
supervisor && \
|
||||||
|
postconf virtual_mailbox_domains=mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf && \
|
||||||
|
postconf virtual_mailbox_maps=mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf && \
|
||||||
|
postconf virtual_alias_maps=mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf && \
|
||||||
|
postconf smtpd_recipient_restrictions="check_recipient_access mysql:/etc/postfix/mysql-recipient-access.cf" && \
|
||||||
|
postconf smtputf8_enable=no && \
|
||||||
|
postconf smtpd_milters="inet:${RSPAMD_HOST}:11332" && \
|
||||||
|
postconf non_smtpd_milters="inet:${RSPAMD_HOST}:11332" && \
|
||||||
|
postconf milter_protocol=6 && \
|
||||||
|
postconf milter_mail_macros="i {mail_addr} {client_addr} {client_name} {auth_authen}" && \
|
||||||
|
postconf milter_default_action=accept && \
|
||||||
|
postconf virtual_transport="lmtp:${MDA_HOST}:2003" && \
|
||||||
|
postconf smtp_tls_security_level=may && \
|
||||||
|
postconf smtpd_tls_security_level=may && \
|
||||||
|
postconf smtpd_tls_auth_only=yes && \
|
||||||
|
postconf smtpd_tls_cert_file="${SSL_CERT}" && \
|
||||||
|
postconf smtpd_tls_key_file="${SSL_KEY}" && \
|
||||||
|
postconf smtpd_discard_ehlo_keywords="silent-discard, dsn" && \
|
||||||
|
postconf soft_bounce=no && \
|
||||||
|
postconf message_size_limit=52428800 && \
|
||||||
|
postconf mailbox_size_limit=0 && \
|
||||||
|
postconf recipient_delimiter=- && \
|
||||||
|
postconf mynetworks="$MYNETWORKS" && \
|
||||||
|
postconf maximal_queue_lifetime=1h && \
|
||||||
|
postconf bounce_queue_lifetime=1h && \
|
||||||
|
postconf maximal_backoff_time=15m && \
|
||||||
|
postconf minimal_backoff_time=5m && \
|
||||||
|
postconf queue_run_delay=5m && \
|
||||||
|
newaliases
|
||||||
|
|
||||||
|
COPY --from=dockerize /usr/local/bin/dockerize /usr/local/bin
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
EXPOSE 25
|
||||||
|
VOLUME ["/var/spool/postfix"]
|
||||||
|
|
||||||
|
HEALTHCHECK CMD postfix status || exit 1
|
||||||
|
CMD ["/usr/local/bin/entrypoint.sh"]
|
1
dockermail/mta/rootfs/etc/postfix/mime_header_checks
Normal file
1
dockermail/mta/rootfs/etc/postfix/mime_header_checks
Normal file
@ -0,0 +1 @@
|
|||||||
|
/name=[^>]*\.(bat|com|exe|dll|vbs|docm|doc|dzip)/ REJECT
|
@ -0,0 +1,5 @@
|
|||||||
|
user = {{ .Env.MYSQL_USER }}
|
||||||
|
password = {{ .Env.MYSQL_PASSWORD }}
|
||||||
|
hosts = {{ .Env.MYSQL_HOST }}
|
||||||
|
dbname = {{ .Env.MYSQL_DATABASE }}
|
||||||
|
query = SELECT CONCAT(mail_users.name, '@', mail_domains.name) AS email FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id HAVING email='%s'
|
@ -0,0 +1,5 @@
|
|||||||
|
user = {{ .Env.MYSQL_USER }}
|
||||||
|
password = {{ .Env.MYSQL_PASSWORD }}
|
||||||
|
hosts = {{ .Env.MYSQL_HOST }}
|
||||||
|
dbname = {{ .Env.MYSQL_DATABASE }}
|
||||||
|
query = SELECT IF(send_only = true, 'REJECT', 'OK') AS access FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id WHERE mail_users.name = '%u' AND mail_domains.name = '%d'
|
@ -0,0 +1,5 @@
|
|||||||
|
user = {{ .Env.MYSQL_USER }}
|
||||||
|
password = {{ .Env.MYSQL_PASSWORD }}
|
||||||
|
hosts = {{ .Env.MYSQL_HOST }}
|
||||||
|
dbname = {{ .Env.MYSQL_DATABASE }}
|
||||||
|
query = SELECT destination FROM mail_aliases JOIN mail_domains ON mail_aliases.domain_id = mail_domains.id WHERE CONCAT(mail_aliases.name, '@', mail_domains.name) = '%s'
|
@ -0,0 +1,5 @@
|
|||||||
|
user = {{ .Env.MYSQL_USER }}
|
||||||
|
password = {{ .Env.MYSQL_PASSWORD }}
|
||||||
|
hosts = {{ .Env.MYSQL_HOST }}
|
||||||
|
dbname = {{ .Env.MYSQL_DATABASE }}
|
||||||
|
query = SELECT 1 FROM mail_domains WHERE name='%s'
|
@ -0,0 +1,5 @@
|
|||||||
|
user = {{ .Env.MYSQL_USER }}
|
||||||
|
password = {{ .Env.MYSQL_PASSWORD }}
|
||||||
|
hosts = {{ .Env.MYSQL_HOST }}
|
||||||
|
dbname = {{ .Env.MYSQL_DATABASE }}
|
||||||
|
query = SELECT 1 FROM mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id WHERE mail_users.name = '%u' AND mail_domains.name = '%d' AND enabled = 1
|
18
dockermail/mta/rootfs/etc/supervisord.conf
Normal file
18
dockermail/mta/rootfs/etc/supervisord.conf
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[supervisord]
|
||||||
|
nodaemon=true
|
||||||
|
logfile=/dev/stderr
|
||||||
|
logfile_maxbytes=0
|
||||||
|
pidfile=/tmp/supervisord.pid
|
||||||
|
user=root
|
||||||
|
|
||||||
|
[program:syslogd]
|
||||||
|
command=/bin/busybox syslogd -n -O - -S
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/dev/stderr
|
||||||
|
stdout_logfile_maxbytes=0
|
||||||
|
|
||||||
|
[program:postfix]
|
||||||
|
command=/usr/libexec/postfix/master -d
|
||||||
|
redirect_stderr=true
|
||||||
|
stdout_logfile=/dev/stderr
|
||||||
|
stdout_logfile_maxbytes=0
|
29
dockermail/mta/rootfs/usr/local/bin/entrypoint.sh
Normal file
29
dockermail/mta/rootfs/usr/local/bin/entrypoint.sh
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
postconf myhostname="${MAILNAME}"
|
||||||
|
postconf mynetworks="${MYNETWORKS}"
|
||||||
|
|
||||||
|
if [ "${FILTER_MIME}" == "true" ]
|
||||||
|
then
|
||||||
|
postconf mime_header_checks=regexp:/etc/postfix/mime_header_checks
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${RELAYHOST}" != "false" ]
|
||||||
|
then
|
||||||
|
postconf relayhost=${RELAYHOST}
|
||||||
|
fi
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-template /etc/postfix/mysql-email2email.cf.templ:/etc/postfix/mysql-email2email.cf \
|
||||||
|
-template /etc/postfix/mysql-virtual-alias-maps.cf.templ:/etc/postfix/mysql-virtual-alias-maps.cf \
|
||||||
|
-template /etc/postfix/mysql-virtual-mailbox-domains.cf.templ:/etc/postfix/mysql-virtual-mailbox-domains.cf \
|
||||||
|
-template /etc/postfix/mysql-virtual-mailbox-maps.cf.templ:/etc/postfix/mysql-virtual-mailbox-maps.cf \
|
||||||
|
-template /etc/postfix/mysql-recipient-access.cf.templ:/etc/postfix/mysql-recipient-access.cf \
|
||||||
|
-wait tcp://${MYSQL_HOST}:3306 \
|
||||||
|
-wait tcp://${MDA_HOST}:2003 \
|
||||||
|
-wait tcp://${RSPAMD_HOST}:11332 \
|
||||||
|
-wait file://${SSL_CERT} \
|
||||||
|
-wait file://${SSL_KEY} \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT} \
|
||||||
|
/usr/bin/supervisord
|
@ -1,17 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if ! command -v swaks &> /dev/null
|
|
||||||
then
|
|
||||||
echo "SWAKS not found."
|
|
||||||
exit
|
|
||||||
fi
|
|
||||||
|
|
||||||
read -p "TO: " to_input
|
|
||||||
read -p "FROM: " from_input
|
|
||||||
read -s -p "PASS: " pass_input
|
|
||||||
printf "\n"
|
|
||||||
read -p "SERVER: " host_input
|
|
||||||
read -p "HEADER: " header_input
|
|
||||||
read -p "BODY: " body_input
|
|
||||||
|
|
||||||
swaks -t "$to_input" -f "$from_input" -s "$host_input" -au "$from_input" -ap "$pass_input" --header "$header_input" --body "$body_input" -tlso
|
|
@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
mkdir ./mailserver
|
|
||||||
pushd ./mailserver || exit
|
|
||||||
curl -o setup.sh https://raw.githubusercontent.com/tomav/docker-mailserver/master/setup.sh && chmod a+x ./setup.sh
|
|
||||||
curl -o docker-compose.yml https://raw.githubusercontent.com/tomav/docker-mailserver/master/docker-compose.yml.dist
|
|
||||||
curl -o env-mailserver https://raw.githubusercontent.com/tomav/docker-mailserver/master/env-mailserver.dist
|
|
||||||
|
|
||||||
if [ -f .env ]; then
|
|
||||||
rm ./.env
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "CONTAINER_NAME=mail" >> .env
|
|
||||||
read -r -p "HOSTNAME: "
|
|
||||||
echo "HOSTNAME=$REPLY" >> .env
|
|
||||||
read -r -p "DOMAIN: "
|
|
||||||
echo "DOMAINNAME=$REPLY" >> .env
|
|
||||||
|
|
||||||
printf "\nSetup the first account.\n"
|
|
||||||
read -r -p "Enter Email: " user
|
|
||||||
|
|
||||||
bash ./setup.sh email add "$user"
|
|
||||||
bash ./setup.sh config dkim
|
|
20
dockermail/ssl/Dockerfile
Normal file
20
dockermail/ssl/Dockerfile
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
|
||||||
|
ENV SSL_CERT=/media/tls/mailserver.crt \
|
||||||
|
SSL_KEY=/media/tls/mailserver.key \
|
||||||
|
SSL_CSR=/media/tls/mailserver.csr \
|
||||||
|
SSL_SUBJ_COUNTRY=DE \
|
||||||
|
SSL_SUBJ_STATE=Northrhine-Westfalia \
|
||||||
|
SSL_SUBJ_LOCALITY=Duesseldorf \
|
||||||
|
SSL_SUBJ_ORGANIZATION=Mail \
|
||||||
|
SSL_SUBJ_ORGANIZATIONAL_UNIT=Mail
|
||||||
|
|
||||||
|
RUN apk --no-cache add openssl
|
||||||
|
COPY create_tls.sh /usr/local/bin
|
||||||
|
|
||||||
|
CMD ["/usr/local/bin/create_tls.sh"]
|
17
dockermail/ssl/create_tls.sh
Normal file
17
dockermail/ssl/create_tls.sh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -r ${SSL_CERT} ]
|
||||||
|
then
|
||||||
|
echo "SSL certificate found. Exiting..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "No SSL certificate found. Creating a new one..."
|
||||||
|
|
||||||
|
openssl req -nodes -newkey rsa:2048 -keyout ${SSL_KEY} -out ${SSL_CSR} -subj "/C=${SSL_SUBJ_COUNTRY}/ST=${SSL_SUBJ_STATE}/L=${SSL_SUBJ_LOCALITY}/O=${SSL_SUBJ_ORGANIZATION}/OU=${SSL_SUBJ_ORGANIZATIONAL_UNIT}/CN=${MAILNAME}"
|
||||||
|
openssl x509 -req -days 3000 -in ${SSL_CSR} -signkey ${SSL_KEY} -out ${SSL_CERT}
|
||||||
|
|
||||||
|
echo "SSL certificate was successfully created! Exiting..."
|
||||||
|
|
||||||
|
exit 0
|
46
dockermail/test/Dockerfile
Normal file
46
dockermail/test/Dockerfile
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
ARG DOCKERIZE_VER=0.6.0
|
||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM jwilder/dockerize:${DOCKERIZE_VER} AS dockerize
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
|
||||||
|
ENV MYSQL_HOST=db \
|
||||||
|
MYSQL_USER=root \
|
||||||
|
MYSQL_PASSWORD=changeme \
|
||||||
|
MYSQL_DATABASE=mailserver \
|
||||||
|
WAITSTART_TIMEOUT=1m
|
||||||
|
|
||||||
|
# Iconv fix: https://github.com/docker-library/php/issues/240#issuecomment-305038173
|
||||||
|
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/ gnu-libiconv
|
||||||
|
ENV LD_PRELOAD=/usr/lib/preloadable_libiconv.so
|
||||||
|
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
bash \
|
||||||
|
bats \
|
||||||
|
curl \
|
||||||
|
docker \
|
||||||
|
jq \
|
||||||
|
mariadb-client \
|
||||||
|
openssl \
|
||||||
|
perl \
|
||||||
|
perl-net-ssleay \
|
||||||
|
php7 \
|
||||||
|
php7-imap \
|
||||||
|
php7-phar \
|
||||||
|
php7-iconv \
|
||||||
|
php7-openssl \
|
||||||
|
&& wget -q -O /usr/local/bin/swaks https://www.jetmore.org/john/code/swaks/files/swaks-20130209.0/swaks \
|
||||||
|
&& chmod +x /usr/local/bin/swaks \
|
||||||
|
&& wget -q -O /usr/local/bin/imap-tester https://github.com/jeboehm/imap-tester/releases/download/v0.2.1/imap-tester.phar \
|
||||||
|
&& chmod +x /usr/local/bin/imap-tester \
|
||||||
|
&& mkdir -p /usr/share/fixtures \
|
||||||
|
&& wget -q -O /usr/share/fixtures/gtube.txt https://spamassassin.apache.org/gtube/gtube.txt \
|
||||||
|
&& wget -q -O /usr/share/fixtures/eicar.com https://secure.eicar.org/eicar.com
|
||||||
|
|
||||||
|
COPY --from=dockerize /usr/local/bin/dockerize /usr/local/bin
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
CMD ["/usr/local/bin/run-tests.sh"]
|
10
dockermail/test/rootfs/usr/local/bin/run-tests.sh
Normal file
10
dockermail/test/rootfs/usr/local/bin/run-tests.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-wait tcp://db:3306 \
|
||||||
|
-wait tcp://mta:25 \
|
||||||
|
-wait tcp://web:80 \
|
||||||
|
-wait tcp://mda:143 \
|
||||||
|
-wait tcp://filter:11334 \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT} \
|
||||||
|
bats /usr/share/tests/*.bats
|
30
dockermail/test/rootfs/usr/share/tests/001_tls.bats
Normal file
30
dockermail/test/rootfs/usr/share/tests/001_tls.bats
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "certificates were created" {
|
||||||
|
[ -f /media/tls/mailserver.crt ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "connection to imaps" {
|
||||||
|
true | openssl s_client -showcerts -connect mda:993
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "connection to pop3s" {
|
||||||
|
true | openssl s_client -showcerts -connect mda:995
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "connection to pop3 with starttls" {
|
||||||
|
true | openssl s_client -showcerts -connect mda:110 -starttls pop3
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "connection to imap with starttls" {
|
||||||
|
true | openssl s_client -showcerts -connect mda:143 -starttls imap
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "connection to smtp with starttls" {
|
||||||
|
true | openssl s_client -showcerts -connect mta:25 -starttls smtp
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
16
dockermail/test/rootfs/usr/share/tests/002_database.bats
Normal file
16
dockermail/test/rootfs/usr/share/tests/002_database.bats
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "user table exists" {
|
||||||
|
run mysql --batch -u "${MYSQL_USER}" --password="${MYSQL_PASSWORD}" -h "${MYSQL_HOST}" "${MYSQL_DATABASE}" -e "select * from mail_users;"
|
||||||
|
[ "$status" = 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "alias table exists" {
|
||||||
|
run mysql --batch -u "${MYSQL_USER}" --password="${MYSQL_PASSWORD}" -h "${MYSQL_HOST}" "${MYSQL_DATABASE}" -e "select * from mail_aliases;"
|
||||||
|
[ "$status" = 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "domain table exists" {
|
||||||
|
run mysql --batch -u "${MYSQL_USER}" --password="${MYSQL_PASSWORD}" -h "${MYSQL_HOST}" "${MYSQL_DATABASE}" -e "select * from mail_domains;"
|
||||||
|
[ "$status" = 0 ]
|
||||||
|
}
|
131
dockermail/test/rootfs/usr/share/tests/003_mta.bats
Normal file
131
dockermail/test/rootfs/usr/share/tests/003_mta.bats
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "send mail to local account address" {
|
||||||
|
run swaks -s mta --to admin@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to local address with extension" {
|
||||||
|
run swaks -s mta --to admin-test@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "authentification on smtp with disabled account should fail" {
|
||||||
|
run swaks -s mta --to admin@example.com --from disabled@example.com -a -au disabled@example.com -ap test1234 -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 28 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "authentification on smtp with disabled and send only account should fail" {
|
||||||
|
run swaks -s mta --to admin@example.com --from disabledsendonly@example.com -a -au disabled@example.com -ap test1234 -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 28 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda with smtp authentification (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from admin@example.com -a -au admin@example.com -ap changeme -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda with smtp authentification, with address extension (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from admin-extension@example.com -a -au admin@example.com -ap changeme -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda from sendonly account with smtp authentification (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from sendonly@example.com -a -au sendonly@example.com -ap test1234 -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to local alias" {
|
||||||
|
run swaks -s mta --to foo@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send junk mail to local address" {
|
||||||
|
run swaks -s mta --to admin@example.com --body "$BATS_TEST_DESCRIPTION" --header "X-Spam: Yes"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail with too big attachment to quota user" {
|
||||||
|
dd if=/dev/urandom of=/tmp/bigfile bs=1M count=5
|
||||||
|
run swaks -s mta --to quota@example.com --body "$BATS_TEST_DESCRIPTION" --attach /tmp/bigfile
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to disabled user" {
|
||||||
|
run swaks -s mta --to disabled@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "maildir was created" {
|
||||||
|
sleep 10 # MTA + MDA need some time. :)
|
||||||
|
[ -d /var/vmail/example.com/admin/Maildir/new/ ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to local account address is stored" {
|
||||||
|
run grep -r "send mail to local account address" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to local alias is stored" {
|
||||||
|
run grep -r "send mail to local alias" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to local address with extension is stored" {
|
||||||
|
run grep -r "send mail to local address with extension" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to mda with smtp authentification (submission service) is stored" {
|
||||||
|
run grep -r "send mail to mda with smtp authentification (submission service)" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda with smtp authentification, with address extension (submission service) is stored" {
|
||||||
|
run grep -r "send mail to mda with smtp authentification, with address extension (submission service)" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda from sendonly account with smtp authentification (submission service) is stored" {
|
||||||
|
run grep -r "send mail to mda from sendonly account with smtp authentification (submission service)" /var/vmail/example.com/admin/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "junk mail is assorted to the junk folder" {
|
||||||
|
run grep -r "send junk mail to local address" /var/vmail/example.com/admin/Maildir/.Junk/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail with too big attachment is not found" {
|
||||||
|
run grep -r "send mail with too big attachment to quota user" /var/vmail/example.com/quota/Maildir/
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to disabled user is stored anyway" {
|
||||||
|
run grep -r "send mail to disabled user" /var/vmail/example.com/disabled/Maildir/
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send gtube mail is rejected" {
|
||||||
|
run swaks -s mta --to admin@example.com --data /usr/share/fixtures/gtube.txt
|
||||||
|
[ "$status" -eq 26 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to send only mailbox is rejected" {
|
||||||
|
run swaks -s mta --to sendonly@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 24 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mail to disabled and send only mailbox is rejected anyway" {
|
||||||
|
run swaks -s mta --to disabledsendonly@example.com --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 24 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "virus is rejected" {
|
||||||
|
if [ ${FILTER_VIRUS} = "false" ]; then
|
||||||
|
skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
run swaks -s mta --to admin@example.com --attach - < /usr/share/fixtures/eicar.com
|
||||||
|
[ "$status" -eq 26 ]
|
||||||
|
}
|
16
dockermail/test/rootfs/usr/share/tests/004_web.bats
Normal file
16
dockermail/test/rootfs/usr/share/tests/004_web.bats
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "http connection to manager web interface" {
|
||||||
|
curl -L http://web/manager/ | grep "Email address"
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "http connection to webmail interface" {
|
||||||
|
curl http://web/webmail/ | grep "jeboehm"
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "http connection to rspamd interface" {
|
||||||
|
curl http://web/rspamd/ | grep "Rspamd Web Interface"
|
||||||
|
[ "$?" -eq 0 ]
|
||||||
|
}
|
72
dockermail/test/rootfs/usr/share/tests/005_mda.bats
Normal file
72
dockermail/test/rootfs/usr/share/tests/005_mda.bats
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "send mail to mda from disabled account with smtp authentification (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from disabled@example.com -a -au disabled@example.com -ap test1234 -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 28 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda without authentification (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from disabled@example.com -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 23 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda without tls (submission service)" {
|
||||||
|
run swaks -s mda --port 587 --to admin@example.com --from admin@example.com -a -au admin@example.com -ap changeme --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 28 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "count mails in inbox via imap" {
|
||||||
|
run imap-tester test:count mda 143 admin@example.com changeme INBOX
|
||||||
|
[ "$output" -gt 3 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "count mails in inbox via imaps" {
|
||||||
|
run imap-tester test:count mda 993 admin@example.com changeme INBOX
|
||||||
|
[ "$output" -gt 3 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "count mails in inbox via pop3" {
|
||||||
|
run imap-tester test:count mda 110 admin@example.com changeme INBOX
|
||||||
|
[ "$output" -gt 3 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "count mails in inbox via pop3s" {
|
||||||
|
run imap-tester test:count mda 995 admin@example.com changeme INBOX
|
||||||
|
[ "$output" -gt 3 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "imap login to send only mailbox is not possible" {
|
||||||
|
run imap-tester test:count mda 143 sendonly@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "pop3 login to send only mailbox is not possible" {
|
||||||
|
run imap-tester test:count mda 110 sendonly@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "pop3 login to quota mailbox is possible" {
|
||||||
|
run imap-tester test:count mda 110 quota@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "imap login to quota mailbox is possible" {
|
||||||
|
run imap-tester test:count mda 143 quota@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "pop3 login to disabled mailbox is not possible" {
|
||||||
|
run imap-tester test:count mda 110 disabled@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "imap login to disabled mailbox is not possible" {
|
||||||
|
run imap-tester test:count mda 143 disabled@example.com test1234 INBOX
|
||||||
|
[ "$status" -eq 1 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "mails are owned by vmail" {
|
||||||
|
run find /var/vmail/example.com/ -not -user 5000
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ "$output" = "" ]
|
||||||
|
}
|
18
dockermail/test/rootfs/usr/share/tests/006_docker.bats
Normal file
18
dockermail/test/rootfs/usr/share/tests/006_docker.bats
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "no unhealthy containers exist" {
|
||||||
|
run docker ps -q --filter health=unhealthy
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ "$output" = "" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "Virus container is not running when filtering is disabled" {
|
||||||
|
if [ ${FILTER_VIRUS} = "true" ]; then
|
||||||
|
echo '# Filtering is disabled, skipping test' >&3
|
||||||
|
skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
run docker ps -q --filter name=docker-mailserver_virus_1
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ "$output" = "" ]
|
||||||
|
}
|
34
dockermail/test/rootfs/usr/share/tests/007_relayhost.bats
Normal file
34
dockermail/test/rootfs/usr/share/tests/007_relayhost.bats
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "check mailhog api for messages" {
|
||||||
|
if [ ${RELAYHOST} = "false" ]; then
|
||||||
|
echo '# Relayhost is disabled, skipping test' >&3
|
||||||
|
skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
run curl "http://mailhog:8025/api/v2/messages"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "send mail to mda with smtp authentification, external recipient" {
|
||||||
|
if [ ${RELAYHOST} = "false" ]; then
|
||||||
|
echo '# Relayhost is disabled, skipping test' >&3
|
||||||
|
skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
run swaks -s mda --port 587 --to nobody@ressourcenkonflikt.de --from admin@example.com -a -au admin@example.com -ap changeme -tls --body "$BATS_TEST_DESCRIPTION"
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "check mailhog api for outgoing message" {
|
||||||
|
if [ ${RELAYHOST} = "false" ]; then
|
||||||
|
echo '# Relayhost is disabled, skipping test' >&3
|
||||||
|
skip
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep 5 # Give mailhog some time
|
||||||
|
|
||||||
|
RESULT=$(curl -s "http://mailhog:8025/api/v2/messages" | jq -cr .items[0].Content.Body | tr -d '[:space:]')
|
||||||
|
|
||||||
|
[ "$RESULT" = "sendmailtomdawithsmtpauthentification,externalrecipient" ]
|
||||||
|
}
|
9
dockermail/test/rootfs/usr/share/tests/008_dkim.bats
Normal file
9
dockermail/test/rootfs/usr/share/tests/008_dkim.bats
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bats
|
||||||
|
|
||||||
|
@test "check DKIM selector map exists" {
|
||||||
|
[ -r /media/dkim/dkim_selectors.map ]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "check DKIM key for example.com exists" {
|
||||||
|
[ -r /media/dkim/example.com.1337.key ]
|
||||||
|
}
|
@ -1,6 +0,0 @@
|
|||||||
#|/bin/bash
|
|
||||||
|
|
||||||
pushd ./mailserver || exit
|
|
||||||
docker-compose down
|
|
||||||
docker pull tvial/docker-mailserver:latest
|
|
||||||
docker-compose up -d mail
|
|
26
dockermail/virus/Dockerfile
Normal file
26
dockermail/virus/Dockerfile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
ARG ALPINE_VER=3.11
|
||||||
|
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"
|
||||||
|
|
||||||
|
ENV FILTER_VIRUS=true
|
||||||
|
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
clamav-daemon \
|
||||||
|
clamav-libunrar && \
|
||||||
|
rm -rf /var/log/clamav
|
||||||
|
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
EXPOSE 3310
|
||||||
|
USER clamav
|
||||||
|
|
||||||
|
RUN /usr/bin/freshclam -l /dev/null
|
||||||
|
|
||||||
|
VOLUME ["/var/lib/clamav"]
|
||||||
|
|
||||||
|
HEALTHCHECK CMD echo PING | nc 127.0.0.1 3310 | grep PONG
|
||||||
|
CMD ["/usr/local/bin/entrypoint.sh"]
|
35
dockermail/virus/contrib/unofficial-sigs/Dockerfile
Normal file
35
dockermail/virus/contrib/unofficial-sigs/Dockerfile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
ARG ALPINE_VER=3.9
|
||||||
|
|
||||||
|
FROM alpine:${ALPINE_VER}
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
|
||||||
|
# hadolint ignore=DL3003
|
||||||
|
RUN apk --no-cache add \
|
||||||
|
bash \
|
||||||
|
bind-tools \
|
||||||
|
clamav-scanner \
|
||||||
|
gnupg \
|
||||||
|
ncurses \
|
||||||
|
rsync \
|
||||||
|
wget && \
|
||||||
|
wget -q -O /tmp/master.tar.gz https://github.com/extremeshok/clamav-unofficial-sigs/archive/master.tar.gz && \
|
||||||
|
cd /tmp && \
|
||||||
|
tar -xvf master.tar.gz && \
|
||||||
|
cd clamav-unofficial-sigs-master && \
|
||||||
|
cp clamav-unofficial-sigs.sh /usr/local/bin/ && \
|
||||||
|
chmod +x /usr/local/bin/clamav-unofficial-sigs.sh && \
|
||||||
|
cp -r config /etc/clamav-unofficial-sigs && \
|
||||||
|
mkdir /var/lib/clamav-unofficial-sigs && \
|
||||||
|
chown clamav /var/lib/clamav-unofficial-sigs && \
|
||||||
|
cp /etc/clamav-unofficial-sigs/os/os.ubuntu.conf /etc/clamav-unofficial-sigs/os.conf && \
|
||||||
|
echo "user_configuration_complete=\"yes\"" >> /etc/clamav-unofficial-sigs/user.conf && \
|
||||||
|
echo "logging_enabled=\"no\"" >> /etc/clamav-unofficial-sigs/user.conf && \
|
||||||
|
echo "enable_random=\"no\"" >> /etc/clamav-unofficial-sigs/user.conf && \
|
||||||
|
echo "reload_dbs=\"no\"" >> /etc/clamav-unofficial-sigs/user.conf && \
|
||||||
|
rm -rf /tmp/* /var/log/* /etc/clamav-unofficial-sigs/os/
|
||||||
|
|
||||||
|
USER clamav
|
||||||
|
|
||||||
|
CMD ["/usr/local/bin/clamav-unofficial-sigs.sh"]
|
2
dockermail/virus/rootfs/etc/clamav/clamd.conf
Normal file
2
dockermail/virus/rootfs/etc/clamav/clamd.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
TCPSocket 3310
|
||||||
|
Foreground true
|
4
dockermail/virus/rootfs/etc/clamav/freshclam.conf
Normal file
4
dockermail/virus/rootfs/etc/clamav/freshclam.conf
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
DatabaseOwner clamav
|
||||||
|
DatabaseMirror database.clamav.net
|
||||||
|
ScriptedUpdates yes
|
||||||
|
NotifyClamd /etc/clamav/clamd.conf
|
10
dockermail/virus/rootfs/usr/local/bin/entrypoint.sh
Normal file
10
dockermail/virus/rootfs/usr/local/bin/entrypoint.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
if [ "${FILTER_VIRUS}" = "false" ]
|
||||||
|
then
|
||||||
|
echo "Virus filtering is disabled, exiting."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/bin/freshclam -d -l /dev/stdout &
|
||||||
|
/usr/sbin/clamd
|
50
dockermail/web/Dockerfile
Normal file
50
dockermail/web/Dockerfile
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ARG ROUNDCUBE_VER=1.4.x-fpm
|
||||||
|
ARG PHP_VER=7.4
|
||||||
|
ARG DOCKERIZE_VER=0.6.0
|
||||||
|
|
||||||
|
FROM jwilder/dockerize:${DOCKERIZE_VER} AS dockerize
|
||||||
|
|
||||||
|
FROM roundcube/roundcubemail:${ROUNDCUBE_VER} AS roundcube
|
||||||
|
|
||||||
|
FROM jeboehm/php-nginx-base:${PHP_VER}
|
||||||
|
|
||||||
|
ARG ADMIN_VER=1.6.1
|
||||||
|
|
||||||
|
LABEL maintainer="jeff@ressourcenkonflikt.de"
|
||||||
|
LABEL vendor="https://github.com/jeboehm/docker-mailserver"
|
||||||
|
LABEL de.ressourcenkonflikt.docker-mailserver.autoheal="true"
|
||||||
|
|
||||||
|
ENV MYSQL_HOST=db \
|
||||||
|
MYSQL_DATABASE=mailserver \
|
||||||
|
MYSQL_USER=mailserver \
|
||||||
|
MYSQL_PASSWORD=changeme \
|
||||||
|
MTA_HOST=mta \
|
||||||
|
MDA_HOST=mda \
|
||||||
|
FILTER_HOST=filter \
|
||||||
|
SUPPORT_URL=https://github.com/jeboehm/docker-mailserver \
|
||||||
|
APP_ENV=prod \
|
||||||
|
TRUSTED_PROXIES=172.16.0.0/12 \
|
||||||
|
WAITSTART_TIMEOUT=1m \
|
||||||
|
ADMIN_VER=${ADMIN_VER}
|
||||||
|
|
||||||
|
COPY --from=roundcube /usr/src/roundcubemail/ /var/www/html/webmail/
|
||||||
|
COPY --from=dockerize /usr/local/bin/dockerize /usr/local/bin
|
||||||
|
COPY rootfs/ /
|
||||||
|
|
||||||
|
WORKDIR /opt/manager
|
||||||
|
|
||||||
|
RUN wget -O /tmp/admin.tar.gz -q https://github.com/jeboehm/mailserver-admin/archive/${ADMIN_VER}.tar.gz && \
|
||||||
|
tar -xf /tmp/admin.tar.gz -C /opt/manager --strip=1 && \
|
||||||
|
rm /tmp/admin.tar.gz && \
|
||||||
|
composer install --no-dev -o
|
||||||
|
|
||||||
|
RUN ln -s /opt/manager/public /var/www/html/manager && \
|
||||||
|
chown -R www-data \
|
||||||
|
/opt/manager/var/cache/ \
|
||||||
|
/opt/manager/var/log/ \
|
||||||
|
/var/www/html/webmail/temp/ \
|
||||||
|
/var/www/html/webmail/logs/
|
||||||
|
|
||||||
|
WORKDIR /var/www/html
|
||||||
|
HEALTHCHECK CMD curl -s http://127.0.0.1/login | grep docker-mailserver
|
||||||
|
CMD ["/usr/local/bin/entrypoint.sh"]
|
6
dockermail/web/README.md
Normal file
6
dockermail/web/README.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# mailserver-web
|
||||||
|
|
||||||
|
This image contains
|
||||||
|
|
||||||
|
[roundcube](https://roundcube.net)
|
||||||
|
and [mailserver-admin](https://github.com/jeboehm/mailserver-admin).
|
68
dockermail/web/rootfs/etc/nginx/sites-enabled/10-docker.conf
Normal file
68
dockermail/web/rootfs/etc/nginx/sites-enabled/10-docker.conf
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
absolute_redirect off;
|
||||||
|
|
||||||
|
root /var/www/html/manager;
|
||||||
|
|
||||||
|
location = /favicon.ico {
|
||||||
|
log_not_found off;
|
||||||
|
access_log off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /manager {
|
||||||
|
return 301 /;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ /\. {
|
||||||
|
deny all;
|
||||||
|
access_log off;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ \.(tpl|yml|ini|log)$ {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri /index.php$is_args$args;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /webmail {
|
||||||
|
alias /var/www/html/webmail;
|
||||||
|
index index.php;
|
||||||
|
try_files $uri $uri/ @webmail;
|
||||||
|
|
||||||
|
location ~ \.php$ {
|
||||||
|
include fastcgi_params;
|
||||||
|
# Mitigate httpoxy vulnerability, see: https://httpoxy.org/
|
||||||
|
fastcgi_param HTTP_PROXY "";
|
||||||
|
|
||||||
|
fastcgi_buffers 8 16k;
|
||||||
|
fastcgi_buffer_size 32k;
|
||||||
|
|
||||||
|
client_max_body_size 24M;
|
||||||
|
client_body_buffer_size 128k;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
fastcgi_pass php-fpm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location @webmail {
|
||||||
|
rewrite /webmail/(.*)$ /webmail/index.php?/$1 last;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ~ ^/index\.php(/|$) {
|
||||||
|
fastcgi_pass php-fpm;
|
||||||
|
fastcgi_split_path_info ^(.+\.php)(/.*)$;
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||||
|
fastcgi_param DOCUMENT_ROOT $realpath_root;
|
||||||
|
internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /rspamd/ {
|
||||||
|
proxy_pass http://filter:11334/;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
}
|
||||||
|
}
|
42
dockermail/web/rootfs/usr/local/bin/entrypoint.sh
Normal file
42
dockermail/web/rootfs/usr/local/bin/entrypoint.sh
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
manager_init() {
|
||||||
|
cd /opt/manager
|
||||||
|
|
||||||
|
bin/console doctrine:migrations:migrate -n
|
||||||
|
bin/console doctrine:schema:update --force
|
||||||
|
}
|
||||||
|
|
||||||
|
roundcube_init() {
|
||||||
|
cd /var/www/html/webmail
|
||||||
|
PWD=`pwd`
|
||||||
|
|
||||||
|
bin/initdb.sh --dir=$PWD/SQL || bin/updatedb.sh --dir=$PWD/SQL --package=roundcube || echo "Failed to initialize databse. Please run $PWD/bin/initdb.sh manually."
|
||||||
|
}
|
||||||
|
|
||||||
|
permissions() {
|
||||||
|
chown -R www-data /media/dkim
|
||||||
|
chmod 777 /media/dkim
|
||||||
|
}
|
||||||
|
|
||||||
|
dkim_refresh() {
|
||||||
|
cd /opt/manager
|
||||||
|
|
||||||
|
bin/console dkim:refresh
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-wait tcp://${MYSQL_HOST}:3306 \
|
||||||
|
-wait tcp://${MDA_HOST}:143 \
|
||||||
|
-wait tcp://${MTA_HOST}:25 \
|
||||||
|
-wait tcp://${FILTER_HOST}:11334 \
|
||||||
|
-wait file:///media/dkim/ \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT}
|
||||||
|
|
||||||
|
manager_init
|
||||||
|
roundcube_init
|
||||||
|
permissions
|
||||||
|
dkim_refresh
|
||||||
|
|
||||||
|
/usr/bin/supervisord
|
7
dockermail/web/rootfs/usr/local/bin/fixtures.sh
Normal file
7
dockermail/web/rootfs/usr/local/bin/fixtures.sh
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
dockerize \
|
||||||
|
-wait tcp://web:80 \
|
||||||
|
-wait tcp://${MYSQL_HOST}:3306 \
|
||||||
|
-timeout ${WAITSTART_TIMEOUT} \
|
||||||
|
${@}
|
4
dockermail/web/rootfs/usr/local/bin/setup.sh
Normal file
4
dockermail/web/rootfs/usr/local/bin/setup.sh
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
/usr/local/bin/fixtures.sh \
|
||||||
|
/opt/manager/bin/console init:setup
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
$config = [];
|
||||||
|
$config['smtp_log'] = false;
|
||||||
|
$config['log_dir'] = '/tmp/';
|
||||||
|
$config['temp_dir'] = '/tmp/';
|
||||||
|
$config['imap_cache'] = 'apc';
|
||||||
|
$config['db_dsnw'] = sprintf(
|
||||||
|
'mysql://%s:%s@%s/%s',
|
||||||
|
getenv('MYSQL_USER'),
|
||||||
|
getenv('MYSQL_PASSWORD'),
|
||||||
|
getenv('MYSQL_HOST'),
|
||||||
|
getenv('MYSQL_DATABASE')
|
||||||
|
);
|
||||||
|
$config['default_host'] = 'tls://' . getenv('MDA_HOST');
|
||||||
|
$config['smtp_server'] = 'tls://' . getenv('MDA_HOST');
|
||||||
|
$config['smtp_port'] = 587;
|
||||||
|
$config['smtp_user'] = '%u';
|
||||||
|
$config['smtp_pass'] = '%p';
|
||||||
|
$config['support_url'] = getenv('SUPPORT_URL');
|
||||||
|
$config['plugins'] = [
|
||||||
|
'archive',
|
||||||
|
'zipdownload',
|
||||||
|
'managesieve',
|
||||||
|
'password',
|
||||||
|
];
|
||||||
|
$config['imap_conn_options'] = [
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer' => false,
|
||||||
|
'verify_peer_name' => false,
|
||||||
|
'allow_self_signed' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$config['smtp_conn_options'] = [
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer' => false,
|
||||||
|
'verify_peer_name' => false,
|
||||||
|
'allow_self_signed' => false,
|
||||||
|
],
|
||||||
|
];
|
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$config['managesieve_port'] = 4190;
|
||||||
|
$config['managesieve_host'] = '%h';
|
||||||
|
$config['managesieve_auth_type'] = 'PLAIN';
|
||||||
|
$config['managesieve_auth_cid'] = null;
|
||||||
|
$config['managesieve_auth_pw'] = null;
|
||||||
|
$config['managesieve_usetls'] = true;
|
||||||
|
$config['managesieve_conn_options'] = [
|
||||||
|
'ssl' => [
|
||||||
|
'verify_peer' => false,
|
||||||
|
'verify_peer_name' => false,
|
||||||
|
'allow_self_signed' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$config['managesieve_default'] = '/etc/dovecot/sieve/global';
|
||||||
|
$config['managesieve_script_name'] = 'managesieve';
|
||||||
|
$config['managesieve_mbox_encoding'] = 'UTF-8';
|
||||||
|
$config['managesieve_replace_delimiter'] = '';
|
||||||
|
$config['managesieve_disabled_extensions'] = [];
|
||||||
|
$config['managesieve_debug'] = false;
|
||||||
|
$config['managesieve_kolab_master'] = false;
|
||||||
|
$config['managesieve_filename_extension'] = '.sieve';
|
||||||
|
$config['managesieve_filename_exceptions'] = [];
|
||||||
|
$config['managesieve_domains'] = [];
|
||||||
|
$config['managesieve_vacation'] = 0;
|
||||||
|
$config['managesieve_vacation_interval'] = 0;
|
||||||
|
$config['managesieve_vacation_addresses_init'] = false;
|
||||||
|
$config['managesieve_notify_methods'] = ['mailto'];
|
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$config['password_driver'] = 'sql';
|
||||||
|
$config['password_confirm_current'] = true;
|
||||||
|
$config['password_minimum_length'] = 6;
|
||||||
|
$config['password_require_nonalpha'] = false;
|
||||||
|
$config['password_log'] = false;
|
||||||
|
$config['password_login_exceptions'] = null;
|
||||||
|
$config['password_hosts'] = null;
|
||||||
|
$config['password_force_save'] = true;
|
||||||
|
$config['password_force_new_user'] = false;
|
||||||
|
$config['password_algorithm'] = 'clear';
|
||||||
|
$config['password_algorithm_prefix'] = '';
|
||||||
|
$config['password_blowfish_cost'] = 12;
|
||||||
|
$config['password_disabled'] = false;
|
||||||
|
$config['password_db_dsn'] = sprintf(
|
||||||
|
'mysql://%s:%s@%s/%s',
|
||||||
|
getenv('MYSQL_USER'),
|
||||||
|
getenv('MYSQL_PASSWORD'),
|
||||||
|
getenv('MYSQL_HOST'),
|
||||||
|
getenv('MYSQL_DATABASE')
|
||||||
|
);
|
||||||
|
$config['password_query'] = "UPDATE mail_users JOIN mail_domains ON mail_users.domain_id = mail_domains.id SET password=CONCAT('{SHA256-CRYPT}', ENCRYPT (%p, CONCAT('$5$', SUBSTRING(SHA(RAND()), -16)))) WHERE CONCAT(mail_users.name, '@', mail_domains.name)=%u;";
|
||||||
|
$config['password_crypt_hash'] = 'md5';
|
||||||
|
$config['password_idn_ascii'] = false;
|
||||||
|
$config['password_dovecotpw_with_method'] = false;
|
||||||
|
$config['password_hash_algorithm'] = 'sha1';
|
||||||
|
$config['password_hash_base64'] = false;
|
Loading…
Reference in New Issue
Block a user