7.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
This repository manages Docker Compose configurations for the Agap self-hosted home server. It is not a software project — it is infrastructure-as-config for several independent services.
Services
| Directory | Service | Port | Notes |
|---|---|---|---|
immich-app/ |
Immich (photo management) | 2283 | Main compose via root docker-compose.yml |
gitea/ |
Gitea (git hosting) + Postgres | 3000, 222 | Standalone compose |
openai/ |
Open WebUI + Ollama (AI chat) | 3125 | Requires NVIDIA GPU |
Common Commands
All services use Docker Compose. From each service directory:
# Start a service
docker compose up -d
# Restart
docker compose restart
# View logs
docker compose logs -f
# Pull latest images
docker compose pull
The root docker-compose.yml is an alias that includes immich-app/docker-compose.yml.
Immich-specific
Environment variables are in the root .env file (referenced by immich-app/docker-compose.yml as ../.env):
UPLOAD_LOCATION,THUMB_LOCATION,ENCODED_VIDEO_LOCATION— media storage pathsDB_DATA_LOCATION— Postgres data directory
Restore from backup (see immich-app/restore_example.sh):
docker compose down -v # destroys all data
docker compose create
docker start immich_postgres
sleep 10
gunzip --stdout "/home/alvis/dump.sql.gz" | \
sed "s/SELECT pg_catalog.set_config('search_path', '', false);/SELECT pg_catalog.set_config('search_path', 'public, pg_catalog', true);/g" | \
docker exec -i immich_postgres psql --dbname=postgres --username=postgres
docker compose up -d
GPU / NVIDIA Setup
Before running GPU-dependent services (Open WebUI/Ollama, Immich ML with CUDA):
- Run
sudo ./nvidia-docker-install.sh— installs Docker + NVIDIA Container Toolkit - Run
./install-cuda.sh— installs CUDA toolkit (toolkit only, not driver)
Storage Layout
| Path | Purpose |
|---|---|
/mnt/media/upload |
Immich uploaded originals |
/mnt/ssd1/media/thumbs |
Immich thumbnails |
/mnt/ssd1/media/encoded-video |
Immich transcoded video |
/mnt/ssd1/media/postgres |
Immich Postgres data |
/mnt/misc/gitea |
Gitea data |
Gitea Integration
When changes are made to infrastructure (services, config, setup), update the relevant Gitea wiki pages at http://localhost:3000/alvis/AgapHost/wiki.
Gitea Instance Details
- URL:
http://localhost:3000 - Repo:
alvis/AgapHost - Wiki:
http://localhost:3000/alvis/AgapHost/wiki - API token: Read from
$GITEA_TOKENenvironment variable — never hardcode it
Wiki Pages Reference
| Page | Topic |
|---|---|
| Hello | Overview of Agap — services, stack |
| Home | Index — links to all pages |
| Network | Netplan bridge setup, Caddy reverse proxy |
| Storage | LVM setup and commands |
| Home-Assistant | KVM-based Home Assistant setup |
| 3X-UI | VPN proxy panel |
| Gitea | Git hosting Docker service |
Read Wiki Pages (API)
# List all pages
curl -s -H "Authorization: token $GITEA_TOKEN" \
http://localhost:3000/api/v1/repos/alvis/AgapHost/wiki/pages
# Read a page (content is base64 in content_base64 field)
curl -s -H "Authorization: token $GITEA_TOKEN" \
http://localhost:3000/api/v1/repos/alvis/AgapHost/wiki/page/Home
Edit Wiki Pages (Git)
The Gitea REST API does not expose wiki write endpoints. Use git directly:
# Clone the wiki repo
git clone http://alvis:$GITEA_TOKEN@localhost:3000/alvis/AgapHost.wiki.git /tmp/AgapHost.wiki
# Edit files, then commit and push
cd /tmp/AgapHost.wiki
git config user.email "allogn@gmail.com"
git config user.name "alvis"
git add <files>
git commit -m "<message>"
git push http://alvis:$GITEA_TOKEN@localhost:3000/alvis/AgapHost.wiki.git main
Wiki Style Guidelines
- Use minimalistic style: clean headings, code blocks, brief descriptions
- Remove outdated or redundant content when updating
- Create a new page if a topic doesn't exist yet
- Wiki files are Markdown, named
<PageTitle>.md
Home Assistant API
Instance: https://haos.alogins.net
Token: Read from $HA_TOKEN environment variable — never hardcode it
Base URL: https://haos.alogins.net/api/
Auth header: Authorization: Bearer <token>
Common Endpoints
# Health check
curl -s -H "Authorization: Bearer $HA_TOKEN" \
https://haos.alogins.net/api/
# Get all entity states
curl -s -H "Authorization: Bearer $HA_TOKEN" \
https://haos.alogins.net/api/states
# Get specific entity
curl -s -H "Authorization: Bearer $HA_TOKEN" \
https://haos.alogins.net/api/states/<entity_id>
# Call service (e.g., turn on light)
curl -s -X POST \
-H "Authorization: Bearer $HA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"entity_id":"light.example"}' \
https://haos.alogins.net/api/services/<domain>/<service>
Note: Status 401 = token invalid/expired
HA → Zabbix Alerting
Home Assistant automations push alerts to Zabbix via history.push API (Zabbix 7.4 trapper items). No middleware needed.
Architecture
[HA sensor ON] → [HA automation] → [rest_command: HTTP POST] → [Zabbix history.push] → [trapper item] → [trigger] → [Telegram]
Water Leak Sensors
3x HOBEIAN ZG-222Z moisture sensors → Disaster-level Zabbix alert with room name.
| HA Entity | Room |
|---|---|
binary_sensor.hobeian_zg_222z |
Kitchen |
binary_sensor.hobeian_zg_222z_2 |
Bathroom |
binary_sensor.hobeian_zg_222z_3 |
Laundry |
Zabbix side (host "HA Agap", hostid 10780):
- Trapper item:
water.leak(text type) — receives room name or "ok" - Trigger:
last(/HA Agap/water.leak)<>"ok"— Disaster (severity 5), manual close - Trigger name uses
{ITEM.LASTVALUE}to show room in notification
HA side (configuration.yaml):
rest_command.zabbix_water_leak— POST to Zabbixhistory.push, accepts{{ room }}template variablerest_command.zabbix_water_leak_clear— pushes "ok" to clear- Automation "Water Leak Alert" — any sensor ON → sends room name to Zabbix
- Automation "Water Leak Clear" — all sensors OFF → sends "ok"
Adding a New HA → Zabbix Alert
- Zabbix: Create trapper item (type 2) on "HA Agap" via
item.createAPI. Create trigger viatrigger.create. - HA config: Add
rest_commandentry inconfiguration.yamlwithhistory.pushpayload. Restart HA. - HA automation: Create via
POST /api/config/automation/config/<id>with trigger on sensor state and action calling the rest_command. - Test: Call
rest_commandvia HA API, verify Zabbix problem appears.
Zabbix API
Instance: http://localhost:81 (local), https://zb.alogins.net (external)
Endpoint: http://localhost:81/api_jsonrpc.php
Token: Read from $ZABBIX_TOKEN environment variable — never hardcode it
Auth header: Authorization: Bearer <token>
Common Requests
# Check API version
curl -s -X POST http://localhost:81/api_jsonrpc.php \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ZABBIX_TOKEN" \
-d '{"jsonrpc":"2.0","method":"apiinfo.version","params":{},"id":1}'
# Get all hosts
curl -s -X POST http://localhost:81/api_jsonrpc.php \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ZABBIX_TOKEN" \
-d '{"jsonrpc":"2.0","method":"host.get","params":{"output":"extend"},"id":1}'
# Get problems/issues
curl -s -X POST http://localhost:81/api_jsonrpc.php \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ZABBIX_TOKEN" \
-d '{"jsonrpc":"2.0","method":"problem.get","params":{"output":"extend"},"id":1}'