From 3eccd6deee92d62d4f92dc283b7b6af1229e88a0 Mon Sep 17 00:00:00 2001 From: Spencer Grimes Date: Sun, 8 Mar 2026 13:36:26 -0500 Subject: [PATCH] "vault backup: 2026-03-08 13:36:25 from Flow" --- .../.claude/settings.local.json | 3 +- 21-Server Reference/network.md | 4 - 21-Server Reference/stacks/README.md | 2 + 21-Server Reference/stacks/calibre.md | 74 +++++++++ 21-Server Reference/stacks/gitea.md | 85 ++++++++++ 21-Server Reference/stacks/gluetun.md | 60 +++++++ 21-Server Reference/stacks/homepage.md | 65 ++++++++ 21-Server Reference/stacks/linkwarden.md | 75 +++++++++ 21-Server Reference/stacks/matrix.md | 150 ++++++++++++++++++ 21-Server Reference/stacks/mealie.md | 63 ++++++++ 21-Server Reference/stacks/melodix.md | 58 +++++++ 21-Server Reference/stacks/n8n.md | 60 +++++++ 21-Server Reference/stacks/openproject.md | 62 ++++++++ 13 files changed, 756 insertions(+), 5 deletions(-) create mode 100644 21-Server Reference/stacks/calibre.md create mode 100644 21-Server Reference/stacks/gitea.md create mode 100644 21-Server Reference/stacks/gluetun.md create mode 100644 21-Server Reference/stacks/homepage.md create mode 100644 21-Server Reference/stacks/linkwarden.md create mode 100644 21-Server Reference/stacks/matrix.md create mode 100644 21-Server Reference/stacks/mealie.md create mode 100644 21-Server Reference/stacks/melodix.md create mode 100644 21-Server Reference/stacks/n8n.md create mode 100644 21-Server Reference/stacks/openproject.md diff --git a/21-Server Reference/.claude/settings.local.json b/21-Server Reference/.claude/settings.local.json index 90158af..9928e1b 100644 --- a/21-Server Reference/.claude/settings.local.json +++ b/21-Server Reference/.claude/settings.local.json @@ -3,7 +3,8 @@ "allow": [ "Bash(ssh homelab:*)", "WebFetch(domain:dockhand.pro)", - "Bash(curl:*)" + "Bash(curl:*)", + "Bash(do:*)" ] } } diff --git a/21-Server Reference/network.md b/21-Server Reference/network.md index f63af13..5970f5e 100644 --- a/21-Server Reference/network.md +++ b/21-Server Reference/network.md @@ -66,10 +66,6 @@ Each major service registers itself as a separate Tailscale node via the sidecar | `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 diff --git a/21-Server Reference/stacks/README.md b/21-Server Reference/stacks/README.md index 15cb51e..0f7b6c8 100644 --- a/21-Server Reference/stacks/README.md +++ b/21-Server Reference/stacks/README.md @@ -37,3 +37,5 @@ The following named volumes exist but are not attached to any running container - `portainer_data` - `open-project_open_project_tailscale_state` - `openproject_openproject_tailscale_state` (from an older `openproject` stack iteration) + +> Orphaned networks (`blight_default`, old `openproject_default`) have been pruned. diff --git a/21-Server Reference/stacks/calibre.md b/21-Server Reference/stacks/calibre.md new file mode 100644 index 0000000..e34e585 --- /dev/null +++ b/21-Server Reference/stacks/calibre.md @@ -0,0 +1,74 @@ +# Calibre + +Self-hosted e-book library manager (Calibre desktop server). + +**Status: STOPPED** — The main `calibre` container is in `Created` state and the Tailscale sidecar exited with code 128. This stack is not currently running. + +## Access (when running) +- **Tailscale:** [calibre.bunny-wyvern.ts.net](https://calibre.bunny-wyvern.ts.net) +- Web UI port: `8080` (mapped to host `8088`) +- Content server port: `8081` (mapped to host `8089`) + +## Containers + +| Container | Image | Status | +|---|---|---| +| `calibre` | `lscr.io/linuxserver/calibre:latest` | Created (never started) | +| `calibre-tailscale-sidecar` | `tailscale/tailscale` (pinned image) | Exited (128) ~3 weeks ago | + +> The Tailscale sidecar is running a pinned image hash (`sha256:1a2e759f...`) rather than `latest`. This may be why it failed — the image may be outdated or incompatible. + +## Compose File +**Path:** `/home/artanis/DockerFiles/Calibre/docker-compose.yaml` + +```yaml +services: + calibre: + image: lscr.io/linuxserver/calibre:latest + container_name: calibre + pull_policy: always + restart: unless-stopped + ports: + - "8088:8080" + - "8089:8081" + - "8181:8181" + volumes: + - /home/artanis/DockerFiles/Calibre/server-config:/config + - /home/artanis/DockerFiles/Calibre/books:/books + environment: + PUID: 1000 + PGID: 1000 + TZ: America/Chicago + + calibre-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: calibre-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - calibre_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=calibre + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:calibre" + +volumes: + calibre_tailscale_state: + +# calibre-web service is commented out in compose +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/home/artanis/DockerFiles/Calibre/server-config` | Calibre server configuration | +| `/home/artanis/DockerFiles/Calibre/books` | E-book library files | + +## Notes +- A `calibre-web` service (separate lightweight web UI) is fully defined in the compose file but commented out +- To restart this stack, the Tailscale sidecar image may need to be re-pulled (`pull_policy: always` is set on calibre but not the sidecar) diff --git a/21-Server Reference/stacks/gitea.md b/21-Server Reference/stacks/gitea.md new file mode 100644 index 0000000..c0b9353 --- /dev/null +++ b/21-Server Reference/stacks/gitea.md @@ -0,0 +1,85 @@ +# Gitea + +Self-hosted Git service (GitHub alternative). + +## Access +- **Tailscale:** [gitea.bunny-wyvern.ts.net](https://gitea.bunny-wyvern.ts.net) +- **LAN Web:** `http://192.168.2.114:3000` +- **LAN SSH:** `ssh://192.168.2.114:2222` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `gitea` | `gitea/gitea:latest` | Web app + Git server | +| `gitea_db` | `mysql:8` | MySQL database | +| `gitea-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/gitea/docker-compose.yml` + +```yaml +services: + gitea: + image: gitea/gitea:latest + container_name: gitea + restart: unless-stopped + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__database__DB_TYPE=mysql + - GITEA__database__HOST=db:3306 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD= + volumes: + - /home/artanis/DockerFiles/gitea/gitea_data:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "2222:2222" + + db: + image: mysql:8 + container_name: gitea_db + restart: unless-stopped + environment: + - MYSQL_ROOT_PASSWORD= + - MYSQL_DATABASE=gitea + - MYSQL_USER=gitea + - MYSQL_PASSWORD= + volumes: + - /home/artanis/DockerFiles/gitea/gitea_db_data:/var/lib/mysql + + gitea-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: gitea-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - gitea_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=gitea + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:gitea" + +volumes: + gitea_tailscale_state: +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/home/artanis/DockerFiles/gitea/gitea_data` | Gitea repos, config, attachments | +| `/home/artanis/DockerFiles/gitea/gitea_db_data` | MySQL data directory | + +## Notes +- Database: MySQL 8 (separate container `gitea_db`) +- Port 2222 is exposed for SSH-based Git operations (clone/push via `ssh://`) +- Timezone files from the host are mounted read-only to keep Gitea's timestamps consistent diff --git a/21-Server Reference/stacks/gluetun.md b/21-Server Reference/stacks/gluetun.md new file mode 100644 index 0000000..ce65af1 --- /dev/null +++ b/21-Server Reference/stacks/gluetun.md @@ -0,0 +1,60 @@ +# Gluetun (VPN Gateway) + +VPN gateway container using Mullvad via WireGuard. Acts as a network proxy for other containers or clients that need to route traffic through the VPN. + +## Access +- **HTTP Control Server:** `http://192.168.2.114:8001` (Gluetun management API) +- **HTTP Proxy:** `http://192.168.2.114:8888` +- **Shadowsocks:** `192.168.2.114:8388` (TCP + UDP) + +## Containers + +| Container | Image | Role | +|---|---|---| +| `gluetun` | `qmcgaw/gluetun:v3` | VPN gateway | + +No Tailscale sidecar — this stack is accessed directly on the LAN. + +## Compose File +**Path:** `/home/artanis/DockerFiles/gluetun-qbittorent/docker-compose.yaml` + +```yaml +services: + gluetun: + image: qmcgaw/gluetun:v3 + container_name: gluetun + restart: unless-stopped + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun:/dev/net/tun + ports: + - 8001:8000/tcp # HTTP Control Server + - 8888:8888/tcp # HTTP proxy + - 8388:8388/tcp # Shadowsocks + - 8388:8388/udp # Shadowsocks + volumes: + - /home/artanis/DockerFiles/ArrSuite/gluetun:/gluetun + environment: + - VPN_SERVICE_PROVIDER=mullvad + - VPN_TYPE=wireguard + - HTTPPROXY=on + - WIREGUARD_PRIVATE_KEY= + - WIREGUARD_ADDRESSES=10.74.136.96/32 + - TZ=UTC-06 + - SERVER_COUNTRIES=Canada,USA + - DNS_ADDRESS=192.168.2.112 + - HTTP_CONTROL_SERVER_ADDRESS=:8000 + - FIREWALL_OUTBOUND_SUBNETS=192.168.2.0/24 + - UPDATER_PERIOD=24h +``` + +## Notes +- **VPN Provider:** Mullvad, WireGuard protocol +- **VPN IP:** `10.74.136.96/32` (assigned Mullvad address) +- **Server regions:** Canada and USA +- **DNS:** Routes DNS through `192.168.2.112` (likely the LAN Pihole) +- `FIREWALL_OUTBOUND_SUBNETS=192.168.2.0/24` allows containers using Gluetun as their network to still reach the local LAN +- `UPDATER_PERIOD=24h` — Gluetun automatically refreshes its Mullvad server list every 24 hours +- The stack name is `gluetun-qbittorent`, suggesting qBittorrent was originally planned to run behind this VPN. The qBittorrent service is not currently deployed (only Gluetun is running) +- Config data is bind-mounted to `/home/artanis/DockerFiles/ArrSuite/gluetun` (note: `ArrSuite` directory, suggesting future *arr apps may be planned) diff --git a/21-Server Reference/stacks/homepage.md b/21-Server Reference/stacks/homepage.md new file mode 100644 index 0000000..7edd7d7 --- /dev/null +++ b/21-Server Reference/stacks/homepage.md @@ -0,0 +1,65 @@ +# Homepage + +Self-hosted dashboard (gethomepage.dev) for quick access to all services. + +## Access +- **Tailscale:** [homepage.bunny-wyvern.ts.net](https://homepage.bunny-wyvern.ts.net) +- **LAN:** `http://192.168.2.114:35000` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `homepage` | `ghcr.io/gethomepage/homepage:latest` | Dashboard web app | +| `homepage-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/homepage/docker-compose.yml` + +```yaml +services: + homepage: + image: ghcr.io/gethomepage/homepage:latest + container_name: homepage + restart: unless-stopped + pull_policy: always + ports: + - 35000:3000 + volumes: + - /home/artanis/DockerFiles/homepage/config:/app/config + - /home/artanis/DockerFiles/homepage/images:/app/public/images + - /var/run/docker.sock:/var/run/docker.sock + environment: + HOMEPAGE_ALLOWED_HOSTS: 192.168.2.114:35000,homelab:35000,100.72.0.62:35000,homepage.bunny-wyvern.ts.net + + homepage-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: homepage-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - homepage_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=homepage + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:homepage" + +volumes: + homepage_tailscale_state: +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/home/artanis/DockerFiles/homepage/config` | YAML config files (services, widgets, settings) | +| `/home/artanis/DockerFiles/homepage/images` | Custom images for the dashboard | + +## Notes +- `HOMEPAGE_ALLOWED_HOSTS` must include all hostnames/IPs from which the dashboard will be accessed — required by Homepage as a CSRF protection measure +- The Docker socket is mounted to enable Homepage's Docker integration (live container status widgets) +- `pull_policy: always` ensures the latest image is pulled on every stack restart diff --git a/21-Server Reference/stacks/linkwarden.md b/21-Server Reference/stacks/linkwarden.md new file mode 100644 index 0000000..2b81f25 --- /dev/null +++ b/21-Server Reference/stacks/linkwarden.md @@ -0,0 +1,75 @@ +# Linkwarden + +Self-hosted bookmark manager with link archiving. + +## Access +- **Tailscale:** [linkwarden.bunny-wyvern.ts.net](https://linkwarden.bunny-wyvern.ts.net) +- **LAN:** `http://192.168.2.114:5001` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `linkwarden` | `ghcr.io/linkwarden/linkwarden:latest` | Web app | +| `linkwarden-db` | `postgres:16-alpine` | PostgreSQL database | +| `linkwarden-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/linkwarden/docker-compose.yml` + +```yaml +services: + postgres: + image: postgres:16-alpine + container_name: linkwarden-db + restart: always + pull_policy: always + volumes: + - /home/artanis/DockerFiles/linkwarden/pgdata:/var/lib/postgresql/data + + linkwarden: + container_name: linkwarden + image: ghcr.io/linkwarden/linkwarden:latest + restart: always + pull_policy: always + ports: + - 5001:3000 + volumes: + - /home/artanis/DockerFiles/linkwarden/data:/data/data + environment: + - DATABASE_URL=postgresql://postgres:@postgres:5432/postgres + - NEXTAUTH_URL=https://linkwarden.bunny-wyvern.ts.net/api/v1/auth + - NEXTAUTH_SECRET= + depends_on: + - postgres + + linkwarden-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: linkwarden-tailscale-sidecar + restart: unless-stopped + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - linkwarden_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=linkwarden + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:linkwarden" + +volumes: + linkwarden_tailscale_state: +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/home/artanis/DockerFiles/linkwarden/pgdata` | PostgreSQL data directory | +| `/home/artanis/DockerFiles/linkwarden/data` | Linkwarden app data (archived pages, assets) | + +## Notes +- `NEXTAUTH_URL` must point to the Tailscale URL for auth to work correctly +- A Meilisearch service was previously considered (commented out in compose) but not deployed diff --git a/21-Server Reference/stacks/matrix.md b/21-Server Reference/stacks/matrix.md new file mode 100644 index 0000000..d5cce7e --- /dev/null +++ b/21-Server Reference/stacks/matrix.md @@ -0,0 +1,150 @@ +# Matrix + +Self-hosted Matrix homeserver (Synapse) with multiple messaging bridges. + +## Access +- **Tailscale:** `matrix.bunny-wyvern.ts.net` (Synapse homeserver) + +## Containers + +| Container | Image | Role | +|---|---|---| +| `synapse` | `matrixdotorg/synapse:latest` | Matrix homeserver | +| `matrix-db` | `postgres:16-alpine` | PostgreSQL database | +| `matrix-tailscale` | `tailscale/tailscale:latest` | Tailscale node (shares synapse network) | +| `mautrix-whatsapp` | `dock.mau.dev/mautrix/whatsapp:latest` | WhatsApp bridge | +| `mautrix-gmessages` | `dock.mau.dev/mautrix/gmessages:latest` | Google Messages bridge | +| `mautrix-slack` | `dock.mau.dev/mautrix/slack:latest` | Slack bridge | +| `mautrix-discord` | `dock.mau.dev/mautrix/discord:latest` | Discord bridge | +| `matrix-relay` | `matrix-matrix-relay` (local build) | Custom relay service | + +## Network Architecture + +All containers (except the Tailscale sidecar) communicate over a shared internal bridge network `matrix_matrix-internal` (`172.25.0.0/16`). No ports are exposed directly to the host — all external access goes through Tailscale on the `synapse` container. + +| Container | Internal IP | +|---|---| +| `synapse` | `172.25.0.2` | +| `mautrix-discord` | `172.25.0.3` | +| `mautrix-whatsapp` | `172.25.0.4` | +| `mautrix-gmessages` | `172.25.0.5` | +| `matrix-db` | `172.25.0.6` | +| `matrix-relay` | `172.25.0.7` | +| `mautrix-slack` | `172.25.0.8` | + +## Compose File +**Path:** `/home/artanis/DockerFiles/Matrix/matrix/compose.yaml` + +```yaml +services: + matrix-tailscale: + image: tailscale/tailscale:latest + container_name: matrix-tailscale + restart: unless-stopped + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - matrix_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=matrix + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:synapse" + + matrix-db: + image: postgres:16-alpine + container_name: matrix-db + restart: unless-stopped + environment: + POSTGRES_USER: synapse + POSTGRES_PASSWORD: + POSTGRES_DB: synapse + volumes: + - /home/artanis/DockerFiles/Matrix/postgresdata:/var/lib/postgresql/data + networks: + - matrix-internal + + synapse: + image: matrixdotorg/synapse:latest + container_name: synapse + restart: unless-stopped + depends_on: + - matrix-db + volumes: + - /home/artanis/DockerFiles/Matrix/synapsedata:/data + networks: + - matrix-internal + + mautrix-whatsapp: + image: dock.mau.dev/mautrix/whatsapp:latest + container_name: mautrix-whatsapp + restart: unless-stopped + volumes: + - /home/artanis/DockerFiles/Matrix/whatsappdata:/data + networks: + - matrix-internal + + mautrix-gmessages: + image: dock.mau.dev/mautrix/gmessages:latest + container_name: mautrix-gmessages + restart: unless-stopped + volumes: + - /home/artanis/DockerFiles/Matrix/gmessagesdata:/data + networks: + - matrix-internal + + mautrix-slack: + image: dock.mau.dev/mautrix/slack:latest + container_name: mautrix-slack + restart: unless-stopped + volumes: + - /home/artanis/DockerFiles/Matrix/slackdata:/data + networks: + - matrix-internal + + mautrix-discord: + image: dock.mau.dev/mautrix/discord:latest + container_name: mautrix-discord + restart: unless-stopped + volumes: + - /home/artanis/DockerFiles/Matrix/discorddata:/data + networks: + - matrix-internal + depends_on: + - matrix-db + - synapse + + matrix-relay: + build: + context: ../ + dockerfile: matrix_relay.Dockerfile + container_name: matrix-relay + restart: unless-stopped + networks: + - matrix-internal + +networks: + matrix-internal: + driver: bridge + +volumes: + matrix_tailscale_state: +``` + +## Data Layout + +| Path | Contents | +|---|---| +| `/home/artanis/DockerFiles/Matrix/postgresdata` | PostgreSQL data | +| `/home/artanis/DockerFiles/Matrix/synapsedata` | Synapse config, media store | +| `/home/artanis/DockerFiles/Matrix/whatsappdata` | WhatsApp bridge config/state | +| `/home/artanis/DockerFiles/Matrix/gmessagesdata` | Google Messages bridge config/state | +| `/home/artanis/DockerFiles/Matrix/slackdata` | Slack bridge config/state | +| `/home/artanis/DockerFiles/Matrix/discorddata` | Discord bridge config/state | + +## Notes +- The `matrix-relay` container is built from a local `matrix_relay.Dockerfile` located one directory up from the compose file (`/home/artanis/DockerFiles/Matrix/`) +- Synapse does not expose any ports to the host — it is only reachable via the `matrix_matrix-internal` network and through Tailscale +- The Tailscale sidecar attaches to `synapse`'s network namespace, so Synapse's internal ports (8008, 8448) become accessible at `matrix.bunny-wyvern.ts.net` diff --git a/21-Server Reference/stacks/mealie.md b/21-Server Reference/stacks/mealie.md new file mode 100644 index 0000000..4599b2c --- /dev/null +++ b/21-Server Reference/stacks/mealie.md @@ -0,0 +1,63 @@ +# Mealie + +Self-hosted recipe manager and meal planner. + +## Access +- **Tailscale:** [mealie.bunny-wyvern.ts.net](https://mealie.bunny-wyvern.ts.net) + +## Containers + +| Container | Image | Role | +|---|---|---| +| `mealie` | `ghcr.io/mealie-recipes/mealie:latest` | Web app | +| `mealie-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/Mealie/docker-compose.yaml` + +```yaml +services: + mealie: + image: ghcr.io/mealie-recipes/mealie:latest + container_name: mealie + restart: always + deploy: + resources: + limits: + memory: 1000M + volumes: + - /home/artanis/DockerFiles/Mealie/data:/app/data/ + environment: + ALLOW_SIGNUP: "false" + PUID: 1000 + PGID: 1000 + TZ: America/Chicago + SECURITY_MAX_LOGIN_ATTEMPTS: 5 + SECURITY_USER_LOCKOUT_TIME: 1 + BASE_URL: https://mealie.bunny-wyvern.ts.net/ + + mealie-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: mealie-tailscale-sidecar + restart: unless-stopped + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - mealie_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=mealie + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:mealie" + +volumes: + mealie_tailscale_state: +``` + +## Notes +- Public signup is disabled — accounts must be created by an admin +- Memory capped at 1 GB +- Data is bind-mounted to `/home/artanis/DockerFiles/Mealie/data` +- OpenAI/LLM integration was previously attempted (commented out in compose) — it was disabled because it was too resource-intensive and caused crashes diff --git a/21-Server Reference/stacks/melodix.md b/21-Server Reference/stacks/melodix.md new file mode 100644 index 0000000..c6b91ab --- /dev/null +++ b/21-Server Reference/stacks/melodix.md @@ -0,0 +1,58 @@ +# Melodix + +Discord music bot. Plays audio in Discord voice channels. + +## Access +Internal only — no web UI, no exposed ports. Controlled via Discord commands. + +## Containers + +| Container | Image | Role | +|---|---|---| +| `melodix` | `melodix-image` (local build) | Discord bot | + +No Tailscale sidecar. The bot connects outbound to Discord's API. + +## Compose File +**Path:** `/home/artanis/DockerFiles/melodix/melodix/docker/docker-compose.yml` + +```yaml +services: + melodix: + container_name: melodix + restart: always + image: '${ALIAS}-image' + volumes: + - ./data/datastore.json:/usr/project/datastore.json + - ./data/cache:/usr/project/cache + environment: + - DISCORD_TOKEN=${DISCORD_TOKEN} + - ENCODE_VOLUME=${ENCODE_VOLUME} + - ENCODE_CHANNELS=${ENCODE_CHANNELS} + - ENCODE_FRAME_RATE=${ENCODE_FRAME_RATE} + - ENCODE_FRAME_DURATION=${ENCODE_FRAME_DURATION} + - ENCODE_BITRATE=${ENCODE_BITRATE} + - ENCODE_COMPRESSION_LEVEL=${ENCODE_COMPRESSION_LEVEL} + - ENCODE_PACKET_LOSS=${ENCODE_PACKET_LOSS} + - ENCODE_BUFFERED_FRAMES=${ENCODE_BUFFERED_FRAMES} + - ENCODE_VBR=${ENCODE_VBR} + - ENCODE_VOLUME_FLOAT=${ENCODE_VOLUME_FLOAT} + - ENCODE_RECONNECT_AT_EOF=${ENCODE_RECONNECT_AT_EOF} + - ENCODE_RECONNECT_STREAMED=${ENCODE_RECONNECT_STREAMED} + - ENCODE_RECONNECT_ON_NETWORK_ERROR=${ENCODE_RECONNECT_ON_NETWORK_ERROR} + - ENCODE_RECONNECT_ON_HTTP_ERROR=${ENCODE_RECONNECT_ON_HTTP_ERROR} + - ENCODE_RECONNECT_DELAY_MAX=${ENCODE_RECONNECT_DELAY_MAX} + - ENCODE_FFMPEG_BINARY_PATH=${ENCODE_FFMPEG_BINARY_PATH} + - ENCODE_ENCODING_LINE_LOG=${ENCODE_ENCODING_LINE_LOG} + - ENCODE_USER_AGENT=${ENCODE_USER_AGENT} + - ENCODE_RAW_OUTPUT=${ENCODE_RAW_OUTPUT} + entrypoint: /usr/project/app +``` + +## Notes +- The image is built locally (`melodix-image`) — the build context and Dockerfile are in the parent directory of the compose file +- All configuration comes from the `.env` file at `/home/artanis/DockerFiles/melodix/melodix/docker/.env` +- `DISCORD_TOKEN` is the bot's Discord API token (in `.env`, redacted here) +- The `ENCODE_*` variables control FFmpeg audio encoding settings for the voice stream +- Data is stored via **relative bind mounts** (`./data/`) relative to the compose file directory — so at `/home/artanis/DockerFiles/melodix/melodix/docker/data/` +- Dockhand shows this stack under the name `docker` (the stack name is derived from the compose working directory name) diff --git a/21-Server Reference/stacks/n8n.md b/21-Server Reference/stacks/n8n.md new file mode 100644 index 0000000..3df8cf8 --- /dev/null +++ b/21-Server Reference/stacks/n8n.md @@ -0,0 +1,60 @@ +# n8n + +Self-hosted workflow automation platform (similar to Zapier/Make). + +## Access +- **Tailscale:** [n8n.bunny-wyvern.ts.net](https://n8n.bunny-wyvern.ts.net) +- **LAN:** `http://192.168.2.114:5678` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `n8n` | `docker.n8n.io/n8nio/n8n` | Web app + workflow engine | +| `n8n-tailscale-sidecar` | `tailscale/tailscale:latest` | Tailscale node | + +## Compose File +**Path:** `/home/artanis/DockerFiles/n8n/docker-compose.yml` + +```yaml +volumes: + n8n_storage: + n8n_tailscale_state: + +services: + n8n: + image: docker.n8n.io/n8nio/n8n + restart: always + pull_policy: always + container_name: n8n + environment: + - DB_TYPE=sqlite + - N8N_RUNNERS_ENABLED=true + - N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME} + ports: + - 5678:5678 + volumes: + - n8n_storage:/home/node/.n8n + + n8n-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: n8n-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - n8n_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=n8n + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:n8n" +``` + +## Notes +- Database: SQLite (stored in the `n8n_storage` named volume) +- `N8N_HOST` and `DOMAIN_NAME` are set via `.env` file at `/home/artanis/DockerFiles/n8n/.env` +- `N8N_RUNNERS_ENABLED=true` enables the task runner mode for better workflow execution performance +- `N8N_SECURE_COOKIE` is commented out — HTTPS is handled by Tailscale so cookies are secure by default diff --git a/21-Server Reference/stacks/openproject.md b/21-Server Reference/stacks/openproject.md new file mode 100644 index 0000000..cd5c16e --- /dev/null +++ b/21-Server Reference/stacks/openproject.md @@ -0,0 +1,62 @@ +# OpenProject + +Self-hosted project management tool (tasks, timelines, wikis). + +## Access +- **Tailscale:** [openproject.bunny-wyvern.ts.net](https://openproject.bunny-wyvern.ts.net) +- **LAN:** `http://192.168.2.114:5010` + +## Containers + +| Container | Image | Role | +|---|---|---| +| `openproject` | `openproject/openproject:17` (pinned hash) | Web app (all-in-one) | +| `openproject-tailscale-sidecar` | `tailscale/tailscale` (pinned hash) | Tailscale node | + +> Both containers are running pinned image hashes rather than tags. This means they will not auto-update until the compose file is updated with a new image reference. + +## Compose File +**Path:** `/home/artanis/DockerFiles/openproject/docker-compose.yaml` + +```yaml +services: + openproject: + image: openproject/openproject:17 + container_name: openproject + restart: always + ports: + - "5010:80" + environment: + - SECRET_KEY_BASE= + - OPENPROJECT_HOST__NAME=openproject.bunny-wyvern.ts.net + - OPENPROJECT_HTTPS=true + - OPENPROJECT_DEFAULT__LANGUAGE=en + stdin_open: true + tty: true + + openproject-tailscale-sidecar: + image: tailscale/tailscale:latest + container_name: openproject-tailscale-sidecar + restart: always + cap_add: + - NET_ADMIN + devices: + - /dev/net/tun + volumes: + - openproject_tailscale_state:/var/lib/tailscale + environment: + - TS_AUTHKEY= + - TS_HOSTNAME=openproject + - TS_STATE_DIR=/var/lib/tailscale + network_mode: "service:openproject" + +volumes: + openproject_tailscale_state: +``` + +## Notes +- Uses the **all-in-one** OpenProject image (includes database, worker, web server in a single container) +- Version pinned to `17` +- `OPENPROJECT_HTTPS=true` tells OpenProject it is behind HTTPS (needed for correct URL generation even though TLS is terminated by Tailscale, not OpenProject itself) +- Data is stored in two **anonymous volumes** (auto-generated hashes) — this means data is not trivially accessible on the host filesystem. Use `docker volume inspect` or the Dockhand volume browser to locate them +- There are orphaned volumes from earlier OpenProject stack iterations: `open-project_open_project_tailscale_state`, `open-project_openproject_tailscale_state`, and `openproject_openproject_tailscale_state`