doc: konsolidierte Homelab-Dokumentation + Original-Plan
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
# homelab — aufbau-anleitung
|
||||
|
||||
Schritt-für-Schritt nach dem Manifest. Reihenfolge ist bewusst: erst Fundament (Pools, Datasets), dann Netzgerüst (Caddy/WireGuard/DNS), dann Apps. Domains und IPs hier als Platzhalter (`deinedomain.ch`, `10.0.0.x`) — anpassen.
|
||||
|
||||
---
|
||||
|
||||
## 1 — proxmox & rpool
|
||||
|
||||
Proxmox-Installer von USB. Bei der Disk-Auswahl die NVMe nehmen, Filesystem **zfs (RAID0)** (= Single-Disk ZFS), `ashift=12`, compression `lz4`. Das wird dein `rpool`.
|
||||
|
||||
Nach dem ersten Boot: Enterprise-Repo raus, No-Subscription-Repo rein, updaten.
|
||||
|
||||
```bash
|
||||
zpool status # rpool sollte ONLINE sein
|
||||
zfs set atime=off rpool
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2 — tank (mirror) anlegen
|
||||
|
||||
Disk-IDs holen (nie /dev/sdX verwenden — die wandern):
|
||||
|
||||
```bash
|
||||
ls -l /dev/disk/by-id/ | grep -i ata # die zwei 4TB-Platten identifizieren
|
||||
|
||||
zpool create -o ashift=12 \
|
||||
-O compression=lz4 -O atime=off -O xattr=sa \
|
||||
tank mirror /dev/disk/by-id/PLATTE1 /dev/disk/by-id/PLATTE2
|
||||
|
||||
zpool status tank # mirror, beide ONLINE
|
||||
```
|
||||
|
||||
Monatlichen Scrub einrichten:
|
||||
|
||||
```bash
|
||||
echo '0 3 1 * * root /sbin/zpool scrub tank' > /etc/cron.d/zfs-scrub
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3 — datasets & quotas
|
||||
|
||||
```bash
|
||||
zfs create -o quota=1300G tank/business
|
||||
zfs create -o quota=300G tank/private
|
||||
zfs create -o quota=600G -o recordsize=1M tank/immich
|
||||
zfs create -o quota=150G tank/paperless
|
||||
zfs create -o quota=150G tank/nextcloud
|
||||
zfs create -o quota=150G tank/dump
|
||||
zfs create -o quota=50G tank/gitea
|
||||
|
||||
zfs list -o name,quota,used tank # kontrollieren
|
||||
```
|
||||
|
||||
`tank/dump` als Proxmox-Backup-Storage eintragen: Datacenter → Storage → Add → Directory, Pfad `/tank/dump`, Inhalt "VZDump backup file".
|
||||
|
||||
---
|
||||
|
||||
## 4 — LXC-muster & mountpoints
|
||||
|
||||
Pro Container: rootfs auf `rpool`, Bulk-Daten auf `tank`. Beispiel Nextcloud (CTID 110), exklusives Dataset → verwalteter Mountpoint:
|
||||
|
||||
```bash
|
||||
pct set 110 -mp0 tank/nextcloud,mp=/data,backup=0
|
||||
```
|
||||
|
||||
Fileserver (102) braucht die **geteilten** Datasets als Bind-Mount (mehrere Dienste im selben LXC):
|
||||
|
||||
```bash
|
||||
pct set 102 -mp0 /tank/business,mp=/srv/business
|
||||
pct set 102 -mp1 /tank/private,mp=/srv/private
|
||||
```
|
||||
|
||||
**Hinweis unprivilegierte LXC:** in-container UID wird um 100000 verschoben. Damit Schreiben klappt, dem Dataset die verschobene UID/GID geben, z.B. für in-container `1000`:
|
||||
|
||||
```bash
|
||||
chown -R 101000:101000 /tank/business /tank/private
|
||||
```
|
||||
|
||||
Tipp: alle drei Zugriffsdienste (Samba/Filebrowser/Syncthing) **im selben LXC 102** halten — dann gibt es keine container-übergreifenden UID-Probleme.
|
||||
|
||||
---
|
||||
|
||||
## 5 — fileserver: samba + filebrowser + syncthing (LXC 102)
|
||||
|
||||
Debian-LXC, dann:
|
||||
|
||||
**Samba** (zwei Shares):
|
||||
|
||||
```bash
|
||||
apt install -y samba
|
||||
groupadd buro; useradd -M -G buro karim; smbpasswd -a karim
|
||||
```
|
||||
|
||||
`/etc/samba/smb.conf` (Auszug):
|
||||
|
||||
```ini
|
||||
[business]
|
||||
path = /srv/business
|
||||
valid users = @buro
|
||||
read only = no
|
||||
force group = buro
|
||||
create mask = 0660
|
||||
directory mask = 0770
|
||||
|
||||
[private]
|
||||
path = /srv/private
|
||||
valid users = karim
|
||||
read only = no
|
||||
create mask = 0600
|
||||
directory mask = 0700
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl restart smbd
|
||||
```
|
||||
|
||||
Mounten am Mac: Finder → ⌘K → `smb://10.0.0.102/business`. Linux: `mount -t cifs //10.0.0.102/business /mnt/business -o user=karim`.
|
||||
|
||||
**Filebrowser** (Web + Share-Links), rooted über beide Shares:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/filebrowser/get/master/get.sh | bash
|
||||
filebrowser config init
|
||||
filebrowser config set --root /srv --address 0.0.0.0 --port 8080
|
||||
filebrowser users add karim DEINPASSWORT --perm.admin
|
||||
```
|
||||
|
||||
Als systemd-Service einrichten (Unit anlegen, enable). Caddy proxyt später `files.deinedomain.ch` → `10.0.0.102:8080`.
|
||||
|
||||
**Syncthing** (das "Drive"): `apt install syncthing`, als User-Service starten, Web-UI auf `:8384`, Ordner `/srv/business` (oder gezielte Unterordner) freigeben und auf dem Laptop verbinden. Da Syncthing plain files schreibt, bleibt SMB parallel nutzbar.
|
||||
|
||||
---
|
||||
|
||||
## 6 — ordnerstruktur anlegen
|
||||
|
||||
```bash
|
||||
# business
|
||||
mkdir -p /srv/business/{_vorlagen,_buro,_bibliothek/{details,cad-blocks,materialien,referenzen},projekte}
|
||||
mkdir -p /srv/business/projekte/2026-001_beispiel/{00_admin,01_grundlagen,02_vorstudien,03_vorprojekt,04_bauprojekt,05_bewilligung,06_ausschreibung,07_ausfuhrung,08_abschluss,cad,plaene,visualisierung,fotos}
|
||||
|
||||
# private
|
||||
mkdir -p /srv/private/{dokumente/2026,finanzen,studium,projekte,scans,archiv}
|
||||
|
||||
chown -R 101000:101000 /srv/business /srv/private
|
||||
```
|
||||
|
||||
Für neue Projekte das `2026-001_beispiel`-Gerüst als Vorlage kopieren (oder ein kleines Skript in `_vorlagen/` ablegen).
|
||||
|
||||
---
|
||||
|
||||
## 7 — caddy (LXC 100)
|
||||
|
||||
`apt install caddy`, dann `/etc/caddy/Caddyfile`:
|
||||
|
||||
```
|
||||
files.deinedomain.ch { reverse_proxy 10.0.0.102:8080 }
|
||||
cloud.deinedomain.ch { reverse_proxy 10.0.0.110:80 }
|
||||
fotos.deinedomain.ch { reverse_proxy 10.0.0.111:2283 }
|
||||
www.deinedomain.ch { root * /srv/www; file_server }
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl reload caddy
|
||||
```
|
||||
|
||||
Caddy holt TLS automatisch. Am Router nur 80/443 auf Caddy forwarden.
|
||||
|
||||
---
|
||||
|
||||
## 8 — wireguard (LXC 101, wg-easy)
|
||||
|
||||
Docker im LXC, wg-easy gibt dir eine GUI für Peers:
|
||||
|
||||
```bash
|
||||
docker run -d --name wg-easy --cap-add NET_ADMIN --cap-add SYS_MODULE \
|
||||
-e WG_HOST=vpn.deinedomain.ch -e PASSWORD_HASH='...' \
|
||||
-p 51820:51820/udp -p 51821:51821/tcp \
|
||||
-v ~/.wg-easy:/etc/wireguard --restart unless-stopped \
|
||||
ghcr.io/wg-easy/wg-easy
|
||||
```
|
||||
|
||||
Am Router **nur** UDP 51820 forwarden. Peers in der UI anlegen, QR scannen. Im Tunnel erreichst du das interne Subnetz → alle privaten Dienste, ohne sie je öffentlich zu machen.
|
||||
|
||||
---
|
||||
|
||||
## 9 — adguard home (LXC 103)
|
||||
|
||||
Installieren, als DNS im Router (oder im WireGuard-Profil) setzen. Interne A-Records anlegen, damit `cloud.deinedomain.ch` etc. intern auf die LXC-IPs zeigen → gleiche Hostnamen drinnen wie draussen.
|
||||
|
||||
---
|
||||
|
||||
## 10 — app-stacks (NC, immich, paperless)
|
||||
|
||||
Pro Stack ein Docker-LXC, compose-File ins Gitea. Muster für **Nextcloud** (110):
|
||||
|
||||
- compose mit `app`, `db` (Postgres), `redis`. Volumes für App/DB auf rootfs (NVMe).
|
||||
- Daten-Volume auf das gemountete `/data` (= `tank/nextcloud`).
|
||||
- Caddy proxyt `cloud.deinedomain.ch`.
|
||||
|
||||
**Immich** (111) und **Paperless-ngx** (113) analog — offizielle compose-Files nehmen (ändern sich regelmässig, drum upstream statt hier einfrieren) und nur den Daten-Pfad auf das jeweilige `tank/...`-Mount zeigen. Paperless' Consume-Ordner auf `/srv/private/scans` zeigen lassen → Scans landen automatisch im Archiv.
|
||||
|
||||
---
|
||||
|
||||
## 11 — monitoring
|
||||
|
||||
- **Uptime Kuma** (140): jeden Dienst als HTTP-Check anlegen, Push aufs Handy (ntfy/Telegram).
|
||||
- **Beszel** (141): Agent auf dem Proxmox-Host, Pool-Auslastung im Blick.
|
||||
- **Pool-Alert <85%** als simpler Cron:
|
||||
|
||||
```bash
|
||||
cat > /etc/cron.hourly/zfs-capacity << 'EOF'
|
||||
#!/bin/bash
|
||||
cap=$(zpool list -H -o capacity tank | tr -d '%')
|
||||
[ "$cap" -ge 85 ] && echo "tank $cap%" | ntfy publish homelab
|
||||
EOF
|
||||
chmod +x /etc/cron.hourly/zfs-capacity
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12 — backup (sanoid + restic)
|
||||
|
||||
**Snapshots** (sanoid) — `/etc/sanoid/sanoid.conf`:
|
||||
|
||||
```ini
|
||||
[tank/business]
|
||||
use_template = prod
|
||||
[tank/private]
|
||||
use_template = prod
|
||||
[tank/immich]
|
||||
use_template = prod
|
||||
|
||||
[template_prod]
|
||||
hourly = 24
|
||||
daily = 30
|
||||
monthly = 6
|
||||
autosnap = yes
|
||||
autoprune = yes
|
||||
```
|
||||
|
||||
**Offsite** zur Hetzner Storage Box (Restic über SFTP):
|
||||
|
||||
```bash
|
||||
export RESTIC_REPOSITORY="sftp:uXXXXX@uXXXXX.your-storagebox.de:/backup"
|
||||
export RESTIC_PASSWORD_FILE=/root/.restic-pw
|
||||
restic init
|
||||
restic backup /tank/business /tank/private /tank/nextcloud /tank/immich /tank/paperless /tank/gitea
|
||||
restic forget --keep-daily 14 --keep-weekly 8 --keep-monthly 12 --prune
|
||||
```
|
||||
|
||||
In einen täglichen Cron packen.
|
||||
|
||||
**Restore-Test (Pflicht):** einmal `restic restore latest --target /tmp/restoretest --include /tank/private/dokumente` und prüfen ob die Files stimmen. Ein ungetestetes Backup ist kein Backup.
|
||||
|
||||
---
|
||||
|
||||
## reihenfolge auf einen blick
|
||||
|
||||
1. Proxmox + rpool → 2. tank Mirror + Scrub → 3. Datasets + Quotas → 4. Fileserver (Samba/Filebrowser/Syncthing) + Ordner → 5. Caddy + WireGuard + AdGuard → 6. Kern-Apps → 7. Monitoring → 8. Backup + Restore-Test → 9. Erweiterungen nach Lust.
|
||||
Reference in New Issue
Block a user