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>
This commit is contained in:
Mikkel Georgsen 2026-01-14 12:38:45 +00:00
commit a6bf1c7706
3 changed files with 687 additions and 0 deletions

97
CLAUDE.md Normal file
View file

@ -0,0 +1,97 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Purpose
This is the management container (VMID 102) for Mikkel's homelab infrastructure. Claude Code operates here to assist with homelab management, automation, and maintenance tasks.
## Environment
- **Container:** LXC on Proxmox VE (core.georgsen.dk)
- **Network Access:** vmbr1 (10.5.0.0/24 internal), Tailscale
- **SSH Keys:** Pre-installed for accessing other containers/VMs
- **User:** mikkel (UID 1000, group georgsen GID 1000)
- **Python venv:** ~/venv (activate with `source ~/venv/bin/activate`)
- **Helper scripts:** ~/bin (pve, npm-api, dns)
- **Git repos:** ~/repos
## Living Documentation
**`homelab-documentation.md`** is the authoritative reference for all infrastructure details. This file must be kept current:
- Update when infrastructure changes are made
- Update when new services/containers are added
- Update when configurations change
- Update IP addresses, ports, and service mappings as they evolve
## Network Topology
```
Internet ─► vmbr0 (65.108.14.165) ─► NPM (10.5.0.1) ─► Internal services
├─ vmbr1: 10.5.0.0/24
└─ vmbr2: 10.9.1.0/24 (Hetzner vSwitch)
Tailscale mesh connects: PBS, Synology NAS, pve01, pve02, dev containers
```
## Key Infrastructure
| Service | IP | Access |
|---------|-----|--------|
| NPM (reverse proxy) | 10.5.0.1 | Admin :81 |
| DNS (Technitium) | 10.5.0.2 | :5380 or dns.georgsen.dk |
| PBS (backups) | 10.5.0.6 | :8007 or pbs.georgsen.dk |
| Dockge (docker mgmt) | 10.5.0.10 | :5001 |
| Forgejo (git) | 10.5.0.14 | :3000 or git.georgsen.dk |
| Tailscale relay | 10.5.0.x | Routes to 10.9.0.0/16 |
## PVE API Access
The `~/bin/pve` helper script provides API access to Proxmox:
```bash
~/bin/pve list # List all VMs/containers
~/bin/pve status <vmid> # Show status
~/bin/pve start <vmid> # Start VM/container
~/bin/pve stop <vmid> # Stop VM/container
~/bin/pve create-ct <vmid> <hostname> <ip> <disk_gb> # Create container
```
## NPM API Access
The `~/bin/npm-api` script manages Nginx Proxy Manager:
```bash
~/bin/npm-api --host-list # List proxy hosts
~/bin/npm-api --host-search <domain> # Search by domain
~/bin/npm-api --host-create <domain> -i <ip> -p <port> # Create proxy host
~/bin/npm-api --host-delete <id> # Delete proxy host
~/bin/npm-api --cert-list # List SSL certs
```
Note: SSL cert generation requires manual setup via web UI (http://10.5.0.1:81)
## DNS API Access
The `~/bin/dns` script manages Technitium DNS (internal zone: lab.georgsen.dk):
```bash
~/bin/dns list # List all zones
~/bin/dns records [zone] # List records in zone
~/bin/dns add <name> <ip> [zone] # Add A record (e.g., dns add myhost 10.5.0.50)
~/bin/dns delete <name> [zone] # Delete A record
~/bin/dns lookup <name> # Query DNS
```
## Common SSH Targets
```bash
ssh root@10.5.0.1 # NPM
ssh root@10.5.0.2 # DNS
ssh root@10.5.0.6 # PBS
ssh root@10.5.0.10 # Dockge
ssh root@10.5.0.14 # Forgejo
ssh mikkel@10.5.0.111 # dev container
```
## User Preferences
- Python and Batch for scripting
- 256-color terminal retro aesthetic for UIs
- Ask clarifying questions rather than making assumptions
- Prefer understanding root causes over workarounds

28
README.md Normal file
View file

@ -0,0 +1,28 @@
# Homelab
Infrastructure documentation and management for Mikkel's homelab.
## Files
- **homelab-documentation.md** - Complete infrastructure documentation
- **CLAUDE.md** - Claude Code guidance and quick reference
## Management Container
This repository is managed from the mgmt container (VMID 102) on core.georgsen.dk.
Helper scripts available:
- `~/bin/pve` - Proxmox VE API
- `~/bin/npm-api` - Nginx Proxy Manager API
- `~/bin/dns` - Technitium DNS API
## Quick Links
| Service | URL |
|---------|-----|
| Proxmox | https://65.108.14.165:8006 |
| Forgejo | https://git.georgsen.dk |
| DNS Admin | https://dns.georgsen.dk |
| NPM Admin | http://10.5.0.1:81 |
| Dockge | https://dockge.georgsen.dk |
| PBS | https://pbs.georgsen.dk |

562
homelab-documentation.md Normal file
View file

@ -0,0 +1,562 @@
# 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:**
```yaml
# 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
- **Purpose:** Custom music player
- **Source:** https://github.com/mikl0s/JukeBox
- **Port:** 4000
#### 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)
- **Server:** 10.5.0.2
- **Web UI:** https://dns.georgsen.dk or http://10.5.0.2:5380
- **API:** http://10.5.0.2:5380/api/
- **Internal zone:** lab.georgsen.dk
- **Upstream:** Cloudflare (1.1.1.1), Google (8.8.8.8), Quad9 (9.9.9.9)
**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:
```bash
# 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):
```bash
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*