Keep your self-hosted Ghost blog up to date - fully automated
How to automatically keep every docker container up to date. Here we will keep a Ghost blog up to date as an example.
As you may or may not know, this blog is running with Ghost with a docker-compose
setup. I have written about this in Self Hosting a Ghost blog with docker-compose, Mailgun setup, and Stripe subscriptions.
Today we are going to take a look at how to keep your blog up to date since this is a big part of self-hosting and often is neglected in these getting started blog articles.
I am focusing on a procedure that will be automated as much as I feel comfortable. The more manual steps you have to be doing the less likely you will keep things up to date. The friction must be as low as possible to achieve this.
And you know what will happen when you do not update your software? The hackers will come! 🧑💻
How to keep your docker containers up to date with Watchtower
I stumbled across a project called Watchtower. This is a docker container that will have access to the docker socket and therefore can update your containers on schedule, a specific time.
Here is the bare minimum docker-compose.yaml
for the watchtower container:
This will update all containers in a 24h rhythm by default from the time you have started this container. At least when your tags are set up correctly, so let's get to that.
How to properly tag containers for Watchtower
Since you are a decent user the tags for your docker containers are at a fixed version. Something like ghost:5.0.0
. This is in general a good idea. But Watchtower will not this particular container.
Actually, Watchtower might update the container. Watchtower will check for the docker image digest. The digest is a sha256
hash of that particular image.
For ghost:5.0.0
is 3ba1995d9b7c94c81a76df5ce85312b388f2575f9b3205db8740dd8206d7ce8b
.
Often only the first few characters will be used 3ba1995d9b7c
which is mostly long enough to not collide.
As long as that digest does not change Watchtower will not update your container. But Ghost and of course others could decide to overwrite that image tag. It is not common but it happens. Reasons may be a broken build that slipt into production or bug fixes.
Check software version policy and update guides
The right way to tag your images highly depends on your used software. Ghost for example has this document about Major Versions & Long Term Support.
You can safely use ghost:4
or ghost:5
in order to get all patch and minor version updates. If you want to stay at a specific patch version you can go with ghost:5.1
for some reason.
Now we have Ghost running and keeping up to date. Awesome! But there is another component which you have to take care of.
Your MySQL database. Ghost 5 only supports MySQL 8 in production. So you will at least have mysql:8
. But you should do some reading on that topic. Regarding to the MySQL documentation upgrading from 8.0.x
to 8.0.z
is always supported (Upgrade Paths).
So for MySQL, I would recommend: mysql:8.0
.
The last piece of software you should at least take care of is your webserver. For me that is caddy. Therefore I am just running caddy:2
.
My personal watchtower setup
Now we have Watchtower running and the tags set up correctly, you could stop here. I will just share my additional configurations for Watchtower.
I have set up a schedule to update my containers from Monday to Thursday at 6 AM UTC. Also, I want to let Watchtower clean up old images to prevent filling up the disk space with not used docker images.
Also, I wanted to have a notification via email when something is updated. Just to know. So here is my more advanced config:
version: '3'
services
watchtower:
image: containrrr/watchtower
container_name: watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
WATCHTOWER_CLEANUP: "true"
TZ: "UTC"
# 0-6 or SUN-SAT: So I want Mo-Fr at 6
WATCHTOWER_SCHEDULE: "0 0 6 * * 1-5"
WATCHTOWER_POLL_INTERVAL: 60
WATCHTOWER_TIMEOUT: "30s"
WATCHTOWER_NOTIFICATIONS: "email"
WATCHTOWER_NOTIFICATION_EMAIL_FROM: "${WATCHTOWER_EMAIL_FROM}"
WATCHTOWER_NOTIFICATION_EMAIL_TO: "${WATCHTOWER_EMAIL_TO}"
WATCHTOWER_NOTIFICATION_EMAIL_SERVER: "smtp.gmail.com"
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: 587
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER: "${WATCHTOWER_EMAIL_USER}"
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD: "${WATCHTOWER_SMTP_PASSWORD}"
WATCHTOWER_NOTIFICATION_EMAIL_DELAY: 10
restart: unless-stopped
Here the .env
file for copy-pasting.
# WATCHTOWER
WATCHTOWER_EMAIL_TO=<MAIL>
WATCHTOWER_EMAIL_FROM=<MAIL>
WATCHTOWER_EMAIL_USER=<MAIL>
WATCHTOWER_SMTP_PASSWORD=<PASSWORD>
And here you see the first ever email when the Watchtower container is started with email notifications:
Watchtower 1.4.0
Using notifications: smtp
Checking all containers (except explicitly disabled with label)
Scheduling first run: 2022-06-02 06:00:00 +0000 UTC
Note that the first check will be performed in 10 hours, 51 minutes, 40 seconds
And if an update has been applied you get something like this:
Found new netdata/netdata:latest image (06223ff4cb1f)
Found new ghost:5 image (0285ba33cc2e)
Found new ghost:5 image (0285ba33cc2e)
Stopping /eliora_ghost-eliora_1 (e9780751ac8f) with SIGTERM
Stopping /blog_ghost_1 (bfc4b2d41da8) with SIGTERM
Stopping /netdata (c8e94f42ee83) with SIGTERM
Creating /netdata
Creating /blog_ghost_1
Creating /eliora_ghost-eliora_1
Removing image 60b5698565b2
Removing image c5c7892dbbb9
New images are found and downloaded, then the current containers get stopped, new ones get created and the old image is removed to save space.
Done.
There are more options than I am using. Check the Watchtower documentation for more information.
That's it. You can apply Watchtower to way more than Ghost. I just use Ghost myself and this did work perfectly as an example.
Have a great day!