Remove old file
parent
2aca3e0d30
commit
9e8a003508
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
104
003-build-sql.sh
104
003-build-sql.sh
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
55
README.md
55
README.md
|
@ -21,10 +21,10 @@ All configurations were written with security in mind.
|
||||||
| redis-mailcow | Redis | redis | - | 6379/tcp |
|
| redis-mailcow | Redis | redis | - | 6379/tcp |
|
||||||
| memcached-mailcow | Memcached | memcached | - | 11211/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).
|
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 and taken from subnet ${DOCKER_SUBNET}.
|
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 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)
|
- 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
|
## 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).
|
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.
|
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
|
## 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.
|
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
|
### build-*.files
|
||||||
|
|
||||||
(Re)build a container:
|
(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:
|
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`:
|
Reset mailcow admin to `admin:moohoo`:
|
||||||
```
|
```
|
||||||
./n-build-sql.sh --reset-admin
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
Dump database to file backup_${DBNAME}_${DATE}.sql:
|
Backup and restore database:
|
||||||
```
|
```
|
||||||
./n-build-sql.sh --dump
|
source mailcow.conf
|
||||||
```
|
# Create
|
||||||
|
DATE=$(date +"%Y%m%d_%H%M%S")
|
||||||
Restore database from a file:
|
docker exec -it mariadb-mailcow /bin/bash mysqldump --default-character-set=utf8mb4 -u${DBUSER} -p${DBPASS} ${DBNAME} > backup_${DBNAME}_${DATE}.sql
|
||||||
```
|
# Restore
|
||||||
./n-build-sql.sh --restore filename
|
docker exec -i mariadb-mailcow mysql -u${DBUSER} -p${DBPASS} ${DBNAME} < ${1}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Redis
|
### 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
|
docker exec -it rspamd-mailcow rspamadm --help
|
||||||
```
|
```
|
||||||
|
|
||||||
Use rspamc:
|
### Use rspamc:
|
||||||
```
|
```
|
||||||
docker exec -it rspamd-mailcow rspamc --help
|
docker exec -it rspamd-mailcow rspamc --help
|
||||||
```
|
```
|
||||||
|
### Use doveadm:
|
||||||
Use doveadm:
|
|
||||||
```
|
```
|
||||||
docker exec -it dovecot-mailcow doveadm
|
docker exec -it dovecot-mailcow doveadm
|
||||||
```
|
```
|
||||||
|
|
10
build-all.sh
10
build-all.sh
|
@ -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
|
|
|
@ -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'
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
chown -R 5000:5000 ../vmail
|
||||||
|
chown -R 33:33 ../dkim
|
|
@ -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');
|
|
|
@ -30,6 +30,11 @@ server {
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location ^~ /inc/init.sql {
|
||||||
|
deny all;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
location ^~ /Microsoft-Server-ActiveSync {
|
location ^~ /Microsoft-Server-ActiveSync {
|
||||||
proxy_pass http://sogo/SOGo/Microsoft-Server-ActiveSync;
|
proxy_pass http://sogo/SOGo/Microsoft-Server-ActiveSync;
|
||||||
proxy_connect_timeout 1000;
|
proxy_connect_timeout 1000;
|
||||||
|
|
|
@ -32,6 +32,31 @@ function hasDomainAccess($username, $role, $domain) {
|
||||||
}
|
}
|
||||||
return false;
|
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) {
|
function verify_ssha256($hash, $password) {
|
||||||
// Remove tag if any
|
// Remove tag if any
|
||||||
$hash = ltrim($hash, '{SSHA256}');
|
$hash = ltrim($hash, '{SSHA256}');
|
||||||
|
|
|
@ -245,3 +245,12 @@ CREATE TABLE IF NOT EXISTS sogo_user_profile (
|
||||||
c_settings text,
|
c_settings text,
|
||||||
PRIMARY KEY (c_uid)
|
PRIMARY KEY (c_uid)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
|
) 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');
|
||||||
|
|
|
@ -22,7 +22,6 @@ $opt = [
|
||||||
PDO::ATTR_EMULATE_PREPARES => false,
|
PDO::ATTR_EMULATE_PREPARES => false,
|
||||||
];
|
];
|
||||||
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
$pdo = new PDO($dsn, $database_user, $database_pass, $opt);
|
||||||
|
|
||||||
$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
|
$_SESSION['mailcow_locale'] = strtolower(trim($DEFAULT_LANG));
|
||||||
setcookie('language', $DEFAULT_LANG);
|
setcookie('language', $DEFAULT_LANG);
|
||||||
if (isset($_COOKIE['language'])) {
|
if (isset($_COOKIE['language'])) {
|
||||||
|
@ -69,3 +68,4 @@ require_once 'lang/lang.en.php';
|
||||||
include 'lang/lang.'.$_SESSION['mailcow_locale'].'.php';
|
include 'lang/lang.'.$_SESSION['mailcow_locale'].'.php';
|
||||||
require_once 'inc/functions.inc.php';
|
require_once 'inc/functions.inc.php';
|
||||||
require_once 'inc/triggers.inc.php';
|
require_once 'inc/triggers.inc.php';
|
||||||
|
init_db_schema();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?php
|
<?php
|
||||||
error_reporting(0);
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
|
PLEASE USE THE FILE "vars.local.inc.php" TO OVERWRITE SETTINGS AND MAKE THEM PERSISTENT!
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
chown -R 5000:5000 data/vmail
|
|
||||||
chown -R 33:33 data/dkim
|
|
|
@ -22,9 +22,3 @@ POP_PORT=110
|
||||||
POPS_PORT=995
|
POPS_PORT=995
|
||||||
SIEVE_PORT=4190
|
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"
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
Loading…
Reference in New Issue