6 minutes
Caddy and Mail in a Box
Installation
Recently I’ve decided to move away from using Vesta CP as my web control panel for my domain, since there hasn’t been any major releases for it in over a year (as of the time of this writing). I also found out that the EC2 instance ran out of disk space, despite me configuring Vesta CP to notify me when this happens. I researched alternative open source control panels and could not find a suitable replacement, so I decided to skip a web control panel all together and configure everything on the box myself. My setup is pretty simple (A WordPress installation, Mail server, and reverse proxy endpoints for my home VPN) so I took the plunge.
Tinc VPN
This was pretty simple, I installed tinc via my package repository and copied over the configuration files from my previous (now defunct) EC2 instance. I configured a systemd service in order to manage the VPN tunnel connection and keep it alive in the background, and the rest is history. Here is my systemd file for tinc:
[Unit]
Description=Tinc VPN After=network.target
[Service]
Type=simple
WorkingDirectory=/etc/tinc/vpn
ExecStart=/usr/sbin/tincd -n vpn-D -d3
ExecReload=/usr/sbin/tincd -n vpn -kHUP
TimeoutStopSec=5
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
Mail Server
I have heard good things about Mail-in-a-Box, and wanted to try it. One of the first issues I experience is that it only supports Ubuntu 14.04 and any attempts to use it on a later version causes the script to abort after notifying you that the version is not supported by MIAB. Luckily an Ubuntu 16.04 fork exists that requires you to take a few extra steps in order to get it working, but after that everything ran smoothly. During the installation process, MIAB installs and nginx webserver to be the fronted for managing the installation (adding new users, aliases, webmail access, etc.). It also wipes any pre-existing nginx configuration files and uninstalls apache2, so be wary if you are trying to run this on a box not solely dedicated to email. Once the setup is complete, you can access the following endpoints:
- Webmail via Roundcube at domain.com/mail
- Administrative portal via a custom Flask server instance at domain.com/admin
- Nextcloud instance (for contacts/calendar) at domain.com/cloud/contacts or domain.com/cloud/calendar
It also installs a few other features (DNS resolver, small static site hosting, autodiscover for Outlook/iOS), but more importantly the web endpoints (and nginx) would be clashing with my reverse proxy setup and my intent to use Caddy as a webserver instead.
Caddy
This was new to me, I have been a long time user of nginx and never had any complaints about it. However one of Caddy’s main features is it’s automatic HTTPS. No more dealing with SSL certificates, keys, expiration dates, etc. It was all handled automatically, and was definitely not one of my favorite parts of maintaining a web server. The documentation seemed simple enough, so I decided to migrate from nginx to Caddy as part of my new web server stack. The first issue I had to deal with is nginx and caddy fighting over port 80/443. I thought about hosting nginx on a different port and using caddy to reverse proxy traffic to the required nginx port, but ultimately I thought it would be a better learning experience if I rewrote the necessary nginx server blocks into caddy server blocks. I decided to skip over the nextcloud related ones as I would not be actually using the MIAB provided instance of nextcloud, since I run my own instance on my home server. So that leaves roundcube and the administrative panel. After much struggling and consulting the caddy documentation, I was able to successfully access the administrative panel and roundcube using the caddy file below:
mail-time.tpage.io {
tls user@tpage.io
gzip
basicauth / user hunter2
root /usr/local/lib/roundcubemail/
fastcgi / /run/php/php7.0-fpm.sock php
}
admin-panel.tpage.io {
tls user@tpage.io
gzip
header / {
X-Frame-Options "DENY"
X-Content-Type-Options "nosniff"
Content-Security-Policy "frame-ancestors 'none';"
Strict-Transport-Security "max-age=31536000"
}
proxy / http://127.0.0.1:10222/ {
transparent
websocket
}
}
Moving forward, I had to setup a WordPress server block for my WordPress installation later on. This time it was pretty easy:
https://www.tpage.io https://tpage.io {
tls user@tpage.io
root /var/www/wordpress
gzip
fastcgi / /run/php/php7.0-fpm.sock php
rewrite {
if {path} not_match ^\/wp-admin
to {path} {path}/ /index.php?_url={uri}
}
}
http://www.tpage.io {
tls user@tpage.io
redir https://www.tpage.io
}
http://tpage.io {
tls user@tpage.io
redir https://tpage.io
}
Note the extra directives for tpage.io and www.tpage.io over HTTP. This is to make Caddy provision/manage TLS certificates for Dovecot/Postfix (which uses the server’s FQDN: tpage.io), instead of Mailinabox. I chose to do it this way because Caddy handles the provisioning of TLS certificates effortlessly and it makes me feel at ease knowing I don’t have to worry about my TLS certificates expiring. Without the extra directives, Caddy doesn’t automatically provision TLS certificates for tpage.io and www.tpage.io, it just redirects them to their HTTPS equivalent.
After configuring the domains and subdomains for automatic TLS
certificate provisioning, I then had to modify the TLS certificate
paths Dovecot/Postfix use when configured to use TLS (Spoiler:
Mailinabox configures them this way). It all came down to editing
/etc/dovecot/conf.d/10-ssl.conf
and /etc/postfix/main.cf
Then swapping out the TLS/SSL certificate/key paths with the path
of where Caddy stores the FQDN (tpage.io) TLS certs, for me this
was /etc/ssl/caddy/acme/auto-generated-folder/tpage.io/tpage.io.crt
and /etc/ssl/caddy/acme/auto-generated-folder/tpage.io/tpage.io.key
Afterwards I restarted Dovecot/Postfix and everything was golden!
Now for the reverse proxy connections over Tinc VPN. This can be
accomplished because web servers bind to 0.0.0.0
, which means
all interfaces available (including VPN tunnels!). So you can build
server blocks that reverse proxy public origin HTTP(S) connections
to private web servers via the VPN tunnel. A few sample server blocks
for basic services (Plex, HomeAssistant, Nextcloud, etc.) are below:
hass.tpage.io {
tls user@tpage.io
proxy / 15.21.5.2:80 {
websocket
transparent
}
}
plex-tv.tpage.io {
tls user@tpage.io
gzip
timeouts none
proxy / 15.21.5.4:32400 {
transparent
websocket
}
}
nextcloud.tpage.io {
tls user@tpage.io
gzip
proxy / 15.21.5.4:9090 {
transparent
websocket
}
}
guacamole.tpage.io {
tls user@tpage.io
gzip
basicauth / user hunter3
proxy / 15.21.5.4:8080/guacamole/ {
transparent
websocket
}
}
Wordpress
This part was the easiest, I used cURL to grab the latest
package release from WordPress.org and decompressed it
into /var/www/
. After configuring the rest of my setup,
I simply restored my previous WordPress installation with a
recent backup and everything just worked! The plugin I use
for backup/restores is: All-in-One WP Migration
Edit (3/21/2018): I’ve updated the post to describe how to make Caddy manage/renew the TLS certificates for Dovecot and Postfix
Edit (4/11/2018): Looks like there was a 0-day for Vesta being actively used - https://www.digitalocean.com/community/questions/how-do-i-determine-the-impact-of-vestacp-vulnerability-from-april-8th-2018
Edit (10/27/18): I’ve since migrated away from MIAB to using ProtonMail as my MX server, self-hosting email is too much of a burden for where I’m at in my life right now