diff --git a/21-Server Reference/README.md b/21-Server Reference/README.md new file mode 100644 index 0000000..a2e4503 --- /dev/null +++ b/21-Server Reference/README.md @@ -0,0 +1,50 @@ +# Homelab Server Documentation + +Living documentation for the `homelab` server. Goal: a new admin with zero prior context should be able to read this and understand everything about the server. + +## Quick Reference + +| Property | Value | +|---|---| +| Hostname | `homelab` | +| LAN IP | `192.168.2.114` | +| Tailscale IP | `100.72.0.62` | +| OS | Ubuntu 25.10 (Questing Quokka) | +| Kernel | 6.17.0-14-generic | +| Docker Files | `/home/artanis/DockerFiles/` | +| Docker Manager | [dockhand.bunny-wyvern.ts.net](https://dockhand.bunny-wyvern.ts.net) | + +## Documentation Index + +- [[hardware]] — CPU, RAM, storage +- [[network]] — Interfaces, Tailscale, ports in use +- [[environments]] — Dockhand-managed environments (Homelab + Pihole) +- [[stacks/README]] — Overview of all Docker stacks + +### Stacks +| Stack | Purpose | Access | +|---|---|---| +| [[stacks/dockhand]] | Docker management UI | [dockhand.bunny-wyvern.ts.net](https://dockhand.bunny-wyvern.ts.net) | +| [[stacks/minecraft]] | Minecraft server (TerraFirmaGreg) | `:25565` | +| [[stacks/mealie]] | Recipe manager | [mealie.bunny-wyvern.ts.net](https://mealie.bunny-wyvern.ts.net) | +| [[stacks/linkwarden]] | Bookmark manager | [linkwarden.bunny-wyvern.ts.net](https://linkwarden.bunny-wyvern.ts.net) | +| [[stacks/gitea]] | Self-hosted Git | [gitea.bunny-wyvern.ts.net](https://gitea.bunny-wyvern.ts.net) | +| [[stacks/matrix]] | Matrix homeserver + bridges | [matrix.bunny-wyvern.ts.net](https://matrix.bunny-wyvern.ts.net) | +| [[stacks/homepage]] | Dashboard | [homepage.bunny-wyvern.ts.net](https://homepage.bunny-wyvern.ts.net) | +| [[stacks/n8n]] | Workflow automation | [n8n.bunny-wyvern.ts.net](https://n8n.bunny-wyvern.ts.net) | +| [[stacks/calibre]] | E-book library (STOPPED) | [calibre.bunny-wyvern.ts.net](https://calibre.bunny-wyvern.ts.net) | +| [[stacks/gluetun]] | VPN gateway (Mullvad) | `:8001` (control) | +| [[stacks/openproject]] | Project management | [openproject.bunny-wyvern.ts.net](https://openproject.bunny-wyvern.ts.net) | +| [[stacks/melodix]] | Discord music bot | Internal only | + +## Key Architectural Patterns + +### Tailscale Sidecar +Nearly every service uses a **Tailscale sidecar** pattern for remote access: +- A `tailscale/tailscale` container runs alongside the main service container +- It uses `network_mode: "service:[main]"` to share the main container's network namespace +- This registers the main service as a Tailscale node (e.g. `mealie.bunny-wyvern.ts.net`) +- Services are **not exposed to the public internet** — only accessible via Tailscale VPN + +### Credentials +Credentials (DB passwords, API keys, Tailscale auth keys) live in the compose files on disk at `/home/artanis/DockerFiles/`. They are redacted in this documentation. See individual stack files for variable names and the actual compose files for values. diff --git a/21-Server Reference/environments.md b/21-Server Reference/environments.md new file mode 100644 index 0000000..48b78af --- /dev/null +++ b/21-Server Reference/environments.md @@ -0,0 +1,38 @@ +# Dockhand Environments + +Dockhand manages two Docker environments. Select an environment with the `?env=[id]` query parameter in the API. + +## Environment 1 — Homelab + +| Property | Value | +|---|---| +| ID | `1` | +| Name | Homelab | +| Connection | Local Unix socket (`/var/run/docker.sock`) | +| Public IP | `192.168.2.114` | +| Timezone | America/Chicago | +| Auto-update checks | Enabled (auto-apply: off) | +| Image pruning | Enabled | +| Activity collection | Enabled | +| Metrics collection | Enabled | + +This is the primary server. All stacks documented in [[stacks/README]] run here. + +## Environment 2 — Pihole + +| Property | Value | +|---|---| +| ID | `2` | +| Name | Pihole | +| Connection | Hawser (remote agent) | +| Host | `100.89.172.56` (Tailscale) | +| Port | `2376` | +| Timezone | America/Chicago | +| Auto-update checks | Enabled (auto-apply: off) | +| Image pruning | Enabled | +| Activity collection | Enabled | +| Metrics collection | Enabled | + +A separate device running Pi-hole (network-wide ad blocker / DNS). Connected to Dockhand via the **Hawser** agent over Tailscale. Documentation for this environment is tracked separately. + +> **Note:** The Hawser agent on the Pihole was last seen as disconnected at the time of this writing — `hawserLastSeen: null`. Hawser may need to be restarted on that device. diff --git a/21-Server Reference/hardware.md b/21-Server Reference/hardware.md new file mode 100644 index 0000000..ba95d06 --- /dev/null +++ b/21-Server Reference/hardware.md @@ -0,0 +1,32 @@ +# Hardware + +## CPU +| Property | Value | +|---|---| +| Model | Intel Core i7-6700K | +| Base Clock | 4.00 GHz | +| Max Boost | 4.20 GHz | +| Cores / Threads | 4 cores / 8 threads | +| Socket | LGA1151 (single socket) | +| Architecture | Skylake | + +## Memory +| Property | Value | +|---|---| +| Total RAM | 32 GB | +| Swap | 8 GB | +| Typical Usage | ~16 GB used at idle with all containers running | + +## Storage + +| Device | Type | Size | Mount | Notes | +|---|---|---|---|---| +| `nvme0n1p2` | NVMe SSD | 931.5 GB | `/` (root) | Primary OS + Docker disk. ~149 GB used. | +| `sda1` | HDD | 298.1 GB | `/mnt/300GBHDD` | Secondary disk. Nearly empty (2.1 MB used). | +| `sdb`–`sde` | — | 0 B | — | Empty/unformatted slots (likely USB or unpopulated) | + +### Storage Layout Notes +- All Docker volumes live under `/var/lib/docker/volumes/` on the NVMe +- Bind-mounted compose data lives under `/home/artanis/DockerFiles/` on the NVMe +- Minecraft server data is at `/Minecraft_Server/` (root of NVMe) +- The 300 GB HDD at `/mnt/300GBHDD` is currently unused by any container diff --git a/21-Server Reference/network.md b/21-Server Reference/network.md new file mode 100644 index 0000000..f63af13 --- /dev/null +++ b/21-Server Reference/network.md @@ -0,0 +1,77 @@ +# Network + +## Physical / Host Interfaces + +| Interface | IP | Notes | +|---|---|---| +| `enp0s31f6` | `192.168.2.114/24` | Primary LAN NIC | +| `tailscale0` | `100.72.0.62/32` | Tailscale VPN interface | +| `lo` | `127.0.0.1` | Loopback | + +The server also has many `br-*` Docker bridge interfaces (172.x.x.x ranges) — one per Docker network. See the Docker Networks section below. + +## Tailscale + +The server is on the `bunny-wyvern.ts.net` Tailnet. Remote access to all services is done exclusively through Tailscale — no public port forwarding is configured. + +Each major service registers itself as a separate Tailscale node via the sidecar pattern (see [[README#Key Architectural Patterns]]). + +| Tailscale Hostname | Service | +|---|---| +| `dockhand.bunny-wyvern.ts.net` | Dockhand | +| `mealie.bunny-wyvern.ts.net` | Mealie | +| `linkwarden.bunny-wyvern.ts.net` | Linkwarden | +| `gitea.bunny-wyvern.ts.net` | Gitea | +| `matrix.bunny-wyvern.ts.net` | Matrix / Synapse | +| `homepage.bunny-wyvern.ts.net` | Homepage | +| `n8n.bunny-wyvern.ts.net` | n8n | +| `calibre.bunny-wyvern.ts.net` | Calibre (inactive) | +| `openproject.bunny-wyvern.ts.net` | OpenProject | + +## Host Ports In Use + +| Port | Protocol | Service | +|---|---|---| +| 22 | TCP | SSH (host) | +| 139, 445 | TCP | Samba | +| 631 | TCP | CUPS (printing) | +| 2222 | TCP | Gitea SSH | +| 3000 | TCP | Gitea web UI | +| 5001 | TCP | Linkwarden | +| 5010 | TCP | OpenProject | +| 5100 | TCP | Python process (unknown) | +| 5555 | TCP | Dockhand | +| 5678 | TCP | n8n | +| 8001 | TCP | Gluetun HTTP control server | +| 8388 | TCP/UDP | Gluetun Shadowsocks | +| 8888 | TCP | Gluetun HTTP proxy | +| 9170 | TCP | system-bridge | +| 25565 | TCP | Minecraft | +| 24454 | UDP | Minecraft voice chat | +| 35000 | TCP | Homepage | + +## Docker Networks + +| Network Name | Subnet | Connected Containers | +|---|---|---| +| `matrix_matrix-internal` | `172.25.0.0/16` | synapse, matrix-db, matrix-relay, mautrix-* | +| `dockhand_default` | `172.23.0.0/16` | dockhand | +| `docker_default` | `172.18.0.0/16` | melodix | +| `gitea_default` | `172.20.0.0/16` | gitea, gitea_db | +| `linkwarden_default` | `172.21.0.0/16` | linkwarden, linkwarden-db | +| `mealie_default` | `172.22.0.0/16` | mealie | +| `homepage_default` | `172.26.0.0/16` | homepage | +| `n8n_default` | `172.29.0.0/16` | n8n | +| `minecraft_server_default` | `172.24.0.0/16` | minecraft | +| `open-project_default` | `172.30.0.0/16` | openproject | +| `gluetun-qbittorent_default` | `172.19.0.0/16` | gluetun | +| `calibre_default` | `172.28.0.0/16` | (empty — calibre stopped) | +| `blight_default` | `172.27.0.0/16` | (empty — orphan from deleted stack) | +| `openproject_default` | `192.168.16.0/20` | (empty — orphan) | + +> **Note:** `blight_default` and `openproject_default` (192.168 subnet) appear to be orphaned networks from previously deleted stacks. Safe to prune if desired. + +## DNS + +- `127.0.0.53` — systemd-resolved (stub resolver) +- Gluetun is configured to use `192.168.2.112` as DNS (likely the Pihole on the LAN) diff --git a/21-Server Reference/stacks/README.md b/21-Server Reference/stacks/README.md new file mode 100644 index 0000000..15cb51e --- /dev/null +++ b/21-Server Reference/stacks/README.md @@ -0,0 +1,39 @@ +# Docker Stacks Overview + +All stacks run on [[../environments#Environment 1 — Homelab]]. Compose files live at `/home/artanis/DockerFiles/` unless noted otherwise. + +## Status Summary + +| Stack | Status | Containers | Tailscale Node | +|---|---|---|---| +| [[dockhand]] | Running | 2 | `dockhand.bunny-wyvern.ts.net` | +| [[minecraft]] | Running | 1 | None (LAN exposed) | +| [[mealie]] | Running | 2 | `mealie.bunny-wyvern.ts.net` | +| [[linkwarden]] | Running | 3 | `linkwarden.bunny-wyvern.ts.net` | +| [[gitea]] | Running | 3 | `gitea.bunny-wyvern.ts.net` | +| [[matrix]] | Running | 8 | `matrix.bunny-wyvern.ts.net` | +| [[homepage]] | Running | 2 | `homepage.bunny-wyvern.ts.net` | +| [[n8n]] | Running | 2 | `n8n.bunny-wyvern.ts.net` | +| [[calibre]] | **Stopped** | 2 | `calibre.bunny-wyvern.ts.net` | +| [[gluetun]] | Running | 1 | None | +| [[openproject]] | Running | 2 | `openproject.bunny-wyvern.ts.net` | +| [[melodix]] | Running | 1 | None | + +## Common Patterns + +### Tailscale Sidecar +Most stacks include a `tailscale/tailscale` sidecar that joins the Tailnet and makes the service accessible at `[name].bunny-wyvern.ts.net`. All sidecars share a single Tailscale auth key stored in the compose files. + +### Bind Mounts vs Named Volumes +- **Config/data that needs to be easily accessible** uses bind mounts into `/home/artanis/DockerFiles/[stack]/` +- **Tailscale state** always uses named volumes (e.g. `stack_tailscale_state`) so node registration persists across restarts +- **Dockhand vulnerability scanner caches** use named volumes (`dockhand-grype-db`, `dockhand-trivy-db`) + +### Orphaned Volumes +The following named volumes exist but are not attached to any running container — likely leftovers from deleted stacks: +- `moltis_moltis-data` +- `moltis_moltis-config` +- `moltis_moltis-tailscale-state` +- `portainer_data` +- `open-project_open_project_tailscale_state` +- `openproject_openproject_tailscale_state` (from an older `openproject` stack iteration) diff --git a/21-Server Reference/stacks/dockhand.md b/21-Server Reference/stacks/dockhand.md new file mode 100644 index 0000000..03285e9 --- /dev/null +++ b/21-Server Reference/stacks/dockhand.md @@ -0,0 +1,59 @@ +# Dockhand + +Docker management UI. Used to manage all containers on the server. Also the tool used to generate this documentation. + +## Access +- **Tailscale:** [dockhand.bunny-wyvern.ts.net](https://dockhand.bunny-wyvern.ts.net) +- **LAN:** `http://192.168.2.114:5555` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `dockhand` | `fnsys/dockhand:latest` | Main web UI | +| `dockhand-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/Dockhand/docker-compose.yaml` + +```yaml +services: + dockhand: + image: fnsys/dockhand:latest + container_name: dockhand + restart: unless-stopped + ports: + - 5555:3000 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /home/artanis/DockerFiles:/DockerFiles + - /Minecraft_Server/docker-compose.yaml:/DockerFiles/Minecraft_Server/docker-compose.yaml + - dockhand_data:/app/data + + dockhand-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: dockhand-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - dockhand_tailscale_state:/var/lib/tailscale + - /home/artanis/DockerFiles:/DockerFiles + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=dockhand + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:dockhand" + +volumes: + dockhand_data: + dockhand_tailscale_state: +``` + +## Notes +- The entire `/home/artanis/DockerFiles` directory is mounted into the container at `/DockerFiles`, giving Dockhand read/write access to all compose files +- The Minecraft compose file lives outside `DockerFiles` (`/Minecraft_Server/`) so it is explicitly bind-mounted in +- `dockhand_data` is the named volume for Dockhand's internal state (environments, settings, user accounts) +- Dockhand also manages vulnerability scanning with two cached databases: `dockhand-grype-db` and `dockhand-trivy-db` diff --git a/21-Server Reference/stacks/minecraft.md b/21-Server Reference/stacks/minecraft.md new file mode 100644 index 0000000..73a72cb --- /dev/null +++ b/21-Server Reference/stacks/minecraft.md @@ -0,0 +1,69 @@ +# Minecraft Server + +Self-hosted Minecraft server running the **TerraFirmaGreg: Modern** modpack. + +## Access +- **Host:** `192.168.2.114:25565` (LAN / Tailscale) +- **Voice Chat:** `192.168.2.114:24454/udp` + +No Tailscale sidecar — ports are exposed directly on the host. + +## Containers + +| Container | Image | Role | +|---|---|---| +| `minecraft` | `itzg/minecraft-server:latest` | Game server | + +## Compose File +**Path:** `/Minecraft_Server/docker-compose.yaml` + +> Note: This file lives outside the main `DockerFiles` directory. It is explicitly mounted into the Dockhand container so it can manage it. + +```yaml +services: + mc: + image: itzg/minecraft-server:latest + container_name: minecraft + mem_limit: 12g + tty: true + stdin_open: true + ports: + - 25565:25565 + - 24454:24454/udp # Voice Chat + volumes: + - /Minecraft_Server/Minecraft_Server/data:/data + - /Minecraft_Server/Minecraft_Server/modpacks:/modpacks:ro + - /Minecraft_Server/Minecraft_Server/downloads:/downloads + environment: + EULA: TRUE + TYPE: AUTO_CURSEFORGE + VERSION: 1.20.1 + CF_API_KEY: + CF_PAGE_URL: "https://www.curseforge.com/minecraft/modpacks/terrafirmagreg-modern/files/7665541" + CF_BASE_DIR: /data + INIT_MEMORY: 8G + MAX_MEMORY: 12G + ENABLE_AUTOPAUSE: true + MAX_TICK_TIME: -1 + AUTOPAUSE_TIMEOUT_INIT: 600 # 10 min before pausing on empty server (init) + AUTOPAUSE_TIMEOUT_EST: 1800 # 30 min before pausing (established) + ENABLE_ROLLING_LOGS: true + LOG_TIMESTAMP: true + MOTD: "Why does Pingle sound like Pringle. Does Sam own Pringles?" + restart: unless-stopped +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/Minecraft_Server/Minecraft_Server/data` | World saves, server config, plugins | +| `/Minecraft_Server/Minecraft_Server/modpacks` | Modpack files (read-only) | +| `/Minecraft_Server/Minecraft_Server/downloads` | CurseForge download cache | + +## Notes +- Uses `itzg/minecraft-server` with `AUTO_CURSEFORGE` type — it auto-downloads the modpack from CurseForge on startup if not already present +- Modpack: **TerraFirmaGreg: Modern** (MC 1.20.1), pinned to a specific file ID (`7665541`) +- Memory: 8 GB initial, 12 GB max (hard limit via `mem_limit: 12g`) +- **Auto-pause** is enabled — server pauses after 30 minutes with no players, resumes on connection +- `MAX_TICK_TIME: -1` disables the watchdog timer (prevents server shutdown if a tick takes too long, common with heavy modpacks)