##### 2025-04-19 #### Using other web services with Mailcow This is roughly what I did to have an Nginx web server on the same machine as dockerized Mailcow https://mailcow.email/ **Note:** mail.xxxxx.com is your mail server (MX), yourdomain.com is whatever domain you wish to use. 1. Change the default http and https ports (for example 8480 and 8443) and set **SKIP_LETS_ENCRYPT=y** in /opt/mailcow-dockerized/mailcow.conf 2. Restart Mailcow by executing cd /opt/mailcow-dockerized;docker compose restart 3. Make sure the DNS entry mail.xxxxx.com points to the server 4. **mkdir -p /var/www/html/letsencrypt/.well-known/acme-challenge** 5. Create /etc/nginx/letsencrypt_path. This can be re-used in your other domains. # url for letsencrypt location ^~ /.well-known/acme-challenge/ { allow all; default_type "text/plain"; # Path can be used for cert-validation on all domains root /var/www/html/letsencrypt; break; } 6. Stop the nginx server **systemctl stop nginx** 7. Run **certbot certonly -d mail.xxxxx.com** (select 2 standalone) 8. Create /etc/nginx/sites-available/mail.xxxxx.com server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name mail.xxxxx.com; charset UTF-8; access_log /var/log/nginx/access.mail.xxxxx.com; error_log /var/log/nginx/error.mail.xxxxx.com; include snippets/error_pages.conf; ssl_certificate /etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mail.xxxxx.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams-2048.pem; include /etc/nginx/letsencrypt_path; location / { proxy_pass http://127.0.0.1:8480; proxy_buffering off; include /etc/nginx/proxy_params; } } server { listen 80; listen [::]:80; server_name mail.xxxxx.com; return 301 https://mail.xxxxx.com; } 9. **ln -s /etc/nginx/sites-available/mail.xxxxx.com /etc/nginx/sites-enabled/mail.xxxxx.com** 10. Test with **nginx -t** , if all is well run **sudo systemctl start nginx** 11. Pointing your browser to https://mail.xxxxx.com should show you the Mailcow login page. ### Problem The problem is that Mailcow can no longer use port 80 to update it's ssl certificates that are used by postfix and dovecot. Instead certbot puts them in /etc/letsencrypt/live. To fix this the following script runs from crontab daily. #!/usr/bin/env bash # we are running behind an nginx proxy, where certbot is run by systemd, # so the mail.xxxxx.com certificates are updated, but not copied to the mailcow folder # in case the certificate isn't renewed automatically, run this: # sudo certbot -n certonly --webroot -w /var/www/html/letsencrypt -d mail.xxxxx.com t1="/etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem" t2="/opt/mailcow-dockerized/data/assets/ssl/mail.xxxxx.com/cert.pem" # test if certificate has been updated differ=$(cmp -b $t1 $t2 | grep -c "differ") [[ "$differ" = "0" ]] && exit 0 # these files are required in /data/assets/ssh/mail.xxxxx.com cp /etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem /opt/mailcow-dockerized/data/assets/ssl/mail.xxxxx.com/cert.pem cp /etc/letsencrypt/live/mail.xxxxx.com/privkey.pem /opt/mailcow-dockerized/data/assets/ssl/mail.xxxxx.com/key.pem # these files are required in /data/assets/ssl/ (turns out sending failed otherwise) cp /etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem /opt/mailcow-dockerized/data/assets/ssl/cert.pem cp /etc/letsencrypt/live/mail.xxxxx.com/privkey.pem /opt/mailcow-dockerized/data/assets/ssl/key.pem # update postfix & docker docker exec $(/usr/bin/docker ps -qaf name=postfix-mailcow) postfix reload docker exec $(/usr/bin/docker ps -qaf name=dovecot-mailcow) dovecot reload Inspiration: Felix Moesbauer https://felixmoessbauer.com/blog-reader/mailcow-reverse-proxy-letsencrypt.html Don't forget to check and correct if necessary your DANE and MTA-STS records if you use them #### DANE On your mail server: apt install hash-slinger -y Create a TLSA record: tlsa --create --selector 1 -p 25 --certificate /etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem mail.xxxxx.com The last line or the result will be something like: _25._tcp.mail.xxxxx.com. IN TLSA 3 1 1 443ac7c5c70fbfbc... Enter this TLSA line in your mail server's DNS record. Do the same for the following ports: _110._tcp.mail.xxxxx.com _143._tcp.mail.xxxxx.com _465._tcp.mail.xxxxx.com _587._tcp.mail.xxxxx.com _993._tcp.mail.xxxxx.com _995._tcp.mail.xxxxx.com You can check your DANE records at https://www.huque.com/bin/danecheck-smtp #### MTA-STS This is a fallback to DANE, you can run both. **Note:** https access to mta-sts.yourdomain.com is obligatory 1. Create /var/www/html/mta-sts/.well-known/mta-sts.txt with the following content: version: STSv1 mode: enforce max_age: 172800 mx: mail.xxxxx.com 2. Create the DNS record _mta-sts.mail.xxxxx.com as TXT with "v=STSv1; id=**INSERT AN ID, EX. 202511101644** " 3. Create the DNS record _mta-sts.yourdomain.com as CNAME pointing to _mta-sts.mail.xxxxx.com (your mail server) 4. Create the DNS record mta-sts.yourdomain.com pointing to the ip of the web server 5. You may need to wait for the DNS records to propagate 6. Stop Nginx with **systemctl stop nginx** 7. Create a letsencrypt certificate with **certbot certonly -d mta-sts.yourdomain.com** (select 2 standalone) 8. Create mta-sts.yourdomain.com in Nginx: 9. /etc/sites-available/mta-sts.yourdomain.com server { listen 443 ssl; listen [::]:443 ssl; http2 on; charset UTF-8; access_log /var/log/nginx/access.mts-sta.yourdomain.com; error_log /var/log/nginx/error.mts-sta.yourdomain.com; include snippets/error_pages.conf; ssl_certificate /etc/letsencrypt/live/mta-sts.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/mta-sts.yourdomain.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams-2048.pem; include /etc/nginx/letsencrypt_path; root /var/www/html/mta-sts; index index.html index.htm; server_name mta-sts.yourdomain.com; location / { try_files $uri $uri/ =404; } } server { listen 80; listen [::]:80; server_name mta-sts.yourdomain.com; return 301 https://mta-sts.yourdomain.com; } 10. **ln -s /etc/nginx/sites-available/mta-sts.yourdomain.com /etc/nginx/sites-enabled/mta-sts.yourdomain.com** 11. Test with nginx -t and if all goes well start nginx **systemctl start nginx** You can check your domain's MTA-STS at https://mxtoolbox.com/mta-sts.aspx All this worked for me :-) I hope it does for you!