This is an old revision of the document!
Self-hosting (a Static Website)
This guide documents 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 relatively straightforward process; depending on your expectations, it is possible to do it at different levels of complexity. This guide focuses on the relatively simple method (as opposed to a more comprehensive “homelab” running services like Nextcloud—explained in our separate guide), which uses a Linux computer that could be your old laptop you always keep powered on or an old desktop PC, mini-PC, a single board computer like a Raspberry Pi, or anything that can run Linux and has enough juice to run two Docker containers. Docker is a containerization (virtualization) system, and an alternative to Docker is Podman, and both are part of the Open Container Initiative. You can use the same container images with Docker and Podman.
Before the Setup: the Intro
Before getting into the setup, you first have to check your internet connection at home or where you want to set up the server for your website. Generally, to set up a self-hosting 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 it 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 that your home server connects to with its dynamic IP address, and you can direct visitor traffic to your website via this “gateway,” which is one way to solve the problem. Another solution is to use a tool that updates your DNS records every time your dynamic IP address changes. The former is a more straightforward solution, not requiring a second external server.
The second issue you must 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, visible to the outside traffic, differs from the one you see in your modem’s admin panel. If these IP addresses differ, your ISP uses a double NAT, which is an issue when you want your home server accessible to outside traffic. To understand if you are behind a double NAT, visit a website showing your IP address, like Whatismyip. Take note of that IP address. Then, log in to your modem’s admin panel (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 shown there. If the two IP addresses, the one shown by “whatismyip-type-of-website” and the one you see on your modem’s admin panel, are different, 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 it is also possible to solve that with some tunneling (more on that here, and here).
There are multiple solutions to the issue with double-NAT, though. The first and usually simple one is to call your ISP and ask them not to use double-NAT or to tell them you need an IP address. The issue is that they sometimes allocate one public IP address to multiple customers and share this one IP between them. But when you ask them not to do that, most say OK and give you an IP address, which is still dynamic, but at least yours. Some do this for free, while 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: Self-hosted Gateway, a self-hosted VPS solution, or WireGuard, a FOSS VPN software (or Tailscale, a proprietary alternative based on WireGuard, or Netbird). A VPN like WireGuard does not solve the problem itself, but more on that later.
At Well Gedacht Publishing, we also had this issue with the ISP sharing an IP address with multiple households. Still, we got a dedicated IP—yet dynamic—after calling their customer service. After solving the double-NAT issue, our self-hosted websites and services run on our home server, but there is no solution to the dynamic IP address problem. That 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. Occasionally, 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 your sites’ uptime, like Uptime Kuma and updating your DNS records automatically when they are changed, like DDNS Updater Docker container.

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
- We start by installing Debian or Ubuntu Server on our PC. Please look for the respective distro’s instructions on how to do this. This guide is based on Debian.
- AAfter installing, use a monitor, mouse, keyboard, or SSH into the PC.
- Install Docker (or Podman). Please look up how to install Docker on your Linux distro. For Debian, you can follow these steps. Setting 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
- 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
- Create a directory where you will place the index.html file, named site-content:
mkdir ~/site-content
- Next step is to deploy the Nginx web server container. For that, we 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 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 browser, and it will show you this page:
- We need to deploy the Nginx Proxy Manager container, which is a very nice reverse proxy manager. With it you can expose 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 get 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).
- 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 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.
- Copy your static website's index.html file into the Nginx web server's public www directory, which we determined as ~/site-content.
- Now go to your domain registrar's website, log in, and add an A record for your domain. That A record should direct traffic to your public IPv4 address, which you looked up on a what-is-my-IP-type-of-website earlier.
- All you need to know is to direct the incoming traffic via Nginx Proxy Manager to your-computer’s-local-IP-address:8080. To do that, go to Nginx Proxy Manager admin UI on your-computer’s-local-IP-address:81, go to the Proxy Hosts tab, and click on Add Proxy Host in the top right corner. Enter your domain name, and enter your computer’s local IP address and port 8080 beneath that. Keep the scheme http. Enable “block common exploits.” Go to the SSL tab in the same window and click “Request a new SSL certificate.” You can enable all of the options below (but beware; some options might make your website unreachable, so try 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!
— 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: