Osiris Posted October 20, 2022 Share Posted October 20, 2022 (edited) First question you might have: "why?". Well, because I can and want to understand. Selfhosted ftw! My ISP blocks port 25 and changes my ip every 6 months. Until a while ago, I could use their smtp servers to send mails for my domain, but they have become more restrictive lately. I thought to post my findings here to achieve a cheap running mailserver on unraid. I'm not trying to sell any services (godaddy, dynu), I'm just explaining how I fixed things. Total cost (besides unraid power cost) = 30$ / year, of which 20$ coz of ISP blocking that port. So I have A domain example.com at godaddy.com (an .xyz domain is 2$ per year). Don't buy any extra services. No certificates, nothing. Also, go to https://developer.godaddy.com/keys to generate an API key/secret pair An updated unraid nas (I'm on 6.9.2 now) A custom created docker network "traefik_secureproxy" (but imho, this isn't really needed, and you can use 'bridge') A container that keeps my dynamic IP A-record up-to-date, using the godaddy API: https://github.com/TrueOsiris/docker-godaddypy docker run -d --name='godaddypy' --net='bridge' --cpset-cpus='7' \ -e TZ='Europe/Paris' \ -e 'HOST_OS'="Unraid" \ -e 'GODADDY_KEY'='yourhashedkey' \ -e 'GODADDY_SECRET'='yourhashedsecret' \ -e 'DOMAINS'='example.com,mail.example.com' \ -v '/mnt/user/docker/godaddypy':'/logdir' --restart=unless-stopped 'trueosiris/godaddypy' 2 paid services at dynu.com: SMTP Outbound Relay + Email Store/Forward (20$ per year total). MX and TXT records need to be manually added to godaddy's dns for the domain, once, as per dynu.com's instructions. (see screenshot below) Generate the TXT fields on your domain on the dns management on the godaddy.com website, as per instructions on dynu.com for both services. Also, add the MX records of dynu. A Traefik container configured with godaddy & letsencrypt, with entrypoints, routers & services as configured below. The acme.json arrives in '/mnt/user/docker/traefik/resolvers/godaddy/' on the host. Btw, I altered the http port of unraid, so I could use 80 & 443 for traefik. Many posts on this forum on how to do this. I've setup traefik using only .yml files. No labels, no docker-compose, no .toml. I'm posting only fragments of my setup, anonymized. First, create the /mnt/user/docker/traefik/.variables.env file GODADDY_API_KEY=yourgodaddyapikey GODADDY_API_SECRET=yourgodaddyapisecret ACME_EMAIL=your.email@example.com The start the traefik container docker run -d --name='a_traefik' \ --net='traefik_secureproxy' \ -e TZ="Europe/Paris" \ -e HOST_OS="Unraid" \ -p '80:80/tcp' \ -p '443:443/tcp' \ -p '8083:8080/tcp' \ -v '/var/run/docker.sock':'/var/run/docker.sock':'rw' \ -v '/mnt/user/docker/traefik':'/etc/traefik':'rw' \ --restart=unless-stopped \ --env-file=/mnt/user/docker/traefik/.variables.env \ 'traefik:2.8.1' tree /mnt/user/docker/traefik/ /mnt/user/docker/traefik/ ├── dynamic │ └── providers │ ├── middlewares.yml │ ├── routers.yml │ └── services.yml ├── traefik.yml ├... traefik.yml ... entryPoints: web: address: ":80" http: redirections: entrypoint: to: websecure scheme: https websecure: address: ":443" traefik: address: ":8080" smtp: address: ":25" imapsecure: address: ":993" providers: docker: exposedByDefault: false httpClientTimeout: 300 network: traefik_secureproxy endpoint: "unix:///var/run/docker.sock" watch: true file: directory: /etc/traefik/dynamic/providers watch: true certificatesResolvers: godaddy1: ### variables.env contains GODADDY_API_KEY and GODADDY_API_SECRET acme: email: "[email protected]" ### caServer production or staging #caServer: https://acme-staging-v02.api.letsencrypt.org/directory storage: /etc/traefik/resolvers/godaddy/acme.json certificatesDuration: 2160 # 2160 is default. equals 90 days. dnsChallenge: provider: godaddy delayBeforeCheck: 5 resolvers: - "ns05.domaincontrol.com:53" - "8.8.8.8:53" ... services.yml tcp: services: ### T C P ### service_tcp_mail_smtp: loadBalancer: servers: - address: 10.10.0.6:25 service_tcp_mail_imapsecure: loadBalancer: servers: - address: 10.10.0.6:993 ### H T T P ### http: services: service_mailwebui: loadBalancer: servers: - url: http://10.10.0.6:8282 routers.yml tcp: routers: tcp_router_mail_smtp: rule: "HostSNI(`mail.example.com`)" entrypoints: - smtp tls: certResolver: godaddy1 service: "service_tcp_mail_smtp" priority: 90 tcp_router_mail_imapsecure: rule: "HostSNI(`mail.example.com`)" entrypoints: - imapsecure tls: certResolver: godaddy1 service: "service_tcp_mail_imapsecure" priority: 87 http: routers: router_mailwebui: rule: "Host(`mail.example.com`) || (Host(`example.com`) && Path(`/.well-known`)) || Host(`webmail.example.com`)" entrypoints: - web - websecure tls: certResolver: godaddy1 service: "service_mailwebui" priority: 92 An acme certificates container, which watches traefik's acme.json for changes and turns them into .pem files. On certificate change, the poste container will be restarted. docker run -d --name='acme_certificates' --net='bridge' -e TZ="Europe/Paris" -e HOST_OS="Unraid" \ -e 'COMBINE_PKCS12'='yes' \ -e 'CONVERT_KEYS_TO_RSA'='yes' \ -e 'COMBINED_PEM'='combined.pem' \ -e 'DOMAIN'='mail.example.com,example.com' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/':'/traefik':'ro' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates':'/output':'rw' \ -v '/var/run/docker.sock':'/var/run/docker.sock':'ro' \ 'humenius/traefik-certs-dumper:latest' --restart-containers poste The files arrive in '/mnt/user/docker/traefik/resolvers/godaddy/certificates' as combined.pem in subfolder mail.example.com the rest of the certificates. The poste.io container ... but ... with some steps. You want to put roundcube in an external volume. mount a temporary volume -v /mnt/user/docker/poste/www:/tmp/www So the docker command becomes this docker run -d --name='poste' --net='bridge' -e TZ="Europe/Paris" -e HOST_OS="Unraid" \ -e 'HTTPS'='OFF' \ -e 'HTTP_PORT'='8282' \ -e 'VIRTUAL_HOST'='mail.example.com,imap.example.com,smtp.example.com' \ -e 'HOSTNAME'='mail.example.com' \ -p '8282:8282/tcp' \ -p '25:25/tcp' \ -p '4190:4190/tcp' \ -p '993:993/tcp' \ -v '/mnt/user/docker/poste/data':'/data':'rw' \ -v '/mnt/user/docker/poste/www':'/tmp/www':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/cert.pem':'/data/ssl/letsencrypt/cert.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/key.pem':'/data/ssl/letsencrypt/key.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/combined.pem':'/data/ssl/letsencrypt/fullchain.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/key.pem':'/etc/ssl/server.key':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/cert.pem':'/etc/ssl/server.crt':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/combined.pem':'/etc/ssl/server-combined.crt':'rw' \ -h "mail.example.com" \ 'analogic/poste.io' then connect to the container docker exec -it poste /bin/bash and copy /opt/www cp -r /opt/www/* /tmp/www/ The restart the container with the /tmp/www changed to /opt/www docker run -d --name='poste' --net='bridge' -e TZ="Europe/Paris" -e HOST_OS="Unraid" \ -e 'HTTPS'='OFF' \ -e 'HTTP_PORT'='8282' \ -e 'VIRTUAL_HOST'='mail.example.com,imap.example.com,smtp.example.com' \ -e 'HOSTNAME'='mail.example.com' \ -p '8282:8282/tcp' \ -p '25:25/tcp' \ -p '4190:4190/tcp' \ -p '993:993/tcp' \ -v '/mnt/user/docker/poste/data':'/data':'rw' \ -v '/mnt/user/docker/poste/www':'/opt/www':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/cert.pem':'/data/ssl/letsencrypt/cert.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/key.pem':'/data/ssl/letsencrypt/key.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/combined.pem':'/data/ssl/letsencrypt/fullchain.pem':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/key.pem':'/etc/ssl/server.key':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/cert.pem':'/etc/ssl/server.crt':'rw' \ -v '/mnt/user/docker/traefik/resolvers/godaddy/certificates/mail.example.com/combined.pem':'/etc/ssl/server-combined.crt':'rw' \ -h "mail.example.com" \ 'analogic/poste.io' create folder mkdir -p /mnt/user/docker/poste/data/_override/etc/dovecot/conf.d/ and 2 files within this folder: 10-ssl.conf and 90-sieve.conf 10-ssl.conf ssl = required ssl = yes ssl_cert=</data/ssl/letsencrypt/cert.pem ssl_key=</data/ssl/letsencrypt/key.pem #ssl_dh=</etc/ssl/dh4096.pem #ssl_dh=</data/ssl/letsencrypt/fullchain.pem ssl_min_protocol = TLSv1.2 ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 #ssl_prefer_server_ciphers = yes # debug auth_verbose=yes auth_debug=yes #auth_debug_passwords=yes mail_debug=yes verbose_ssl=yes #auth_verbose_passwords=plain 90-sieve.conf plugin { sieve = file:~/sieve;active=~/.dovecot.sieve #sieve_default = /var/lib/dovecot/sieve/default.sieve sieve_default = /data/custom-sieve/default.sieve #sieve_default_name = #sieve_global = #sieve_discard = sieve_before = /data/custom-sieve/sieve.d/ #sieve_before2 = ldap:/etc/sieve-ldap.conf;name=ldap-domain #sieve_before3 = (etc...) #sieve_after = #sieve_after2 = #sieve_after2 = (etc...) sieve_extensions = +editheader #sieve_global_extensions = #sieve_plugins = #recipient_delimiter = + #sieve_max_script_size = 1M sieve_max_actions = 55 sieve_max_redirects = 60 #sieve_quota_max_scripts = 0 #sieve_quota_max_storage = 0 #sieve_user_email = #sieve_user_log = #sieve_redirect_envelope_from = sender #sieve_trace_dir = #sieve_trace_level = #sieve_trace_debug = no #sieve_trace_addresses = no create folder /mnt/user/docker/poste/data/custom-sieve/ edit these files to match the outgoing smtp /mnt/user/docker/poste/www/webmail/config/config.inc.php //$config['smtp_user'] = '%u'; $config['smtp_user'] = '[email protected]'; // this is your smtp-relay username from dynu //$config['smtp_pass'] = '%p'; $config['smtp_pass'] = 'L3prichaun!'; // this is your smtp-relay password from dynu //$config['smtp_server'] = 'tls://127.0.0.1:587'; $config['smtp_server'] = 'tls://relay.dynu.com:587'; /mnt/user/docker/poste/www/webmail/config/defaults.inc.php $config['smtp_server'] = 'tls://relay.dynu.com'; // SMTP port. Use 25 for cleartext, 465 for Implicit TLS, or 587 for STARTTLS (default) //$config['smtp_port'] = 587; $config['smtp_port'] = 2525; // SMTP username (if required) if you use %u as the username Roundcube // will use the current username for login //$config['smtp_user'] = '%u'; $config['smtp_user'] = '[email protected]'; // SMTP password (if required) if you use %p as the password Roundcube // will use the current user's password for login //$config['smtp_pass'] = '%p'; $config['smtp_pass'] = 'L3prichaun!'; $config['smtp_auth_type'] = 'PLAIN'; restart the poste container On your firewall, forward the following TCP ports to your docker host: external tcp 2525 to internal 25 on dockerhost-ip (smtp) external tcp 993 to internal 993 on dockerhost-ip (imaps) external tcp 4190 to internal 4190 on dockerhost-ip (sieve) Conclusion: You can now use webmail.example.com to use roundcube. you can use a mailclient, like thunderbird, or your mail-app on your phone with these settings: server-in: mail.example.com, username: [email protected], port 993, SSL/TLS, normal password server-out: relay.dynu.com, username: [email protected], port 2525 (or 587), starttls, normal password PS: In thunderbird, you need to manage the passwords for each of these servers in 'settings' (and not account settings). The reason I hardcode the outgoing server in roundcube is this bug: https://bitbucket.org/analogic/mailserver/issues/961/external-relay-authentication-bug Edited October 21, 2022 by Osiris layout fixes Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.