Self Hosting Websites using Docker

I decided to self host Ghost CMS for this blog, and needed to expose its interface to the public. I found Nginx Proxy Manager (NPM) quite appealing, and decided to give it a try.

Background

There are many ways to host your own website(s). The combination I chose and documented here is just one of them. In particular,

  • I have obtained a VPS in the cloud, running Ubuntu.
  • In the past, I would just install the plain old Nginx, log in into the machine remotely, and manage services using the command line.
  • Recently I found many people using NPM, and wanted to give it a try.
  • As switching to NPM almost means I need to use Docker as the basis for the services I am hosting later, more investigations are needed, especially for the case where the services to be hosted do not run as Docker containers.

Preparation

Naturally, before deciding on NPM I have searched the web for related information. This process highly subjective for different people, and for different purposes. For me, at least right now, I will just make sure the tool is widely used and frequently maintained, has no obvious drawbacks and bad reputation, and will not lock me down so deep that I cannot leave it without a lot of reworking.

To install NPM, I start with skimming the web for common practices, while paying attention to the official website at the same time. I don't want to just jump in following the official website and filling the blanks myself, only to find later that there are common or better practices people use. However, while "unofficial" blog posts and guidelines can provide quicker introduction, more well-rounded instructions, and useful feedbacks in shorter passages, they may contain outdated information.

Installation

First create a "parent" folder that will hold container configurations and working spaces for NPM and other services later.

mkdir ws
cd ws

Create the folder for NPM:

mkdir npm1
cd npm1

Head to official website for setup instructions, then create docker-compose.yaml with the following content:

networks:
  mynet:
    name: mynet

services:
  mynpm:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    ports:
      - '80:80' # Public HTTP Port
      - '443:443' # Public HTTPS Port
      - '81:81' # Admin Web Port
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    network:
      - mynet
      

The major modifications compared to the website are:

  • remove the version property
  • define a network mynet, on which this NPM and other containers will run later
  • change the container "block" name to mynpm for clear reference later (can also set container_name)

Now launch NPM using docker compose:

docker compose up -d

after which, you can also see the running logs by

docker compose logs -f

You can access NPM via http://localhost:81 and initialize the admin account. However, since the procedure is over HTTP, entering passwords would not feel right. Since we will be serving main services, likely including the NPM itself, it is better to obtain domain names, bind them to corresponding IPs, and try to run things over HTTPS. For more detailed setup, see this lab.

Serving Another Site

Assuming you have set up NPM and can access it using the domain name of your choice over HTTPS. It is easy now to add another site, on another domain.

Let's just use a bare Nginx container as an example. Suppose you have created the domain docs.example.com and bound to the same IP where the NPM is running. Create another folder (next to NPM's)

mkdir docs
cd docs

Create inside the docker-compose.yaml file:

networks:
  mynet:
    name: mynet
    external: true

services:
  docs:
    restart: unless-stopped
    image: nginx:1-alpine
    expose:
      - 80
    # volumes:
    # - ./html/:/usr/share/nginx/html
    networks:
      - mynet

Launch the service

docker compose up -d && docker compose logs -f

If everything is running OK, back to the NPM page, and add the following proxy host (please rename accordingly):

  • domain name: docs.example.com
  • scheme, hostname, and port: http, docs, 80
  • obtain the SSL certificate

You can see if the bare Nginx site is accessible by visiting https://docs.example.com.

If you want to try some HTMLs of your own, you can uncomment the volumes lines in the docker compose file, create an html subfolder, and place index.html and other files in it.

References

  • Install Docker and Docker Compose - see lab
  • Install NPM - see lab