diff --git a/.env b/.env index 030063b..3aed925 100644 --- a/.env +++ b/.env @@ -5,10 +5,12 @@ # You can find documentation for all the supported env variables at https://docs.immich.app/install/environment-variables # The location where your uploaded files are stored -UPLOAD_LOCATION=/mnt/data/media/upload +UPLOAD_LOCATION=/mnt/media/upload +THUMB_LOCATION=/mnt/ssd1/media/thumbs +ENCODED_VIDEO_LOCATION=/mnt/ssd1/media/encoded-video # The location where your database files are stored. Network shares are not supported for the database -DB_DATA_LOCATION=/mnt/data/media/postgres +DB_DATA_LOCATION=/mnt/ssd1/media/postgres # To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List # TZ=Etc/UTC diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..efe08f8 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,127 @@ +# 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: + +```bash +# 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 paths +- `DB_DATA_LOCATION` — Postgres data directory + +**Restore from backup** (see `immich-app/restore_example.sh`): +```bash +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): + +1. Run `sudo ./nvidia-docker-install.sh` — installs Docker + NVIDIA Container Toolkit +2. 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_TOKEN` environment 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) + +```bash +# 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: + +```bash +# 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 +git commit -m "" +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 `.md` diff --git a/README.md b/README.md index e69de29..d2703ee 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,60 @@ +# Agap Home Server + +Docker Compose configurations for the Agap self-hosted home server infrastructure. + +## Services + +- **Immich** (`immich-app/`) — Photo management and backup (port 2283) +- **Gitea** (`gitea/`) — Self-hosted Git server with web UI (port 3000, SSH 222) +- **Open WebUI** (`openai/`) — AI chat interface with Ollama, GPU-accelerated (port 3125) + +## Quick Start + +### Start Immich (main service) + +```bash +docker compose up -d +``` + +### Start Gitea (from gitea/ directory) + +```bash +cd gitea +docker compose up -d +``` + +### Start Open WebUI (from openai/ directory) + +```bash +cd openai +docker compose up -d +``` + +## Configuration + +Environment variables are in the root `.env` file for Immich: +- `UPLOAD_LOCATION` — where photo originals are stored +- `THUMB_LOCATION` — thumbnail cache directory +- `ENCODED_VIDEO_LOCATION` — transcoded video cache +- `DB_DATA_LOCATION` — Postgres database directory +- `DB_PASSWORD` — Postgres password + +## Storage + +Media is stored on: +- `/mnt/media/upload` — Immich originals +- `/mnt/ssd1/media/` — Immich thumbnails, encoded video, and Postgres database +- `/mnt/misc/gitea` — Gitea repositories and data + +## GPU Support + +For GPU acceleration (Open WebUI/Ollama, Immich ML): + +1. Install NVIDIA Docker runtime: `sudo ./nvidia-docker-install.sh` +2. Install CUDA toolkit: `./install-cuda.sh` + +## Documentation + +See [CLAUDE.md](./CLAUDE.md) for detailed developer instructions and Gitea wiki integration guidelines. + +See the [Gitea wiki](http://localhost:3000/alvis/AgapHost/wiki) for infrastructure documentation (storage, network, services setup). diff --git a/docker-compose.yaml b/docker-compose.yaml deleted file mode 100644 index 0d11650..0000000 --- a/docker-compose.yaml +++ /dev/null @@ -1,2 +0,0 @@ -include: - - path: ./immich-app/docker-compose.yaml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c7122e1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,3 @@ +include: + - path: ./immich-app/docker-compose.yml + diff --git a/gitea/docker-compose.yml b/gitea/docker-compose.yml new file mode 100644 index 0000000..4f4f962 --- /dev/null +++ b/gitea/docker-compose.yml @@ -0,0 +1,43 @@ +version: "3" + +networks: + gitea: + external: false + +services: + server: + image: docker.gitea.com/gitea:1.25.3 + container_name: gitea + environment: + - USER_UID=1001 + - USER_GID=1001 + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=db:5432 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD=gitea + restart: always + networks: + - gitea + volumes: + - /home/git/.ssh/:/data/git/.ssh + - /mnt/misc/gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "222:22" + depends_on: + - db + + db: + image: docker.io/library/postgres:14 + restart: always + environment: + - POSTGRES_USER=gitea + - POSTGRES_PASSWORD=gitea + - POSTGRES_DB=gitea + networks: + - gitea + volumes: + - ./postgres:/var/lib/postgresql/data diff --git a/immich-app/docker-compose.yml b/immich-app/docker-compose.yml index e4e0f96..af4ac79 100644 --- a/immich-app/docker-compose.yml +++ b/immich-app/docker-compose.yml @@ -19,9 +19,11 @@ services: volumes: # Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file - ${UPLOAD_LOCATION}:/data + - ${THUMB_LOCATION}:/data/thumbs + - ${ENCODED_VIDEO_LOCATION}:/data/encoded-video - /etc/localtime:/etc/localtime:ro env_file: - - .env + - ../.env ports: - '2283:2283' depends_on: @@ -42,7 +44,7 @@ services: volumes: - model-cache:/cache env_file: - - .env + - ../.env restart: always healthcheck: disable: false diff --git a/immich-app/immich-go b/immich-app/immich-go deleted file mode 100755 index 1ef2d9b..0000000 Binary files a/immich-app/immich-go and /dev/null differ diff --git a/immich-app/restore_example.sh b/immich-app/restore_example.sh new file mode 100755 index 0000000..897cfd0 --- /dev/null +++ b/immich-app/restore_example.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +docker compose down -v # CAUTION! Deletes all Immich data to start from scratch +## Uncomment the next line and replace DB_DATA_LOCATION with your Postgres path to permanently reset the Postgres database +# rm -rf DB_DATA_LOCATION # CAUTION! Deletes all Immich data to start from scratch +docker compose pull # Update to latest version of Immich (if desired) +docker compose create # Create Docker containers for Immich apps without running them +docker start immich_postgres # Start Postgres server +sleep 10 # Wait for Postgres server to start up +# Check the database user if you deviated from the default +# Replace with the database username - usually postgres unless you have changed it. +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 # Restore Backup +docker compose up -d # Start remainder of Immich apps diff --git a/install-cuda.sh b/install-cuda.sh new file mode 100755 index 0000000..39e4a0a --- /dev/null +++ b/install-cuda.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +# Remove old CUDA GPG key if present +sudo apt-key del 7fa2af80 2>/dev/null || true + +# Install prerequisites +sudo apt-get update +sudo apt-get install -y gcc g++ make dkms + +# Add NVIDIA CUDA repository (Ubuntu 22.04/24.04) +DISTRO=$(lsb_release -rs | tr -d '.') # e.g., 2204 or 2404 +ARCH=$(uname -m) # x86_64 or aarch64 + +# Download and install the CUDA keyring package +wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu${DISTRO}/${ARCH}/cuda-keyring_1.1-1_all.deb +sudo dpkg -i cuda-keyring_1.1-1_all.deb +rm cuda-keyring_1.1-1_all.deb + +# Update and install the latest CUDA toolkit +sudo apt-get update +sudo apt-get install -y cuda-toolkit # toolkit only (no driver) +# OR install everything including the driver: +# sudo apt-get install -y cuda + +# Add CUDA to PATH and LD_LIBRARY_PATH +CUDA_PATH="/usr/local/cuda" +echo "" >> ~/.bashrc +echo "# CUDA" >> ~/.bashrc +echo "export PATH=${CUDA_PATH}/bin:\$PATH" >> ~/.bashrc +echo "export LD_LIBRARY_PATH=${CUDA_PATH}/lib64:\$LD_LIBRARY_PATH" >> ~/.bashrc +source ~/.bashrc + +echo "CUDA installed successfully!" +nvcc --version diff --git a/nvidia-docker-install.sh b/nvidia-docker-install.sh new file mode 100755 index 0000000..172ba2d --- /dev/null +++ b/nvidia-docker-install.sh @@ -0,0 +1,99 @@ +#!/bin/bash +set -euo pipefail + +# ============================================================================= +# NVIDIA Container Toolkit + Docker Installation Script +# Enables GPU-accelerated Docker containers +# Tested on Ubuntu 20.04/22.04/24.04, Debian 11/12 +# ============================================================================= + +RED=$'\033[0;31m' +GREEN=$'\033[0;32m' +YELLOW=$'\033[1;33m' +NC=$'\033[0m' + +log() { echo -e "${GREEN}[INFO]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; } + +# --- Pre-flight checks ------------------------------------------------------- +[[ $EUID -ne 0 ]] && error "Please run as root or with sudo." + +log "Checking for NVIDIA GPU..." +if ! lspci | grep -qi nvidia; then + error "No NVIDIA GPU detected. Aborting." +fi + +log "Checking for NVIDIA driver..." +if ! nvidia-smi &>/dev/null; then + warn "NVIDIA driver not found. Attempting to install recommended driver..." + apt-get update -qq + apt-get install -y ubuntu-drivers-common + ubuntu-drivers autoinstall + warn "NVIDIA driver installed. A REBOOT may be required before proceeding." + read -rp "Continue anyway? (y/N): " choice + [[ "$choice" != [yY] ]] && { log "Reboot and re-run this script."; exit 0; } +fi + +nvidia-smi +log "NVIDIA driver is working." + +# --- Install Docker ----------------------------------------------------------- +if ! command -v docker &>/dev/null; then + log "Docker not found. Installing Docker Engine..." + apt-get update -qq + apt-get install -y ca-certificates curl gnupg + + install -m 0755 -d /etc/apt/keyrings + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \ + gpg --dearmor -o /etc/apt/keyrings/docker.gpg + chmod a+r /etc/apt/keyrings/docker.gpg + + # Detect distro (works for Ubuntu & Debian) + DISTRO_ID=$(. /etc/os-release && echo "$ID") + DISTRO_CODENAME=$(. /etc/os-release && echo "$VERSION_CODENAME") + + echo \ + "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/${DISTRO_ID} ${DISTRO_CODENAME} stable" | \ + tee /etc/apt/sources.list.d/docker.list > /dev/null + + apt-get update -qq + apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + + systemctl enable --now docker + log "Docker installed successfully." +else + log "Docker is already installed: $(docker --version)" +fi + +# --- Install NVIDIA Container Toolkit ---------------------------------------- +log "Adding NVIDIA Container Toolkit repository..." + +curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \ + gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg + +curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \ + sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \ + tee /etc/apt/sources.list.d/nvidia-container-toolkit.list > /dev/null + +apt-get update -qq +apt-get install -y nvidia-container-toolkit + +# --- Configure Docker runtime ------------------------------------------------- +log "Configuring Docker to use NVIDIA runtime..." +nvidia-ctk runtime configure --runtime=docker + +systemctl restart docker +log "Docker restarted with NVIDIA runtime." + +# --- Verify ------------------------------------------------------------------- +log "Running verification: docker run --gpus all nvidia/cuda nvidia-smi" +echo "---" +docker run --rm --gpus all nvidia/cuda:12.6.3-base-ubuntu24.04 nvidia-smi + +echo "" +log "=============================================" +log " NVIDIA Docker setup complete!" +log " Usage: docker run --gpus all " +log "=============================================" diff --git a/openai/docker-compose.yml b/openai/docker-compose.yml new file mode 100644 index 0000000..a9d351d --- /dev/null +++ b/openai/docker-compose.yml @@ -0,0 +1,23 @@ +services: + open-webui: + image: ghcr.io/open-webui/open-webui:ollama + container_name: open-webui + ports: + - "3125:8080" + volumes: + - ollama:/root/.ollama + - open-webui:/app/backend/data + restart: always + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + environment: + - ANTHROPIC_API_KEY=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 + +volumes: + ollama: + open-webui: