How I self-host my blog with Docker & Ansible
I have always wanted to build a blog, but for a long time, I have been postponing it.
Well, I guess I thought it was difficult to build a blog. Turns out, even if you self-host it, it’s not that hard.
I decided to finally create it one day, and I had a few criteria:
-
No fancy admin panels. I want to write markdown and deliver it as is.
-
Without sacrificing the privacy of visitors, I should be able to collect traffic statistics, i.e. Google Analytics. No external JavaScripts.
Just a number of visitors per article per day is enough for me.
-
Complete control over my data.
-
I would like to have comments on my website in the future.
Considered options
-
A popular blogging platform such as wordpress.com or blogspot.com.
The choice does not provide as much flexibility as I wanted, it has privacy issues, and I don’t have any control over my data at the end of the day.
The entire platform can be blocked in specific countries sometimes: list of contries blocking blogspot.com on Wikipedia.
-
GitHub Pages
Almost a flawless hit.
But it’s way too static, which means I’m not going to be able to have comments on my page unless I use an external solution.
The shipping of something like Disqus sacrifices privacy and leads to no data control.
Things like Disqus also have a price (or they show ads).
Self-hosting
Self-hosting has never been so easy, the only hard requirement is to have a Linux server costing $5 a month for 25GB SSD, 1GB RAM and 1vCPU.
I have selected Hugo for site generation because it is very popular, has a large supportive community, uses markdown, and has a lot of free themes.
Packaging
Packaging and distribution is done using Docker. This is how tiny my Dockerfile looks:
FROM alpine as build
RUN apk add --update --no-cache hugo
WORKDIR /srv/http/
COPY . /srv/http/
RUN hugo -e production
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /srv/http/public /srv/http/
WORKDIR /srv/http/
This ends up as a Docker container with Nginx and static HTML and CSS files.. The docker image is approximately 52MB in size.
Just two commands and the blog is ready for deployment:
$ docker build -t kovetskiy/my-blog .
$ docker push kovetskiy/my-blog
Deployment
A manual way of deployment and an automatic way are available.
Manual way
Manually, on the remote host, you would end up with commands like:
- Pull the Docker image:
$ docker pull kovetskiy/my-blog
- Stop and delete existing Docker container:
$ docker rm -f my-blog
- Start a new Docker container:
$ docker run --detach --restart=always --name my-blog -p 80:80 kovetskiy/my-blog
Automation with Ansible
A playbook is a list of tasks that should be executed to accomplish the desired status. In my case, it is pulling of the Docker image and starting a Docker container.
The playbook is saved as a file called my-blog.yaml
:
- hosts: my-server
tasks:
- name: Pull image
docker_image:
name: kovetskiy/my-blog
- name: Start container
docker_container:
name: my-blog
detach: true
image: kovetskiy/my-blog
restart_policy: always
state: started
Ansible needs a bit of project-wide configuration, it just has to understand how to connect to this
my-server
server.
To tell Ansible where the list of server is, put the following content into ansible.cfg
:
[defaults]
inventory = hosts
Add your server into the hosts
file and replace 123.123.123.123
with the host’s IP address:
[my-server]
123.123.123.123
The deployment will be done with one small command from now on:
$ ansible-playbook my-blog.yaml
Recap
How I self-host my blog:
— Egor Kovetskiy (@reconquestio) November 5, 2020
* Static site generated with Hugo
* Packaged with Docker: docker build
* Linux host/droplet on Linode/DigitalOcean
* Ansible for the deployment of Docker containers
Which topic to expand first?
Links
I also self-host an open source comments system without sacrificing any privacy. 👇
Comments