public
nobgit
read
NobMail
Based on mailcow: dockerized
Languages
Repository composition by tracked source files.
PHP
49%
JavaScript
35%
HTML
9%
CSS
4%
Shell
2%
Python
1%
Lua
0%
Perl
0%
Ruby
0%
SCSS
0%
Create file
Wiki Documentation
Clone
https://nobgit.com/orgs/nobgit/nobmail.git
ssh://[email protected]:2222/orgs/nobgit/nobmail.git
Commit
Remove old file
9e8a0035
.env | 1 +
000-build-certs.sh | 16 ---
001-build-network.sh | 13 ---
002-build-pdns.sh | 19 ---
003-build-sql.sh | 104 -----------------
004-build-redis.sh | 39 -------
005-build-rspamd.sh | 36 ------
006-build-php-fpm.sh | 28 -----
007-build-sogo.sh | 22 ----
008-build-rmilter.sh | 19 ---
009-build-dovecot.sh | 30 -----
010-build-postfix.sh | 35 ------
011-build-memcached.sh | 26 -----
012-build-nginx.sh | 30 -----
README.md | 55 ++++-----
build-all.sh | 10 --
data/Dockerfiles/sogo/gnustep_defaults.sh | 7 --
data/assets/fix-permissions.sh | 2 +
data/assets/mysql/pw.sql | 2 -
data/conf/nginx/site.conf | 5 +
data/web/inc/functions.inc.php | 25 ++++
data/{assets/mysql => web/inc}/init.sql | 9 ++
data/web/inc/prerequisites.inc.php | 2 +-
data/web/inc/vars.inc.php | 2 +-
docker-compose.yml | 187 ++++++++++++++++++++++++++++++
fix-permissions.sh | 2 -
mailcow.conf | 6 -
port-check.sh | 20 ----
28 files changed, 259 insertions(+), 493 deletions(-)
create mode 120000 .env
delete mode 100755 000-build-certs.sh
delete mode 100755 001-build-network.sh
delete mode 100755 002-build-pdns.sh
delete mode 100755 003-build-sql.sh
delete mode 100755 004-build-redis.sh
delete mode 100755 005-build-rspamd.sh
delete mode 100755 006-build-php-fpm.sh
delete mode 100755 007-build-sogo.sh
delete mode 100755 008-build-rmilter.sh
delete mode 100755 009-build-dovecot.sh
delete mode 100755 010-build-postfix.sh
delete mode 100755 011-build-memcached.sh
delete mode 100755 012-build-nginx.sh
delete mode 100755 build-all.sh
delete mode 100755 data/Dockerfiles/sogo/gnustep_defaults.sh
create mode 100755 data/assets/fix-permissions.sh
delete mode 100644 data/assets/mysql/pw.sql
rename data/{assets/mysql => web/inc}/init.sql (95%)
create mode 100644 docker-compose.yml
delete mode 100755 fix-permissions.sh
delete mode 100755 port-check.sh
Diff
diff --git a/.env b/.env
new file mode 120000
index 00000000..9400869f
--- /dev/null
+++ b/.env
@@ -0,0 +1 @@
+mailcow.conf
\ No newline at end of file
diff --git a/000-build-certs.sh b/000-build-certs.sh
deleted file mode 100755
index 12ae26ff..00000000
--- a/000-build-certs.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-. mailcow.conf
-
-openssl dhparam -out data/assets/ssl/dhparams.pem 2048
-
-docker run \
- --rm \
- -v ${PWD}/data/assets/ssl:/certs \
- ehazlett/certm \
- -d /certs ca generate -o=mailcow
-
-docker run \
- --rm \
- -v ${PWD}/data/assets/ssl:/certs \
- ehazlett/certm \
- -d /certs client generate --common-name=${MAILCOW_HOSTNAME} -o=mailcow
diff --git a/001-build-network.sh b/001-build-network.sh
deleted file mode 100755
index 878e6334..00000000
--- a/001-build-network.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-. mailcow.conf
-
-if [[ -z $(docker network ls --filter "name=${DOCKER_NETWORK}" -q) ]]; then
- docker network create ${DOCKER_NETWORK} --subnet ${DOCKER_SUBNET}
-else
- if [[ $(docker network inspect mailcow-network --format='{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2> /dev/null) != ${DOCKER_SUBNET} ]]; then
- echo "ERROR: mailcow network exists, but has wrong subnet!"
- exit 1
- fi
- echo "Correct mailcow network exists, skipped..."
- exit 0
-fi
diff --git a/002-build-pdns.sh b/002-build-pdns.sh
deleted file mode 100755
index ef11abc2..00000000
--- a/002-build-pdns.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="pdns-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-docker run \
- -v ${PWD}/data/conf/pdns/:/etc/powerdns/ \
- --network=${DOCKER_NETWORK} \
- -h pdns \
- --network-alias=pdns \
- --name ${NAME} \
- -d andryyy/mailcow-dockerized:pdns
diff --git a/003-build-sql.sh b/003-build-sql.sh
deleted file mode 100755
index c7a4459f..00000000
--- a/003-build-sql.sh
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="mariadb-mailcow"
-
-reconf() {
- echo "Installing database schema (this will not overwrite existing data)"
- echo "It may take a while for MariaDB to warm up, please wait..."
- echo docker exec ${NAME} mysql -u${DBUSER} -p${DBPASS} ${DBNAME}
- until docker exec ${NAME} /bin/bash -c "mysql -u'${DBUSER}' -p'${DBPASS}' ${DBNAME} < /assets/init.sql"; do
- echo "Trying again in 2 seconds..."
- sleep 2
- done
- echo "Done."
-}
-
-dump() {
- DATE=$(date +"%Y%m%d_%H%M%S")
- echo "Creating dump file ./backup_${DBNAME}_${DATE}.sql"
- docker exec -it ${NAME} /bin/bash mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > backup_${DBNAME}_${DATE}.sql
-}
-
-restore() {
- echo "Restoring dump file ${2}..."
- docker exec -i ${NAME} mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < ${1}
-}
-
-insert_admin() {
- echo 'Setting mailcow UI admin login to "admin:moohoo"...'
- echo "It may take a while for MariaDB to warm up, please wait..."
- until docker exec ${NAME} /bin/bash -c "mysql -u'${DBUSER}' -p'${DBPASS}' ${DBNAME} < /assets/pw.sql"; do
- echo "Trying again in 2 seconds..."
- sleep 2
- done
- echo "Done."
-}
-
-client() {
- echo "==============================="
- echo "DB: ${DBNAME} - USER: ${DBUSER}"
- echo "==============================="
- docker exec -it ${NAME} mysql -u${DBUSER} -p${DBPASS} ${DBNAME}
-}
-
-if [[ ${1} == "--init-schema" ]]; then
- reconf
- exit 0
-elif [[ ${1} == "--dump" ]]; then
- dump
- exit 0
-elif [[ ${1} == "--restore" ]]; then
- if [[ -z ${2} || ! -f ${2} ]]; then
- echo "Invalid input file"
- exit 1
- fi
- restore ${2}
- exit 0
-elif [[ ${1} == "--client" ]]; then
- client
- exit 0
-elif [[ ${1} == "--reset-admin" ]]; then
- insert_admin
- exit 0
-elif [[ ! -z ${1} ]]; then
- echo "Unknown parameter"
- exit 1
-fi
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-if [[ ! -z "$(docker images -q mariadb:${DBVERS})" ]]; then
- read -r -p "Found image locally. Delete local image and repull? [y/N] " response
- response=${response,,}
- if [[ $response =~ ^(yes|y)$ ]]; then
- docker rmi mariadb:${DBVERS}
- fi
-fi
-
-docker run \
- -v ${PWD}/data/db/mysql/:/var/lib/mysql/ \
- -v ${PWD}/data/conf/mysql/:/etc/mysql/conf.d/:ro \
- -v ${PWD}/data/assets/mysql:/assets:ro \
- --name=${NAME} \
- --network=${DOCKER_NETWORK} \
- -h mysql \
- --network-alias=mysql \
- -e MYSQL_ROOT_PASSWORD=${DBROOT} \
- -e MYSQL_DATABASE=${DBNAME} \
- -e MYSQL_USER=${DBUSER} \
- -e MYSQL_PASSWORD=${DBPASS} \
- -d mariadb:${DBVERS}
-
-reconf
-
-read -r -p "Do you want to reset mailcow admin to admin:moohoo? [y/N] " response
-response=${response,,}
-if [[ $response =~ ^(yes|y)$ ]]; then
- insert_admin
-fi
diff --git a/004-build-redis.sh b/004-build-redis.sh
deleted file mode 100755
index 70c4b42d..00000000
--- a/004-build-redis.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="redis-mailcow"
-
-client() {
- docker exec -it ${NAME} /bin/bash -c "redis-cli"
-}
-
-if [[ ${1} == "--client" ]]; then
- client
- exit 0
-elif [[ ! -z ${1} ]]; then
- echo "Unknown parameter"
- exit 1
-fi
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-if [[ ! -z "$(docker images -q redis:${DBVERS})" ]]; then
- read -r -p "Found image locally. Delete local image and repull? [y/N] " response
- response=${response,,}
- if [[ $response =~ ^(yes|y)$ ]]; then
- docker rmi redis:${DBVERS}
- fi
-fi
-
-docker run \
- -v ${PWD}/data/db/redis/:/data/ \
- --network=${DOCKER_NETWORK} \
- --network-alias=redis \
- -h redis \
- --name=${NAME} \
- -d redis:${REDISVERS} --appendonly yes
diff --git a/005-build-rspamd.sh b/005-build-rspamd.sh
deleted file mode 100755
index f1f3fa1d..00000000
--- a/005-build-rspamd.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="rspamd-mailcow"
-
-PDNS_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' pdns-mailcow 2> /dev/null)
-if [[ ! ${PDNS_IP} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
- echo "Cannot determine Powerdns Recursor ip address. Is the container running?"
- exit 1
-fi
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-# Needs network-alias because of different dns
-
-docker run \
- -v ${PWD}/data/conf/rspamd/override.d/:/etc/rspamd/override.d:ro \
- -v ${PWD}/data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro \
- -v ${PWD}/data/conf/rspamd/lua/:/etc/rspamd/lua/:ro \
- -v ${PWD}/data/dkim/txt/:/etc/rspamd/dkim/txt/:ro \
- -v ${PWD}/data/dkim/keys/:/etc/rspamd/dkim/keys/:ro \
- --dns=${PDNS_IP} \
- --dns-search=${DOCKER_NETWORK} \
- --network=${DOCKER_NETWORK} \
- --network-alias=rspamd \
- -h rspamd \
- --name ${NAME} \
- -d andryyy/mailcow-dockerized:rspamd
-
-/bin/bash ./fix-permissions.sh
-
diff --git a/006-build-php-fpm.sh b/006-build-php-fpm.sh
deleted file mode 100755
index 1898b87a..00000000
--- a/006-build-php-fpm.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="php-fpm-mailcow"
-
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-if [[ ! -z "$(docker images -q php:${PHPVERS})" ]]; then
- read -r -p "Found image locally. Delete local image and repull? [y/N] " response
- response=${response,,}
- if [[ $response =~ ^(yes|y)$ ]]; then
- docker rmi php:${PHPVERS}
- fi
-fi
-
-docker run \
- -v ${PWD}/data/web:/web:ro \
- -v ${PWD}/data/conf/rspamd/dynmaps:/dynmaps:ro \
- -v ${PWD}/data/dkim/:/shared/dkim/ \
- -d --network=${DOCKER_NETWORK} \
- --name ${NAME} \
- --network-alias=phpfpm \
- -h phpfpm \
- andryyy/mailcow-dockerized:phpfpm
diff --git a/007-build-sogo.sh b/007-build-sogo.sh
deleted file mode 100755
index 94da4024..00000000
--- a/007-build-sogo.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="sogo-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-docker run \
- -v ${PWD}/data/conf/sogo/:/etc/sogo/ \
- --name ${NAME} \
- --network=${DOCKER_NETWORK} \
- --network-alias sogo \
- -h sogo \
- -e DBNAME=${DBNAME} \
- -e DBUSER=${DBUSER} \
- -e DBPASS=${DBPASS} \
- -d -t andryyy/mailcow-dockerized:sogo
diff --git a/008-build-rmilter.sh b/008-build-rmilter.sh
deleted file mode 100755
index 742fb728..00000000
--- a/008-build-rmilter.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="rmilter-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-docker run \
- -v ${PWD}/data/conf/rmilter/:/etc/rmilter.conf.d/:ro \
- --network=${DOCKER_NETWORK} \
- -h rmilter \
- --network-alias=rmilter \
- --name ${NAME} \
- -d andryyy/mailcow-dockerized:rmilter
diff --git a/009-build-dovecot.sh b/009-build-dovecot.sh
deleted file mode 100755
index c4a90dd2..00000000
--- a/009-build-dovecot.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-source mailcow.conf
-
-NAME="dovecot-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-sed -i "/^connect/c\connect = \"host=mysql dbname=${DBNAME} user=${DBUSER} password=${DBPASS}\"" data/conf/dovecot/sql/*
-
-docker run \
- -p ${IMAP_PORT}:143 \
- -p ${IMAPS_PORT}:993 \
- -p ${POP_PORT}:110 \
- -p ${POPS_PORT}:995 \
- -p ${SIEVE_PORT}:4190\
- -v ${PWD}/data/conf/dovecot:/etc/dovecot:ro \
- -v ${PWD}/data/vmail:/var/vmail \
- -v ${PWD}/data/assets/ssl:/etc/ssl/mail/:ro \
- --name ${NAME} \
- --network=${DOCKER_NETWORK} \
- --network-alias dovecot \
- -h ${MAILCOW_HOSTNAME} \
- -d andryyy/mailcow-dockerized:dovecot
-
-/bin/bash ./fix-permissions.sh
diff --git a/010-build-postfix.sh b/010-build-postfix.sh
deleted file mode 100755
index 34dbdac0..00000000
--- a/010-build-postfix.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="postfix-mailcow"
-
-PDNS_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' pdns-mailcow 2> /dev/null)
-if [[ ! ${PDNS_IP} =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
- echo "Cannot determine Powerdns Recursor ip address. Is the container running?"
- exit 1
-fi
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-sed -i "/^user/c\user = ${DBUSER}" data/conf/postfix/sql/*
-sed -i "/^password/c\password = ${DBPASS}" data/conf/postfix/sql/*
-sed -i "/^dbname/c\dbname = ${DBNAME}" data/conf/postfix/sql/*
-
-docker run \
- -p ${SMTP_PORT}:25 \
- -p ${SMTPS_PORT}:465 \
- -p ${SUBMISSION_PORT}:587 \
- -v ${PWD}/data/conf/postfix:/opt/postfix/conf:ro \
- -v ${PWD}/data/assets/ssl:/etc/ssl/mail/:ro \
- --dns=${PDNS_IP} \
- --dns-search=${DOCKER_NETWORK} \
- --name ${NAME} \
- --network=${DOCKER_NETWORK} \
- --network-alias postfix \
- -h ${MAILCOW_HOSTNAME} \
- -d andryyy/mailcow-dockerized:postfix
diff --git a/011-build-memcached.sh b/011-build-memcached.sh
deleted file mode 100755
index 6ea44275..00000000
--- a/011-build-memcached.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="memcached-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-if [[ ! -z "$(docker images -q rmilter)" ]]; then
- read -r -p "Found image locally. Delete local image and repull? [y/N] " response
- response=${response,,}
- if [[ $response =~ ^(yes|y)$ ]]; then
- docker rmi memcached
- fi
-fi
-
-docker run \
- --network=${DOCKER_NETWORK} \
- -h memcached \
- --network-alias=memcached \
- --name=${NAME} \
- -d memcached
diff --git a/012-build-nginx.sh b/012-build-nginx.sh
deleted file mode 100755
index 6cddc454..00000000
--- a/012-build-nginx.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-NAME="nginx-mailcow"
-
-echo "Stopping and removing containers with name tag ${NAME}..."
-if [[ ! -z $(docker ps -af "name=${NAME}" -q) ]]; then
- docker stop $(docker ps -af "name=${NAME}" -q)
- docker rm $(docker ps -af "name=${NAME}" -q)
-fi
-
-sed -i "s#database_name.*#database_name = \"${DBNAME}\";#" data/web/inc/vars.inc.php
-sed -i "s#database_user.*#database_user = \"${DBUSER}\";#" data/web/inc/vars.inc.php
-sed -i "s#database_pass.*#database_pass = \"${DBPASS}\";#" data/web/inc/vars.inc.php
-
-docker run \
- -p 443:443 \
- --expose 8081 \
- --name ${NAME} \
- -v ${PWD}/data/web:/web:ro \
- -v ${PWD}/data/conf/rspamd/dynmaps:/dynmaps:ro \
- -v ${PWD}/data/assets/ssl/:/etc/ssl/mail/:ro \
- -v ${PWD}/data/conf/nginx/:/etc/nginx/conf.d/:ro \
- --network=${DOCKER_NETWORK} \
- -h nginx \
- --network-alias=nginx \
- -d andryyy/mailcow-dockerized:nginx
-
-/bin/bash ./fix-permissions.sh
diff --git a/README.md b/README.md
index 2b27a52a..e41a868b 100644
--- a/README.md
+++ b/README.md
@@ -21,10 +21,10 @@ All configurations were written with security in mind.
| redis-mailcow | Redis | redis | - | 6379/tcp |
| memcached-mailcow | Memcached | memcached | - | 11211/tcp |
-All containers share a network ${MAILCOW_NETWORK} (name can be changed, but remove all containers and rebuild them after changing).
-IPs are dynamic and taken from subnet ${DOCKER_SUBNET}.
+All containers share a network "mailcow-network" with the subnet 172.22.1.0/24 - if you want to change it, set it in the composer file.
+IPs are dynamic except for PowerDNS resolver which has a static ip address 172.22.1.2.
-FAQ:
+### **FAQ**
- rspamd learns mail as spam or ham when you move a message in or out of the junk folder to any mailbox besides trash.
- rspamd auto-learns mail when a high or low score is detected (see https://rspamd.com/doc/configuration/statistic.html#autolearning)
@@ -34,16 +34,15 @@ FAQ:
## Installation
-1. You need Docker. Most systems can install Docker by running `wget -qO- https://get.docker.com/ | sh`
+1. You need Docker and Docker Compose. Most systems can install Docker by running `wget -qO- https://get.docker.com/ | sh` - see [this link](https://docs.docker.com/compose/install/) for installing Docker Compose.
2. Clone this repository and configure `mailcow.conf`, do not use special chars in passwords in this file (will be fixed soon).
-It is almost always enough to just change the hostname.
-3. Run `./build-all.sh` - select `Y` when asked to reset the admin password.
+3. `docker-compose up -d` - leave the `-d` out for a wall of logs in case of debugging.
Done.
-You can now access https://${MAILCOW_HOSTNAME} with the default credentials `admin` + password `moohoo`.
+You can now access https://${MAILCOW_HOSTNAME} with the default credentials `admin` + password `moohoo`. The database will be initialized when you first visit the UI.
## Configuration after installation
@@ -102,7 +101,8 @@ docker restart nginx-mailcow
When renewing certificates, run the last two steps (link + restart) as post-hook in certbot.
-## Special usage
+## More useful commands and examples (todo: move to wiki soon)
+
### build-*.files
(Re)build a container:
@@ -123,49 +123,50 @@ You can use docker logs $name for almost all containers. Only rmilter does not l
Connect to MariaDB database:
```
-./n-build-sql.sh --client
+source mailcow.conf
+docker exec -it mariadb-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME}
```
-Init schema (will also be installed when running `./n-build-sql.sh` without parameters):
+Init schema (will be auto-installed by mailcow UI, but just in case...):
```
-./n-build-sql.sh --init-schema
+source mailcow.conf
+docker exec -it mariadb-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < data/web/inc/init.sql
```
Reset mailcow admin to `admin:moohoo`:
```
-./n-build-sql.sh --reset-admin
-```
-
-Dump database to file backup_${DBNAME}_${DATE}.sql:
-```
-./n-build-sql.sh --dump
+source mailcow.conf
+docker exec -it mariadb-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} -e "DROP TABLE admin; DROP TABLE domain_admins"
+# Open mailcow UI to auto-init the db
```
-Restore database from a file:
+Backup and restore database:
```
-./n-build-sql.sh --restore filename
+source mailcow.conf
+# Create
+DATE=$(date +"%Y%m%d_%H%M%S")
+docker exec -it mariadb-mailcow /bin/bash mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > backup_${DBNAME}_${DATE}.sql
+# Restore
+docker exec -i mariadb-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < ${1}
```
### Redis
-Connect to redis database:
+Connect to redis key store:
```
-./n-build-redis.sh --client
+docker exec -it redis-mailcow /bin/bash -c "redis-cli"
```
-### Some examples
-
-Use rspamadm:
+### Use rspamadm:
```
docker exec -it rspamd-mailcow rspamadm --help
```
-Use rspamc:
+### Use rspamc:
```
docker exec -it rspamd-mailcow rspamc --help
```
-
-Use doveadm:
+### Use doveadm:
```
docker exec -it dovecot-mailcow doveadm
```
diff --git a/build-all.sh b/build-all.sh
deleted file mode 100755
index 19b015f4..00000000
--- a/build-all.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-/bin/bash port-check.sh
-[[ $? != 0 ]] && exit 1
-
-for build in $(ls *build*.sh | grep -v all); do
- echo "Starting build file ${buildx} ..."
- /bin/bash ${build}
-done
-/bin/bash fix-permissions.sh
diff --git a/data/Dockerfiles/sogo/gnustep_defaults.sh b/data/Dockerfiles/sogo/gnustep_defaults.sh
deleted file mode 100755
index a93bbd21..00000000
--- a/data/Dockerfiles/sogo/gnustep_defaults.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-defaults write sogod SOGoUserSources '({type = sql;id = directory;viewURL = mysql://${DBUSER}:${DBPASS}@${DBHOST}:3306/${DBNAME}/sogo_view;canAuthenticate = YES;isAddressBook = YES;displayName = \"GAL\";MailFieldNames = (aliases, ad_aliases, senderacl);userPasswordAlgorithm = ssha256;})'
-defaults write sogod SOGoProfileURL 'mysql://${DBUSER}:${DBPASS}@${DBHOST}:3306/${DBNAME}/sogo_user_profile'
-defaults write sogod OCSFolderInfoURL 'mysql://${DBUSER}:${DBPASS}@${DBHOST}:3306/${DBNAME}/sogo_folder_info'
-defaults write sogod OCSEMailAlarmsFolderURL 'mysql://${DBUSER}:${DBPASS}@${DBHOST}:3306/${DBNAME}/sogo_alarms_folder'
-defaults write sogod OCSSessionsFolderURL 'mysql://${DBUSER}:${DBPASS}@${DBHOST}:3306/${DBNAME}/sogo_sessions_folder'
-
diff --git a/data/assets/fix-permissions.sh b/data/assets/fix-permissions.sh
new file mode 100755
index 00000000..4b956a2f
--- /dev/null
+++ b/data/assets/fix-permissions.sh
@@ -0,0 +1,2 @@
+chown -R 5000:5000 ../vmail
+chown -R 33:33 ../dkim
diff --git a/data/assets/mysql/pw.sql b/data/assets/mysql/pw.sql
deleted file mode 100644
index f5a65466..00000000
--- a/data/assets/mysql/pw.sql
+++ /dev/null
@@ -1,2 +0,0 @@
-REPLACE INTO admin VALUES ('admin','{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1);
-REPLACE INTO domain_admins (username, domain, created, active) VALUES ('admin', 'ALL', NOW(), '1');
diff --git a/data/conf/nginx/site.conf b/data/conf/nginx/site.conf
index 59f3932c..9433b608 100644
--- a/data/conf/nginx/site.conf
+++ b/data/conf/nginx/site.conf
@@ -30,6 +30,11 @@ server {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
+ location ^~ /inc/init.sql {
+ deny all;
+ }
+
+
location ^~ /Microsoft-Server-ActiveSync {
proxy_pass http://sogo/SOGo/Microsoft-Server-ActiveSync;
proxy_connect_timeout 1000;
diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php
index b5d36f26..b10b1f8d 100644
--- a/data/web/inc/functions.inc.php
+++ b/data/web/inc/functions.inc.php
@@ -32,6 +32,31 @@ function hasDomainAccess($username, $role, $domain) {
}
return false;
}
+function init_db_schema() {
+ global $pdo;
+ try {
+ $stmt = $pdo->prepare("SELECT `username` FROM `admin`");
+ $stmt->execute();
+ }
+ catch (Exception $e) {
+ $lines = file('/web/inc/init.sql');
+ $data = '';
+ foreach ($lines as $line) {
+ if (substr($line, 0, 2) == '--' || $line == '') {
+ continue;
+ }
+ $data .= $line;
+ if (substr(trim($line), -1, 1) == ';') {
+ $pdo->query($data);
+ $data = '';
+ }
+ }
+ $_SESSION['return'] = array(
+ 'type' => 'success',
+ 'msg' => 'Database initialization completed.'
+ );
+ }
+}
function verify_ssha256($hash, $password) {
// Remove tag if any
$hash = ltrim($hash, '{SSHA256}');
diff --git a/data/assets/mysql/init.sql b/data/web/inc/init.sql
similarity index 95%
rename from data/assets/mysql/init.sql
rename to data/web/inc/init.sql
index e7f15a19..3dd1bacc 100644
--- a/data/assets/mysql/init.sql
+++ b/data/web/inc/init.sql
@@ -245,3 +245,12 @@ CREATE TABLE IF NOT EXISTS sogo_user_profile (
c_settings text,
PRIMARY KEY (c_uid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
+
+INSERT INTO admin (username, password, superadmin, created, modified, active)
+ SELECT 'admin', '{SSHA256}K8eVJ6YsZbQCfuJvSUbaQRLr0HPLz5rC9IAp0PAFl0tmNDBkMDc0NDAyOTAxN2Rk', 1, NOW(), NOW(), 1
+ WHERE NOT EXISTS (SELECT username FROM admin WHERE superadmin='1');
+
+INSERT INTO domain_admins (username, domain, created, active)
+ SELECT 'admin', 'ALL', NOW(), 1
+ WHERE NOT EXISTS (SELECT username FROM domain_admins WHERE domain='ALL');
+
diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php
index 5fce44a1..08eedfab 100644
--- a/data/web/inc/prerequisites.inc.php
+++ b/data/web/inc/prerequisites.inc.php
@@ -22,7 +22,6 @@ $opt = [
PDO::ATTR_EMULATE_PREPARES => false,
];
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
-
$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
setcookie('language', $DEFAULT_LANG);
if (isset($_COOKIE['language'])) {
@@ -69,3 +68,4 @@ require_once 'lang/lang.en.php';
include 'lang/lang.'.$_SESSION['mailcow_locale'].'.php';
require_once 'inc/functions.inc.php';
require_once 'inc/triggers.inc.php';
+init_db_schema();
diff --git a/data/web/inc/vars.inc.php b/data/web/inc/vars.inc.php
index 158729c9..9aff2c4c 100644
--- a/data/web/inc/vars.inc.php
+++ b/data/web/inc/vars.inc.php
@@ -1,5 +1,5 @@
<?php
-error_reporting(0);
+error_reporting(E_ALL);
/*
PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..e0389e03
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,187 @@
+version: '2'
+
+services:
+ pdns-mailcow:
+ image: andryyy/mailcow-dockerized:pdns
+ volumes:
+ - ./data/conf/pdns/:/etc/powerdns/
+ restart: always
+ networks:
+ mailcow-network:
+ ipv4_address: 172.22.1.2
+ aliases:
+ - pdns
+
+ mariadb-mailcow:
+ image: mariadb:latest
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/db/mysql/:/var/lib/mysql/
+ - ./data/conf/mysql/:/etc/mysql/conf.d/:ro
+ environment:
+ - MYSQL_ROOT_PASSWORD=${DBROOT}
+ - MYSQL_DATABASE=${DBNAME}
+ - MYSQL_USER=${DBUSER}
+ - MYSQL_PASSWORD=${DBPASS}
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - mysql
+
+ redis-mailcow:
+ image: redis
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/db/redis/:/data/
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - redis
+
+ rspamd-mailcow:
+ image: andryyy/mailcow-dockerized:rspamd
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/conf/rspamd/override.d/:/etc/rspamd/override.d:ro
+ - ./data/conf/rspamd/local.d/:/etc/rspamd/local.d:ro
+ - ./data/conf/rspamd/lua/:/etc/rspamd/lua/:ro
+ - ./data/dkim/txt/:/etc/rspamd/dkim/txt/:ro
+ - ./data/dkim/keys/:/etc/rspamd/dkim/keys/:ro
+ restart: always
+ dns:
+ - 172.22.1.2
+ - 127.0.0.11
+ dns_search: mailcow-network
+ networks:
+ mailcow-network:
+ aliases:
+ - rspamd
+
+ php-fpm-mailcow:
+ image: andryyy/mailcow-dockerized:phpfpm
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/web:/web:ro
+ - ./data/conf/rspamd/dynmaps:/dynmaps:ro
+ - ./data/dkim/:/shared/dkim/
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - phpfpm
+
+ sogo-mailcow:
+ image: andryyy/mailcow-dockerized:sogo
+ depends_on:
+ - pdns-mailcow
+ environment:
+ - DBNAME=${DBNAME}
+ - DBUSER=${DBUSER}
+ - DBPASS=${DBPASS}
+ volumes:
+ - ./data/conf/sogo/:/etc/sogo/
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - sogo
+
+ rmilter-mailcow:
+ image: andryyy/mailcow-dockerized:rmilter
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/conf/rmilter/:/etc/rmilter.conf.d/:ro
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - rmilter
+
+ dovecot-mailcow:
+ image: andryyy/mailcow-dockerized:dovecot
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/conf/dovecot:/etc/dovecot:ro
+ - ./data/vmail:/var/vmail
+ - ./data/assets/ssl:/etc/ssl/mail/:ro
+ ports:
+ - "${IMAP_PORT}:143"
+ - "${IMAPS_PORT}:993"
+ - "${POP_PORT}:110"
+ - "${POPS_PORT}:995"
+ - "${SIEVE_PORT}:4190"
+ restart: always
+ hostname: ${MAILCOW_HOSTNAME}
+ networks:
+ mailcow-network:
+ aliases:
+ - dovecot
+
+ postfix-mailcow:
+ image: andryyy/mailcow-dockerized:postfix
+ depends_on:
+ - pdns-mailcow
+ volumes:
+ - ./data/conf/postfix:/opt/postfix/conf:ro
+ - ./data/assets/ssl:/etc/ssl/mail/:ro
+ ports:
+ - "${SMTP_PORT}:25"
+ - "${SMTPS_PORT}:465"
+ - "${SUBMISSION_PORT}:587"
+ restart: always
+ hostname: ${MAILCOW_HOSTNAME}
+ dns:
+ - 172.22.1.2
+ - 127.0.0.11
+ dns_search: mailcow-network
+ networks:
+ mailcow-network:
+ aliases:
+ - postfix
+
+ memcached-mailcow:
+ image: memcached
+ depends_on:
+ - pdns-mailcow
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - memcached
+
+ nginx-mailcow:
+ depends_on:
+ - mariadb-mailcow
+ - sogo-mailcow
+ - php-fpm-mailcow
+ image: nginx
+ volumes:
+ - ./data/web:/web:ro
+ - ./data/conf/rspamd/dynmaps:/dynmaps:ro
+ - ./data/assets/ssl/:/etc/ssl/mail/:ro
+ - ./data/conf/nginx/:/etc/nginx/conf.d/:ro
+ ports:
+ - "443:443"
+ restart: always
+ networks:
+ mailcow-network:
+ aliases:
+ - nginx
+
+networks:
+ mailcow-network:
+ driver: bridge
+ ipam:
+ driver: default
+ config:
+ - subnet: 172.22.1.0/24
+ gateway: 172.22.1.1
+
diff --git a/fix-permissions.sh b/fix-permissions.sh
deleted file mode 100755
index 7017fd1f..00000000
--- a/fix-permissions.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-chown -R 5000:5000 data/vmail
-chown -R 33:33 data/dkim
diff --git a/mailcow.conf b/mailcow.conf
index 10992726..72ec2944 100644
--- a/mailcow.conf
+++ b/mailcow.conf
@@ -22,9 +22,3 @@ POP_PORT=110
POPS_PORT=995
SIEVE_PORT=4190
-# Networking
-# You need to rebuild all containers after changing values.
-# Remove old networks manually.
-DOCKER_NETWORK="mailcow-network"
-DOCKER_SUBNET="172.18.0.0/16"
-
diff --git a/port-check.sh b/port-check.sh
deleted file mode 100755
index 4e854459..00000000
--- a/port-check.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-
-. mailcow.conf
-
-if [[ -z $(which ss) ]]; then echo "Please install the ss util first."; exit 1; fi
-
-for port in ${SMTP_PORT} ${SMTPS_PORT} ${SUBMISSION_PORT} ${IMAP_PORT} ${IMAPS_PORT} ${POP_PORT} ${POPS_PORT} ${SIEVE_PORT} 443; do
- if [[ ! -z $(ss -tlnp "( sport = :$port )" 2> /dev/null | grep LISTEN | grep -vi docker) ]]; then
- echo "Port $port is in use by another process."
- err=1
- fi
-done
-
-if [[ ${err} == "1" ]]; then
- echo
- echo "Exiting."
- exit 1
-fi
-
-exit 0