homelab/homelab-documentation.md
Mikkel Georgsen a6bf1c7706 Initial commit: homelab documentation and management
- homelab-documentation.md: Complete infrastructure docs
- CLAUDE.md: Claude Code guidance
- README.md: Quick reference

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 12:38:45 +00:00

15 KiB

Mikkel's Homelab Infrastructure

Overview

This document describes the complete homelab infrastructure spanning Hetzner cloud servers, home NAS, and future expansion plans.


Core Infrastructure

core.georgsen.dk (Primary Server)

Attribute Value
Provider Hetzner (AX52)
Location Helsinki, Finland
CPU AMD Ryzen 7 3700X
RAM 64GB ECC
Storage 2x 1TB NVMe (RAID0) - ZFS (rpool)
OS Proxmox VE
Public IP 65.108.14.165/26
IPv6 2a01:4f9:6a:4a4f::/64

Warning: Storage is RAID0 — no local redundancy. PBS backups to Synology are critical.

Network Bridges

Bridge Purpose Subnet Gateway
vmbr0 Public internet 65.108.14.165/26 65.108.14.129
vmbr1 Internal services 10.5.0.0/24 10.5.0.254
vmbr2 Hetzner vSwitch 10.9.1.0/24 10.9.1.1

vSwitch Details

  • Cloud Network: #11828854
  • Subnet: 10.9.1.0/24
  • Routes to: 10.9.0.0/16 via 10.9.1.1
  • MTU: 1400

Network Configuration

/etc/network/interfaces (core)

auto lo
iface lo inet loopback

auto enp9s0
iface enp9s0 inet manual

auto enp9s0.4000
iface enp9s0.4000 inet manual
    mtu 1400

auto vmbr0
iface vmbr0 inet static
    address 65.108.14.165/26
    gateway 65.108.14.129
    bridge-ports enp9s0
    bridge-stp off
    bridge-fd 0

iface vmbr0 inet6 static
    address 2a01:4f9:6a:4a4f::/64
    gateway fe80::1

auto vmbr1
iface vmbr1 inet static
    address 10.5.0.254/24
    bridge-ports none
    bridge-stp off
    bridge-fd 0

auto vmbr2
iface vmbr2 inet static
    address 10.9.1.2/24
    bridge-ports enp9s0.4000
    bridge-stp off
    bridge-fd 0
    mtu 1400
    up ip route add 10.9.0.0/16 via 10.9.1.1 dev vmbr2
    down ip route del 10.9.0.0/16 via 10.9.1.1 dev vmbr2

Port Forwarding (iptables)

External Port Internal Destination Purpose
80 10.5.0.1:80 NPM HTTP
443 10.5.0.1:443 NPM HTTPS

NAT masquerade enabled for 10.5.0.0/24 → vmbr0

DHCP (dnsmasq)

  • Range: 10.5.0.100 - 10.5.0.200
  • Lease time: 24h

Virtual Machines

VM 200: mail.georgsen.dk (Stalwart Mail Server)

Attribute Value
Type VM (KVM)
IP 65.108.14.164 (dedicated public IP)
Bridge vmbr0 (direct)
Software Stalwart Mail Server
Webmail Snappymail (via dockge)

Current domains: dataloes.dk (building reputation before adding more)

Planned domains: georgsen.dk, microsux.dk, dataloes.dk


LXC Containers

Container Overview

VMID Name IP Purpose Status
100 npm 10.5.0.1 Nginx Proxy Manager Running
101 dockge 10.5.0.10 Docker Compose Manager Running
102 mgmt 10.5.0.102 Management/Automation (Claude Code) Running
103 postgresql01 DHCP PostgreSQL (community) Running
104 redis01 DHCP Redis (community) Running
105 sentry DHCP Defense Intelligence System Running
106 pbs 10.5.0.6 Proxmox Backup Server Running
107 pve-scripts-local DHCP Community Scripts Web UI Running
108 jukebox DHCP (→10.5.0.184) Music Player (custom project) Running
110 sense.microsux.dk DHCP CBD Vendor Locator Stopped
111 dev DHCP Development container Running
112 dataloes 10.5.0.112 dataloes.dk website Stopped
113 general 10.5.0.113 Decomissioned Stopped
114 forgejo 10.5.0.14 Git server (Forgejo) Running
115 dns 10.5.0.2 DNS server (Technitium) Running
1000 tailscale 10.5.0.x + 10.9.1.10 Tailscale relay Running

Container Details

100: NPM (Nginx Proxy Manager)

  • Purpose: Reverse proxy with automatic Let's Encrypt certificates
  • IP: 10.5.0.1
  • Ports: 80, 443, 81 (admin)
  • SSL: Let's Encrypt (HTTP challenge)

Proxy Hosts:

Domain Destination SSL
dataloes.dk, www.dataloes.dk http://10.5.0.112:80 Let's Encrypt
dev01.georgsen.dk http://10.5.0.113:3001 Let's Encrypt
dns.georgsen.dk http://10.5.0.2:5380 Let's Encrypt
dockge.georgsen.dk http://10.5.0.10:5001 Let's Encrypt
git.georgsen.dk http://10.5.0.14:3000 Let's Encrypt
jukebox.georgsen.dk http://10.5.0.184:4000 Let's Encrypt
pbs.georgsen.dk https://10.5.0.6:8007 Let's Encrypt
status.georgsen.dk http://10.5.0.10:3001 Let's Encrypt
webmail.georgsen.dk http://10.5.0.10:8888 Let's Encrypt

101: Dockge

  • Purpose: Docker Compose stack management
  • IP: 10.5.0.10
  • Port: 5001

Running Stacks:

# Snappymail (webmail for Stalwart)
services:
  snappymail:
    image: djmaze/snappymail:latest
    container_name: snappymail
    restart: unless-stopped
    ports:
      - 8888:8888
    volumes:
      - ./data:/var/lib/snappymail

# Uptime Kuma (status monitoring)
services:
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    restart: unless-stopped
    ports:
      - 3001:3001
    volumes:
      - ./data:/app/data

105: Sentry (Defense Intelligence)

  • Purpose: Custom defense intelligence system for monitoring military contracting opportunities
  • Focus: Ground equipment (EV conversion, diesel upgrades, specialty vehicles, bomb loaders, Humvee engines)
  • Databases: Uses postgresql01 and redis01

106: PBS (Proxmox Backup Server)

  • Purpose: Centralized backup for all PVE nodes
  • IP (vmbr1): 10.5.0.6
  • Tailscale IP: 100.115.85.120
  • Web UI: https://10.5.0.6:8007

Configuration:

  • Container type: Privileged (required for NFS/CIFS)
  • Features: nesting=1
  • AppArmor: unconfined
  • TUN device enabled (for Tailscale)

Datastore:

  • Name: synology
  • Path: /mnt/synology/datastore
  • Backend: Synology NAS via CIFS over Tailscale

Namespaces:

  • core.georgsen.dk
  • pve01.warradejendomme.dk
  • pve02.warradejendomme.dk

Retention Policy:

  • Keep Daily: 7
  • Keep Weekly: 4
  • Keep Monthly: 3

Schedule:

  • Prune: 21:00
  • GC: 22:30
  • core backup: 01:00
  • pve01 backup: 01:30
  • pve02 backup: 02:00

108: JukeBox

114: Forgejo (Git Server)

  • Purpose: Self-hosted Git server (GitHub alternative)
  • IP: 10.5.0.14
  • Port: 3000
  • URL: https://git.georgsen.dk
  • Software: Forgejo 10.0.1
  • Storage: 60GB

115: Technitium DNS

  • Purpose: Local DNS server with web UI and API
  • IP: 10.5.0.2
  • Ports: 53 (DNS), 5380 (Web UI)
  • URL: https://dns.georgsen.dk
  • Features: Authoritative DNS for internal zone, upstream forwarder

1000: Tailscale

  • Purpose: Tailscale access to vmbr1 and vmbr2 networks
  • IPs: vmbr1 (DHCP) + 10.9.1.10 (vmbr2)
  • Tailscale IP: 100.99.33.100

Backup Architecture

┌─────────────────────────────────────────────────────────────────┐
│  BACKUP FLOW                                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  core.georgsen.dk ────────┐                                     │
│  (01:00 daily)            │                                     │
│                           ▼                                     │
│  pve01.warradejendomme.dk ──► PBS (10.5.0.6)                    │
│  (01:30 daily)            │        │                            │
│                           │        │ CIFS over Tailscale        │
│  pve02.warradejendomme.dk ┘        ▼                            │
│  (02:00 daily)                Synology NAS                      │
│                               (100.105.26.130)                  │
│                                                                 │
│  Retention: 7 daily, 4 weekly, 3 monthly                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

PBS Container Config (/etc/pve/lxc/106.conf)

arch: amd64
cores: 2
features: nesting=1
hostname: pbs
memory: 2048
net0: name=eth0,bridge=vmbr1,gw=10.5.0.254,hwaddr=BC:24:11:BF:BD:74,ip=10.5.0.6/24,type=veth
onboot: 1
ostype: debian
rootfs: local-zfs:subvol-106-disk-0,size=50G
swap: 512
lxc.cgroup2.devices.allow: c 10:200 rwm
lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file
lxc.cap.drop:
lxc.apparmor.profile: unconfined

PBS fstab (/etc/fstab on PBS)

//100.105.26.130/pbs-backup /mnt/synology cifs credentials=/etc/pbs-smb.creds,uid=34,gid=34,vers=3.0,_netdev,x-systemd.automount,x-systemd.after=tailscaled.service,x-systemd.requires=tailscaled.service 0 0

PBS Systemd Dependencies

# /etc/systemd/system/proxmox-backup-proxy.service.d/wait-for-mount.conf
[Unit]
After=mnt-synology.mount tailscaled.service
Requires=mnt-synology.mount

# /etc/systemd/system/proxmox-backup.service.d/wait-for-mount.conf
[Unit]
After=mnt-synology.mount tailscaled.service
Requires=mnt-synology.mount

Synology NFS/CIFS Settings

  • Share: /volume1/pbs-backup
  • Protocol: CIFS (SMB 3.0)
  • Squash: Map all users to admin
  • Tailscale IP allowed: 100.115.85.120

Other PVE Nodes

pve01.warradejendomme.dk

  • Purpose: Friend's server (former job), needs backups
  • Backup namespace: pve01.warradejendomme.dk
  • PBS connection: Via Tailscale (100.115.85.120:8007)

pve02.warradejendomme.dk

  • Purpose: Friend's server (former job), needs backups
  • Backup namespace: pve02.warradejendomme.dk
  • PBS connection: Via Tailscale (100.115.85.120:8007)

Tailscale Network

Device Tailscale IP Notes
pbs-1 (PBS) 100.115.85.120 PBS container
nas01 (Synology) 100.105.26.130 Home NAS, backup target
tailscale-pve01 100.99.33.100 core's Tailscale LXC
pve01 100.99.118.54 Friend's server
pve02 100.82.87.108 Friend's server
dev 100.85.227.17
sentry 100.83.236.113
mge-t14 100.112.71.15
mikflix 100.84.253.6
xanderryzen 100.71.118.78
nvr01 100.118.17.103 Exit node
tailscalemg 100.115.101.65 Exit node

Tailscale config: SSH enabled on all devices where possible


DNS

External DNS

Provider: dns.services (Danish, free, has API for future automation)

Domains:

  • georgsen.dk
  • dataloes.dk
  • microsux.dk
  • warradejendomme.dk

Internal DNS (Technitium)

Internal DNS Records (lab.georgsen.dk):

Name IP
npm 10.5.0.1
dns 10.5.0.2
pbs 10.5.0.6
dockge 10.5.0.10
forgejo 10.5.0.14
mgmt 10.5.0.102

Home Infrastructure

Synology NAS (nas01)

  • Tailscale IP: 100.105.26.130
  • Purpose: Backup target, general NAS
  • PBS Share: /volume1/pbs-backup
  • Note: To be replaced in 2026 (noisy)

Future: Intel NUC Cluster (3 nodes)

Planned home PVE cluster:

Node RAM NVMe SATA SSD HDD
Node 1 16GB 500GB 512GB -
Node 2 16GB 500GB 512GB -
Node 3 16GB 2TB 512GB 5TB (CCTV)

User Conventions

Standard User Setup

When creating containers/VMs:

# Create group and user with UID/GID 1000
groupadd -g 1000 georgsen
useradd -u 1000 -g 1000 -m -s /bin/bash mikkel

# Passwordless sudo
apt install -y sudo
echo "mikkel ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/mikkel
chmod 440 /etc/sudoers.d/mikkel

# SSH key
mkdir -p /root/.ssh /home/mikkel/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIOQrK06zVkfY6C1ec69kEZYjf8tC98icCcBju4V751i mikkel@georgsen.dk" | tee /root/.ssh/authorized_keys /home/mikkel/.ssh/authorized_keys
chmod 700 /root/.ssh /home/mikkel/.ssh
chmod 600 /root/.ssh/authorized_keys /home/mikkel/.ssh/authorized_keys
chown -R mikkel:georgsen /home/mikkel/.ssh

Projects

Sentry (Defense Intelligence)

Custom system monitoring military contracting news for business opportunities.

  • Focus: Ground equipment (NOT aircraft/naval)
  • Services: EV conversion, diesel upgrades, specialty vehicles, bomb loaders, Humvee engine upgrades

JukeBox

Custom music player: https://github.com/mikl0s/JukeBox

Sense Vendor Locator

CBD retailer locator for Denmark (sense.microsux.dk)

dataloes.dk

Personal company website


Preferences

  • Coding: Python, Batch
  • UI Style: 256-color terminal retro aesthetic
  • Development: Ask clarifying questions, prefer understanding over workarounds
  • Tools: Claude Code for development projects

Maintenance Notes

Cleanup Tasks

  1. Remove orphaned iptables rules (Coolify is gone):

    iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 6001 -j DNAT --to-destination 10.5.0.1:6001
    iptables -t nat -D PREROUTING -i vmbr0 -p tcp --dport 6002 -j DNAT --to-destination 10.5.0.1:6002
    netfilter-persistent save
    
  2. Containers to evaluate:

    • 110 (sense.microsux.dk) - Consider consolidating
    • 112 (dataloes) - Stopped
    • 113 (general) - Decomissioned, can remove
  3. DHCP vs Static IPs:

    • Containers .112 and .113 have static IPs inside DHCP range (100-200)
    • Consider moving static assignments to .2-.99 range

Quick Reference

Service URLs

Service URL
PVE (core) https://65.108.14.165:8006
PBS https://pbs.georgsen.dk or https://10.5.0.6:8007
NPM Admin http://10.5.0.1:81
Dockge https://dockge.georgsen.dk
DNS Admin https://dns.georgsen.dk or http://10.5.0.2:5380
Forgejo https://git.georgsen.dk or http://10.5.0.14:3000
Status https://status.georgsen.dk
Webmail https://webmail.georgsen.dk
JukeBox https://jukebox.georgsen.dk

Important IPs

Resource IP
core public 65.108.14.165
mail public 65.108.14.164
NPM 10.5.0.1
DNS 10.5.0.2
PBS 10.5.0.6
Dockge 10.5.0.10
Forgejo 10.5.0.14
Synology (Tailscale) 100.105.26.130
PBS (Tailscale) 100.115.85.120

PBS Credentials

  • Web UI: root@pam
  • API Token: root@pam!pve
  • Fingerprint: f6:5d:3f:63:0e:15:38:10:38:7a:33:82:3a:c0:b0:59:98:a7:04:7d:8d:ed:64:7d:fc:85:ab:8f:87:a4:48:eb

PVE API (from mgmt container)

  • Token: root@pam!mgmt
  • Config: ~/.config/pve/credentials
  • Helper: ~/bin/pve (list, status, start, stop, create-ct)

NPM API (from mgmt container)

  • Config: ~/repos/nginx-proxy-manager-Bash-API/npm-api.conf
  • Helper: ~/bin/npm-api (--host-list, --host-create, --host-delete, --cert-list)

DNS API (from mgmt container)

  • Config: ~/.config/dns/credentials
  • Helper: ~/bin/dns (list, records, add, delete, lookup)
  • Default zone: lab.georgsen.dk

Last updated: 2026-01-14