Hosting Hackmd and Nginx inside Docker containers
It’s my side project for learning networking and docker. :)
The goal is to run both Nginx to Hackmd in Docker containers.
Introduction
Hackmd can be easily run in the container thanks to the developers from HackMD for dockerizing the entire project already. The part for setting up Nginx, interconnecting containers, and properly setting up the port and stuff to expose the containers, is what makes this project interesting.
Let’s begin our journey!
Make sure that you have docker and docker-compose installed.
Hackmd
Installation
Running self-hosted Hackmd is super easy
- Get the docker stuff that is already prepared for you by running
git clone https://github.com/hackmdio/codimd-container.git
cd docker-hackmd
, andrun docker-compose up
(In future runs,docker-compose up -d
to run the containers in the background)
Update
Taken from the official documentation.
|
|
Backup
Where is the data?
- If we trace the
docker-compose
file of HackMD, we can see that for thedatabase
, there is a volume associated with it. - After running
docker-compose up
, we can rundocker volume ls
to inspect what volumes are mounted now. - After knowing the volume’s name, we can use
docker volume inspect [name]
to see more, including the location that the volume is actually storing its data!sudo cd
won’t work. Usesudo -i
and thencd
Backup
docker-compose exec database pg_dump hackmd -U hackmd > backup.sql
Restore
cat backup.sql | docker exec -i $(docker-compose ps -q database) psql -U hackmd
Nginx
We will build our own Nginx image for container, so we can get the bash shell, logs, and be able control lots of stuff easily. The tradeoff will be huge image size though…
The dockerfile
for Nginx. Build it with docker build -t nginx .
|
|
Nginx config file and basic auth details is explained below.
Basic auth
The basic auth works by creating a username-password file by using htpassed
tool. After creating the file, we just need to add it to Nginx’s configuration file.
- Install
apache2-utils
- Create users
sudo htpasswd -c .htpasswd Henry
-c
means create file, so only use it on the first run!)
- Watch out for the location you put the file in the container. If you put it at
/root
, Nginx won’t be able to read it, since its permission is700
.- Internal server error of
500
will occur since the system can’t open the file - Digging from the log, which is usually kept at
/var/log/nginx
, is a good way good way to debug!
- Internal server error of
Hosting on Virtual Host
For every virtual host that you want to host your website, create a dedicated file for it! For example, if I want to have a website at test.henrybear327.com
, we need to create a config file with name test.henrybear327.com
Sample config file:
|
|
There are several things in this file that required attention.
The first thing is the proxy_pass
. Because when running docker-compose
, it will automatically create a new network! So the Nginx must be on the same network as HackMD (will be discussed about later).
Another thing is that the address of the container we will be connecting to. It’s not localhost:3000
, it’s the container’s name!
Starting HackMD and Nginx containers
If you have done the previous HackMD and Nginx setup correctly, we can now start our containers! We will start the HackMD first, and then connect Nginx to HackMD’s network, and exposing the 80 or 443 port to the outside world!
|
|
The part for starting the Nginx container is a little bit complicated.
As mentioned before, docker-compose
will create its own network. So after starting it, we need to use sudo docker network ls
to check the network name, and specify it in the --net
argument.
-p 80:80
or -p 443:443
depends on your connection type.
Stopping HackMD and Nginx containers
Simply… stop it :)
|
|
Sidenotes
- Use
docker container exec <container> nginx -s reload
to reload Nginx if you have changed some config file - Whatever changes you do to the Nginx config files, run sudo nginx -t to perform a check before reloading it
Nginx with Cloudflare SSL
After messing with Let’s encrypt for quite a while, I decided to simply use Cloudflare’s origin certificate…
The following passage is taken from this post… Great explanation about Cloudflare origin vs Let’s encrypt Certificate
If you use Cloudflare to front your website, there’s no real point to continually renewing Let’s Encrypt certs every few months. The end user never sees your server cert and doesn’t have to trust it, so the long-lived origin cert is probably less work.
Setup
- Have your site hide behind cloudflare’s.
- Generate the origin certificate
- Update dockerfile and nginx config file
- Update
dockerfile
andnginx config file
- New test.henrybear327.com config file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
server { listen 443; ssl_certificate /etc/ssl/certs/henrybear327.com.pem; ssl_certificate_key /etc/ssl/private/henrybear327.com.key; auth_basic_user_file /etc/nginx/conf.d/.htpasswd; proxy_pass http://docker-hackmd_app_1:3000/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; } }
- New
dockerfile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
FROM ubuntu:bionic ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update RUN apt-get upgrade -y RUN apt-get install -y apt-utils man RUN apt-get install -y locales sudo wget curl htop RUN apt-get install -y vim RUN apt-get install -y nginx RUN mkdir /var/run/sshd RUN locale-gen zh_TW.UTF-8 ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 # Notice that the symbolic link for linking must be absolute path! COPY test.henrybear327.com /etc/nginx/sites-available/test.henrybear327.com RUN sudo ln -s /etc/nginx/sites-available/test.henrybear327.com /etc/nginx/sites-enabled/test.henrybear327.com COPY .htpasswd /etc/nginx/conf.d COPY henrybear327.com.key /etc/ssl/private COPY henrybear327.com.pem /etc/ssl/certs EXPOSE 443 CMD ["nginx", "-g", "daemon off;"]
- New test.henrybear327.com config file
Turn your SSL
to full(strict)
and set Always Use HTTPS
to on
!
Well done! Now the site is on HTTPS!