You've already forked mailcow-dockerized
							
							
				mirror of
				https://github.com/mailcow/mailcow-dockerized.git
				synced 2025-10-30 23:57:54 +02:00 
			
		
		
		
	Remove old file
This commit is contained in:
		| @@ -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                       | | ||||
| | 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 | ||||
| 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 | ||||
| ``` | ||||
|  | ||||
| Restore database from a file: | ||||
| ``` | ||||
| ./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 | ||||
| ``` | ||||
|   | ||||
							
								
								
									
										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' | ||||
|  | ||||
							
								
								
									
										2
									
								
								data/assets/fix-permissions.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								data/assets/fix-permissions.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -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; | ||||
| 		} | ||||
|  | ||||
|         location ^~ /inc/init.sql { | ||||
| 			deny all; | ||||
|         } | ||||
|  | ||||
|  | ||||
|         location ^~ /Microsoft-Server-ActiveSync { | ||||
|                 proxy_pass http://sogo/SOGo/Microsoft-Server-ActiveSync; | ||||
|                 proxy_connect_timeout 1000; | ||||
|   | ||||
| @@ -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}'); | ||||
|   | ||||
| @@ -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'); | ||||
| 
 | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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! | ||||
|   | ||||
							
								
								
									
										187
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| 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 | ||||
		Reference in New Issue
	
	Block a user