Comprehensive Guide to Setting Up Mail Server and Web Services with Docker, Apache, and SSL on Ubuntu 24
You should consider the AWS Kubernetes in MaxOffice, is a bit less easy, but better, and like always, free!
sudo apt update && sudo apt upgrade -y
sudo apt install -y docker.io docker-compose apache2 certbot python3-certbot-apache vim
sudo usermod -aG docker busy
sudo mkdir -p /docker
sudo chown -R busy:busy /docker
cd /docker
cat <<EOT > .env
MYSQL_ROOT_PASSWORD=ChangeMe
MYSQL_USER=admin
MYSQL_PASSWORD=ChangeMe
MYSQL_DATABASE=mailserver_db
WORDPRESS_DB_USER=admin
WORDPRESS_DB_PASSWORD=ChangeMe
POSTFIXADMIN_SETUP_PASSWORD=ChangeMe
ROUNDCUBEMAIL_DB_USER=admin
ROUNDCUBEMAIL_DB_PASSWORD=ChangeMe
DOMAIN1=example1.com
DOMAIN2=example2.com
MAIL_DOMAIN=mail.example1.com
ADMIN_DOMAIN=admin.example1.com
WEBMAIL_DOMAIN=webmail.example1.com
EOT
vim docker-compose.yml
Add the following content then save and close the file:
version: '3.7'
services:
db:
image: mariadb:latest
volumes:
- db_data:/var/lib/mysql
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
ports:
- "3306:3306"
postfix:
image: boky/postfix
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
ports:
- "25:25"
- "587:587"
dovecot:
image: tvial/docker-mailserver:latest
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
ports:
- "993:993"
- "995:995"
postfixadmin:
image: postfixadmin
volumes:
- postfixadmin_data:/data
env_file:
- .env
environment:
POSTFIXADMIN_SETUP_PASSWORD: \${POSTFIXADMIN_SETUP_PASSWORD}
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
ports:
- "8081:80"
roundcube:
image: roundcube/roundcubemail
env_file:
- .env
environment:
MYSQL_ROOT_PASSWORD: \${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: \${MYSQL_DATABASE}
MYSQL_USER: \${MYSQL_USER}
MYSQL_PASSWORD: \${MYSQL_PASSWORD}
ports:
- "8080:80"
wordpress_domain1:
image: wordpress:latest
volumes:
- wordpress_domain1_data:/var/www/html
env_file:
- .env
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: \${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: \${WORDPRESS_DB_PASSWORD}
WORDPRESS_DB_NAME: \${MYSQL_DATABASE}
ports:
- "8001:80"
wordpress_domain2:
image: wordpress:latest
volumes:
- wordpress_domain2_data:/var/www/html
env_file:
- .env
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: \${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: \${WORDPRESS_DB_PASSWORD}
WORDPRESS_DB_NAME: \${MYSQL_DATABASE}
ports:
- "8002:80"
volumes:
db_data:
postfixadmin_data:
wordpress_domain1_data:
wordpress_domain2_data:
docker-compose up -d
sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests ssl
cat <<EOT | sudo tee /etc/apache2/sites-available/mail.example1.com.conf
<VirtualHost *:80>
ServerName mail.example1.com
ProxyPreserveHost On
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/
</VirtualHost>
EOT
cat <<EOT | sudo tee /etc/apache2/sites-available/admin.example1.com.conf
<VirtualHost *:80>
ServerName admin.example1.com
ProxyPreserveHost On
ProxyPass / http://localhost:8081/
ProxyPassReverse / http://localhost:8081/
</VirtualHost>
EOT
cat <<EOT | sudo tee /etc/apache2/sites-available/example1.com.conf
<VirtualHost *:80>
ServerName example1.com
ProxyPreserveHost On
ProxyPass / http://localhost:8001/
ProxyPassReverse / http://localhost:8001/
</VirtualHost>
EOT
cat <<EOT | sudo tee /etc/apache2/sites-available/example2.com.conf
<VirtualHost *:80>
ServerName example2.com
ProxyPreserveHost On
ProxyPass / http://localhost:8002/
ProxyPassReverse / http://localhost:8002/
</VirtualHost>
EOT
cat <<EOT | sudo tee /etc/apache2/sites-available/webmail.example1.com.conf
<VirtualHost *:80>
ServerName webmail.example1.com
ProxyPreserveHost On
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
</VirtualHost>
EOT
sudo a2ensite mail.example1.com.conf
sudo a2ensite admin.example1.com.conf
sudo a2ensite example1.com.conf
sudo a2ensite example2.com.conf
sudo a2ensite webmail.example1.com.conf
sudo systemctl restart apache2
sudo certbot --apache -d mail.example1.com -d admin.example1.com -d example1.com -d example2.com -d webmail.example1.com --cert-name mail.example1.com --key-type rsa
cat <<EOT > /docker/tools/backup.sh
#!/bin/bash
BACKUP_DIR="/SPACE/BACKUP/database"
TIMESTAMP=$(date +%F-%H-%M-%S)
docker exec db /usr/bin/mysqldump -u root --password=\${MYSQL_ROOT_PASSWORD} \${MYSQL_DATABASE} > \${BACKUP_DIR}/database_\${TIMESTAMP}.sql
tar -czf \${BACKUP_DIR}/database_\${TIMESTAMP}.tar.gz -C \${BACKUP_DIR} database_\${TIMESTAMP}.sql
rm \${BACKUP_DIR}/database_\${TIMESTAMP}.sql
EOT
chmod +x /docker/tools/backup.sh
(crontab -l 2>/dev/null; echo "0 3 * * * /docker/tools/backup.sh") | crontab -
By following these steps, you will have a fully functional mail server and web services setup using Docker and Apache with SSL. This comprehensive guide ensures that you have a secure and maintainable system for managing your domains and services.
Make sure you replace example1.com and example2.com with your actual domain names before running the commands.
Taking in consideration that the domains exist and the default values are already there, these examples can help you setup what you'll need. Notice that you could host the web servers and everything on the same host, but that is not recommended, instead you should use another docker and add it to the orchestration. Use the WordPress code in the project to create 1 or 2 WordPress sites and wrap it all up with Kubernetes.
##########################################
A Record for mail.example.com:
Name: mail
Type: A
IP Address: The public IP address of your mail server
MX: @ 10 mail.example.com
A: mail The public IP address of your mail server
Name: email
Type: CNAME
Value: mail.example.com.
Name: TXT
Type: @
Value: v=spf1 a mx ip4:The public IP address of your mail server ~all
Name: TXT
Type: @
Value: mail._domainkey IN TXT ( "v=DKIM1; h=rsa-sha256; k=rsa; s=email; " "p=THE PUBLIC KEY OF YOUR MAIL SERVER" ) ; ----- DKIM key mail for mail.example.com
Name: TXT
Type: PRT
Value: For improved security, you should have a reverse lookup record. If you don't have your own DNS server, you might have to ask your host provider to help you.
If they refuse, then you can create your DNS server container to get around that.
##########################################
MX Record for example1.com:
Name: @
Type: MX
Priority: 10 (or any other appropriate value)
Mail Server: mail.example.com
##########################################
MX Record for example2.com:
Name: @
Type: MX
Priority: 10 (or any other appropriate value)
Mail Server: mail.example.com