Post-Platform Digital Publishing Toolkit

Self-hosting (a static website)

In this guide I will try to document how we host our (static) websites at Well Gedacht Publishing. Here is an example, and another one, and another one.

Setting up something like a home server is a fairly straight forward process; depending on what your expectation is, it is possible to do it in different levels of complexity. This guide focuses on the relatively simple method (as opposed to a more comprehensive “homelab” running services like Nextcloud—explained here), which uses a Linux computer that could be your old laptop you keep turned on always, or an old desktop PC, mini-PC, a single board computer like a Raspberry Pi, or basically anything that can run a Linux distro and has enough juice to run two Docker containers. Docker is a containerization (virtualization) system, and an alternative to it is Podman, and both of them are part of the Open Container Initiative. This means you can use the same container images with both of them.

Before the setup: the intro

Before getting into the setup, the first thing you have to check is related to your internet connection at home, or where you want to setup the server for your website. Generally, to be able to setup self-hosting a website, and make your server accessible to traffic on the internet, you need to have a static IP address. This address is then used when someone wants to visit your website. Most, if not all, internet service providers though, do not give their customers static IP addresses; the static ones are usually reserved for “enterprise,” and is not possible to get with typical customer internet plans. But no worries, there are still some ways to overcome this issue. You can use VPS, a virtual private server, which your home server connects to with its dynamic IP address, and you direct visitor traffic to your website via this “gateway,” which is one way to solve the problem. Another solution is to use a tool which updates your DNS records, every time your dynamic IP address changes. The former is a simpler solution, as it does not require a second, external server.

The second issue, which you have to pay attention to, before setting up everything, is to understand if your ISP is using a system called double-NAT or CG-NAT. If that is the case, your public IP which is visible to the outside traffic, is different from the one that you see in the admin panel of your modem. If these IP addresses are different from each other, it means your ISP is using something like a double-NAT, which is an issue when you want your home server accessible to the outside traffic. To understand if you are behind a double-NAT, you can go to a website that shows you your IP address, like whatismyip etc. Take a note of that IP address. Then, login to your modem's admin panel (which is usually done by typing 192.168.X.X—you can find the correct address by googling your modem's brand and model) and look for the IPv4 address that is shown there. If the two IP addresses, the one that is shown by “whatismyip-type-of-website” and the one you see on your modem's admin panel are different than each other, this means your ISP is using a double-NAT type of thing.

I think some ISPs let their customers use an IPv6 address, which—I believe—also makes it possible to do what we want, but as I have no experience with it, I cannot elaborate much on that. The issue with self-hosting a website with IPv6 is that only people with IPv6 addresses can access your site, but also, it is possible to solve that with some tunneling (more on that here, and here).

Back to the issue with double-NAT though, and there are multiple solutions to this problem. The first and usually simple one is to call your ISP, and ask them not to use double-NAT, or to tell them that you need an IP address. The issue is that they sometimes allocate one public IP address to multiple customers, and share this one IP in between them. But when you ask them not to do that, most of them say OK, and give you an IP address, which is still dynamic, but at least yours. Some do this for free, others might charge you a fee.

Another way to tackle the issue related to your ISP using double-NAT or CG-NAT, and not having an accessible public IP address for your home internet, is again to use a VPS or a VPN like these:

At Well Gedacht Publishing, we also had this issue with the ISP sharing an IP address with multiple households, and were able to get a dedicated IP—yet a dynamic one—after calling their customer service. Currently, our self-hosted websites and services run on our home server, without any VPS or another type of solution to the dynamic IP address problem. This means that once our ISP decides to change our IP address, for example if we restart our router, or the electricity goes out etc, our IP address changes too, and in that case, we would need to update the DNS records on our registrars ourselves; also meaning that our websites will be inaccessible, if we don't update the IP address on the DNS records, which is something we are OK with. Every once in a while, your websites might have some downtime, and if you are OK with this, you can even self-host with your dynamic IP address. There are also tools for monitoring the uptime of your sites, like this one.

Figure 1: A self-hosted website

Requirements

  • A PC running Linux (Debian, or Ubuntu Server)
  • Docker or Podman installed (to self-host our static website, we are using two Docker containers: nginx, and nginx-proxy-manager)
  • That's it!

The steps to follow

  1. We start by installing Debian or Ubuntu Server on our PC. Please look up for the respective distro's instructions on how to do this. This guide is based on Debian.
  2. After installing either use a monitor, mouse and keyboard, or SSH into the PC.
  3. Install Docker (or Podman). Please look up how to install Docker on your Linux distro. For Debian you can simply follow these steps. Seting up Docker's apt repository:
    # Add Docker's official GPG key:
    sudo apt-get update
    sudo apt-get install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc
    
    # Add the repository to Apt sources:
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update

    Install the Docker packages:

    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    Verify that the installation is successful by running the hello-world image:

    sudo docker run hello-world
  4. Optional step: You can run Docker on the terminal, but if you prefer to have a GUI to manage your Docker containers, you can install Portainer. For deploying the Portainer as a Docker container, you can:
     sudo docker run -d -p 9000:9000 --restart always -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer-ce:latest 
  5. Create a directory where you will place the index.html file, named site-content:
     mkdir ~/site-content 
  6. Next step is to deploy the Nginx web server container. For that, we simply type:
     sudo docker run -it --restart always -d -p 8080:80 --name web -v ~/site-content:/usr/share/nginx/html nginx 

    This command tells this Nginx container to listen for upcoming traffic on the port 8080, and the content of your website, such as the index.html goes to the directory ~/site-content, and the name of the container is “web.” You can check if Nginx is succesfully deployed and running by typing your-computer's-IP-address:8080 on your brower, and it will show you this page:

  7. Now, we need to deploy the Nginx Proxy Manager container, which is a very nice reverse proxy manager. With it you can expose the ports 80 and 443 of your router to outside traffic, and then direct the incoming traffic to the web server you deployed in the previous step. It also helps you with getting SSL encryption certificates with Let's Encrypt and use https on your website very easily. First, create a new directory called npm:
    mkdir -p npm
    cd npm

    Then, create a Docker compose file there:

    # Create a docker-compose configuration file
    touch docker-compose.yml
    # Editing the file
    nano docker-compose.yml

    Put these inside the docker-compose.yml:

    version: '3.8'
    services:
      app:
        image: 'jc21/nginx-proxy-manager:latest'
        restart: unless-stopped
        ports:
          - '80:80'
          - '81:81'
          - '443:443'
        volumes:
          - ./data:/data
          - ./letsencrypt:/etc/letsencrypt 

    Finally, you need to run:

    docker compose up -d 

    Now, your Nginx Proxy Manager admin UI should be accessible at your Linux PC's IP address on your local network, on port 81 (something like 192.168.186.10:81).

  8. With this step, you have all the things ready for self-hosting your website. Now, important thing to do is, logging into your router's admin panel, and opening up the ports 443 and 80 (port 80 for HTTP and 443 for HTTPS traffic) to the internet. You do this by editing the port forwarding settings on your router, please check your router's instructions online, for how to do this. You need to direct incoming traffic from port 80 to your-pc's-ip-address:80 and port 443 to your-pc's-ip-address:443. In this way, Nginx Proxy Manager will start to listen incoming traffic on these ports, and will direct the traffic to our Nginx web server we set up on step 5.
  9. Copy your static website's index.html file into the Nginx web server's public www directory, which we determined as ~/site-content.
  10. Now go to your domain registrar's website, login, and add an A record for your domain. This A record should direct traffic to your public IPv4 address, which you looked up on a what-is-my-IP-type-of-website earlier.
  11. All you need to do know is to direct the incoming traffic via Nginx Proxy Manager to your-computer's-local-IP-address:8080. In order to do that go to Nginx Proxy Manager admin UI on your-computer's-local-IP-address:81, go to Proxy Hosts tab, click on Add Proxy Host on top right corner. Enter your domain name, and beneath that enter your-computer's-local-IP-address and the port 8080. Keep the scheme http. Enable “block common exploits.” Go to the SSL tab on the same window, and click on “request a new SSL certificate.” You can enable all of the options below (but beware; some options might make your website unreachable, so try out by disabling and enabling them). Enter your email address for Let's Encrypt, accept the ToS, and click on save. Now your website should be reachable on your domain! 🌐

Solving the dynamic IP issue

Here I will document my solution to dynamically update the dynamic IP address on the DNS records of my domain. Using something like this. Coming up soon! FIXME

Well Gedacht Publishing 2025/02/21 14:40


Nice tools which are not in the scope of this guide, or other guides for self-hosting:

guides/self-hosting_guide.txt · Last modified: 2025/02/23 11:45 by wgp