David's Coding Blog

My Home Server Setup

In this blog post, I will document the setup of my first home server, covering everything from the hardware to the software.

The server

Since I didn’t want to invest a fortune right from the start, I bought a mini PC with 12 CPU cores, 12 GB of memory and 500 GB of SSD storage. This is more than enough for my initial experiments, and it has low power consumption.

I chose Ubuntu Server for the operating system and installed Docker using the package manager. The aim is to keep the server setup simple. Ideally, everything should run as a Docker container, which reduces the number of packages installed on the OS itself and keeps it clean.

After the server was installed I have connected it directly to the router.

The applications

The first container on the server was a simple HTML page showing all the applications running on the server, along with links to them. This was followed by Portainer, a Speedtest Tracker and Pi-hole. If a container requires persistent storage, its paths are mounted to a subfolder in /srv (e.g. /srv/pihole), so all container data is stored in one place.

Until a few days ago, all applications had to be accessed via the server IP address and application port. This meant that the URLs in browsers were difficult to remember, e.g. http://192.168.2.101:8083/.

DNS and Nginx

Instead of using a local DNS server provided by the router or Pi-Hole, I came up with the idea of using public DNS entries. I purchased the domain masterzydra.de (my GitHub username) and created subdomain entries such as pihole.masterzydra.de.

All these subdomains are CNAME entries, meaning they point to another domain instead of an explicit IP address. The domain they are pointing to is nl-sr1.masterzydra.de, which points to the local IP address of my home server. This configuration allows the server IP address to be changed in one place, rather than having to modify all DNS entries individually.

In order to use the new subdomains, I installed Nginx as proxy to resolve incoming requests, e.g. for pihole.masterzydra.de, and forward them to local port 8080.

Right now, everything is running on HTTP, and each Nginx configuration is based on the following template:


server {
    listen 80;
    server_name {{ domain }};

    location / {
        proxy_pass http://127.0.0.1:{{ port }};

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

To simplify the creation of new configurations and the modification of existing templates, I created a Bash script that uses the template and fills it in for each domain:


#!/bin/bash

confPath="/srv/nginx/conf.d/"

containerName="nginx-proxy"

removeAllConfs () {
    echo "Removing all configuration files..."
    rm -f "${confPath}"*
}

createConf () {
    confFileName=$1
    domain=$2
    port=$3

    echo "Creating ${confFileName}..."

    confFile="${confPath}${confFileName}"

    cp template.conf "${confPath}${confFileName}"

    sed -i "s|{{ domain }}|${domain}|g" $confFile
    sed -i "s|{{ port }}|${port}|g" $confFile
}

# Remove all configrations
removeAllConfs
echo ""

# Config files
createConf "01-home.conf" "home.masterzydra.de" "8089"
createConf "02-beszel.conf" "beszel.masterzydra.de" "8090"
createConf "02-metube.conf" "metube.masterzydra.de" "8085"
createConf "02-overleaf.conf" "overleaf.masterzydra.de" "8091"
createConf "02-pihole.conf" "pihole.masterzydra.de" "8080"
createConf "02-portainer.conf" "portainer.masterzydra.de" "9000"
createConf "02-speedtest.conf" "speedtest.masterzydra.de" "8082"
echo ""

# Fix ownership
echo "Fixing file ownership..."
chown -R root:root $confPath
echo ""

# Restart container
echo "Restarting container ${containerName}..."
docker stop $containerName >/dev/null 2>&1
docker start $containerName >/dev/null 2>&1
echo ""

echo -e "\e[1;32mDone\e[0m"

The script involves the following steps: