diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..639d3d4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,88 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +This is a personal homelab running 21 Docker Compose stacks on a single Linux host. Each service lives in its own subdirectory with an independent `compose.yaml` (or `docker-compose.yaml`). There is no CI/CD, no Makefile, and no shared orchestration layer — everything is managed manually. + +## Common Commands + +All commands must be run from within the relevant service directory: + +```bash +# Start a stack (detached) +docker compose up -d + +# Stop a stack +docker compose down + +# Restart a single service within a stack +docker compose restart + +# Pull latest images and recreate +docker compose pull && docker compose up -d + +# View logs +docker compose logs -f [service] +``` + +## Architecture + +### Directory Layout + +Each service is self-contained in its own directory. The pattern is: +- `compose.yaml` or `docker-compose.yaml` — service definition +- `.env` — secrets/overrides (only Authentik and SparkFitness use this; most others embed values inline) +- `compose.env` — Komodo-specific env file loaded via `--env-file` + +### Storage + +Two storage tiers are used across all stacks: + +- `/docker//` — Local persistent data (databases, config, app state) +- `/nfs/media/` — NFS-mounted shared library for large binary data: + - `Movies/`, `Shows/`, `Musics/`, `Podcasts/` — consumed by Jellyfin, ARR stack, Navidrome + - `photo/library/` — Immich photo library + - `Books/Kavita Library/` — Kavita ebook collection + - `/nfs/torrent/` — qBittorrent download target (Radarr/Sonarr pick up from here) + +### Authentication + +**Authentik** (`authentik/`) is the central SSO/OIDC provider. Currently integrated with: +- **Paperless-NGX** — OIDC via `PAPERLESS_SOCIALACCOUNT_PROVIDERS` +- **Komodo** — OIDC via `KOMODO_OIDC_*` vars + +When adding OIDC to a new service, the Authentik provider/application must be configured separately in the Authentik admin UI, and the client ID/secret wired into the service's compose file. + +### Key Service Relationships + +- **ARR stack** (Sonarr → qBittorrent → Radarr/Bazarr → `/nfs/torrent`) feeds content into Jellyfin +- **Komodo** manages container lifecycle across the host; the `periphery` agent mounts `/var/run/docker.sock` +- **Immich** uses `pgvecto-rs` (not stock PostgreSQL) — image version pinning matters for DB compatibility +- **Paperless-NGX** depends on Gotenberg (PDF rendering) and Tika (content extraction) sidecar containers + +### Ports + +Services are exposed on `localhost:80xx` ports (see individual compose files). A reverse proxy (not in this repo) sits in front and handles TLS/domain routing. + +## Conventions + +### Commit Messages + +Follow the format used throughout git history: +``` +add: # new service or feature +fix: # corrections +remove: # deletions +``` + +### Environment Variables + +- `TZ: Asia/Ho_Chi_Minh` is set on all containers +- LinuxServer.io images use `PUID`/`PGID` for file permission mapping +- All credentials go inline in compose files — never use `.env` files for new stacks + +### Image Pinning + +Most services pin to a specific tag or `latest`. When upgrading images that have associated databases (Immich, Paperless-NGX, Gitea), check upstream migration notes before pulling. diff --git a/karakeep/compose.yaml b/karakeep/compose.yaml new file mode 100644 index 0000000..6406bb1 --- /dev/null +++ b/karakeep/compose.yaml @@ -0,0 +1,43 @@ +services: + web: + image: ghcr.io/karakeep-app/karakeep:release + container_name: karakeep + depends_on: + - chrome + - meilisearch + ports: + - "8026:3000" + environment: + TZ: Asia/Ho_Chi_Minh + NEXTAUTH_SECRET: "duy@karakeep1772003" + NEXTAUTH_URL: "https://karakeep.fireflylab.cc" + MEILI_ADDR: http://meilisearch:7700 + MEILI_MASTER_KEY: "duy@karakeep1772003" + BROWSER_WEB_URL: http://chrome:9222 + DATA_DIR: /data + # OPENAI_API_KEY: ... + volumes: + - /docker/karakeep/data:/data + restart: unless-stopped + + chrome: + image: gcr.io/zenika-hub/alpine-chrome:124 + container_name: karakeep-chrome + command: + - --no-sandbox + - --disable-gpu + - --disable-dev-shm-usage + - --remote-debugging-address=0.0.0.0 + - --remote-debugging-port=9222 + - --hide-scrollbars + restart: unless-stopped + + meilisearch: + image: getmeili/meilisearch:v1.41.0 + container_name: karakeep-meilisearch + environment: + MEILI_MASTER_KEY: "duy@karakeep1772003" + MEILI_NO_ANALYTICS: "true" + volumes: + - /docker/karakeep/meilisearch:/meili_data + restart: unless-stopped diff --git a/nginx-proxy-manager/compose.yaml b/nginx-proxy-manager/compose.yaml new file mode 100644 index 0000000..e4ed3fc --- /dev/null +++ b/nginx-proxy-manager/compose.yaml @@ -0,0 +1,14 @@ +services: + npm: + image: jc21/nginx-proxy-manager:latest + container_name: nginx-proxy-manager + ports: + - "80:80" + - "443:443" + - "8028:81" + environment: + TZ: Asia/Ho_Chi_Minh + volumes: + - /docker/nginx-proxy-manager/data:/data + - /docker/nginx-proxy-manager/letsencrypt:/etc/letsencrypt + restart: unless-stopped diff --git a/pihole/compose.yaml b/pihole/compose.yaml new file mode 100644 index 0000000..1b7bc07 --- /dev/null +++ b/pihole/compose.yaml @@ -0,0 +1,17 @@ +services: + pihole: + image: pihole/pihole:latest + container_name: pihole + ports: + - "53:53/tcp" + - "53:53/udp" + - "8026:80/tcp" + environment: + TZ: Asia/Ho_Chi_Minh + FTLCONF_webserver_api_password: "changeme" + FTLCONF_dns_listeningMode: ALL + volumes: + - /docker/pihole/etc-pihole:/etc/pihole + cap_add: + - SYS_NICE + restart: unless-stopped