Serves you right!
A new post for a new year! I spent my previous post advocating
having been a heavy
Vim user for many years. I’ll definitely get back to my
editor setup in future posts, but before that I thought I’d do a quick post
about the server setup I’m currently using for this site. It’s not overly
complex, so the post won’t be too long (hopefully).
I’ve been using Linode as a
VPS provider for quite some time. I won’t say I’m
a power user when it comes to hosting.
Linode gives me more than enough
freedom to run the services I want, at a comfortably low price-point ($5/month).
Linode configuration interface makes it easy to setup and manage server
DNS and networking, emergency login shells, automated
backups, and whatnot. Like I said though, I’m not a power user so I can’t really
comment on all of the features they provide.
I have been running servers for many years, although mostly for personal
(non-)use1. This time, instead of installing everything
using standard package managers and global installations, I decided to give
Docker a go.
Due to the simplicity of my current setup, I’m using Docker Compose2 to orchestrate the few services I use. It’s using a
yaml configuration file to define and manage the different images used for
each service. My configuration isn’t overly complicated, once you look past the
fact that most of it is simply specifying mount points for the different
services. The images I currently use are vanilla images fetched from the Docker Hub.
nginx image provides a vanilla
Nginx server packaged for
are two currently in my setup:
- The internet-facing reverse proxy.
- The static server serving the contents of this blog.
It’s fairly obvious that running muliple instances of
Nginx may be quite
overkill, but to me the convenience this setup provides trumps it. Hopefully it
becomes clear why when talking about the other two services.
version: "3.2" services: nginx: restart: always image: nginx container_name: nginx ports: - "80:80" - "443:443" volumes: - "/data/nginx/certs:/etc/nginx/certs:ro" - "/data/nginx/conf.d:/etc/nginx/conf.d:ro" - "/data/nginx/html:/usr/share/nginx/html:ro" - "/data/nginx/vhost.d:/etc/nginx/vhost.d" myme.no: restart: always image: nginx container_name: myme.no depends_on: - letsencrypt volumes: - "/data/myme.no/nginx:/etc/nginx/conf.d:ro" - "/data/myme.no/public:/usr/share/nginx/html:ro" environment: - VIRTUAL_HOST=myme.no - LETSENCRYPT_HOST=myme.no - LETSENCRYPT_EMAILfirstname.lastname@example.org
docker-gen is a smart little image which uses the
Docker APIs to determine
when containers come and go and dynamically adds a virtual host configuration
for them in the reverse proxy. This means that it’s as simple as firing up a new
container with the correct
VIRTUAL_HOST configuration, and suddenly a new
virtual host is readily configured in the proxy.
Now adding and removing vhosts is not something I do often, to be honest. But the simplicity of it all makes adding new services effortless.
nginx-gen: restart: always image: jwilder/docker-gen container_name: nginx-gen depends_on: - nginx volumes: - "/data/nginx/certs:/etc/nginx/certs:ro" - "/data/nginx/conf.d:/etc/nginx/conf.d:rw" - "/data/nginx/templates/nginx.tmpl:/etc/docker-gen/templates/nginx.tmpl:ro" - "/data/nginx/vhost.d:/etc/nginx/vhost.d:ro" - "/var/run/docker.sock:/tmp/docker.sock:ro" entrypoint: >- /usr/local/bin/docker-gen -notify-sighup nginx -watch -wait 5s:30s /etc/docker-gen/templates/nginx.tmpl /etc/nginx/conf.d/default.conf
The final piece of the puzzle is an image which creates and maintains Let’s Encrypt certificates for all exposed services. This means you get
free, without lifting a finger. The image also ensures that certificates are
renewed automatically when they close in on their expiration date.
Now there’s no reason not to serve secure pages using
HTTPS. Here’s that part
of the config:
letsencrypt: restart: always image: jrcs/letsencrypt-nginx-proxy-companion container_name: letsencrypt depends_on: - nginx-gen volumes: - "/data/nginx/certs:/etc/nginx/certs:rw" - "/data/nginx/html:/usr/share/nginx/html:rw" - "/data/nginx/vhost.d:/etc/nginx/vhost.d:rw" - "/var/run/docker.sock:/var/run/docker.sock:ro" environment: - NGINX_DOCKER_GEN_CONTAINER=nginx-gen - NGINX_PROXY_CONTAINER=nginx
That’s it folks!
As I’m getting older I realize that I want more and more of what I use in my
daily life to just work. I’m definitely not as eager as I was before to tinker
around with things just for fun.3 So even though I ended up running
multiple instances of
Nginx and managing my services using
Docker, I feel
like my current setup is simple in the sense that I don’t have to do much to
have it work as I intend it to.
The servers I’ve been running have had a tendency to get neglected and not really used for anything purposeful, or just running
Docker Composeis not advised to be used in production. Besides the fact that my setup hardly qualifies as “production”, it seems more than stable enough for my needs.↩︎
That’s not completely true though, as I do have a tendency to start short-lived (or active) coding projects just to try out some stuff.↩︎