diff --git a/stacks/storage/.gitkeep b/stacks/storage/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/stacks/storage/README.md b/stacks/storage/README.md new file mode 100644 index 00000000..edf9a929 --- /dev/null +++ b/stacks/storage/README.md @@ -0,0 +1,131 @@ +# Storage Stack + +Self-hosted file storage, object storage, and file management for HomeLab Stack. + +## What's Included + +| Service | Version | URL | Purpose | +|---------|---------|-----|---------| +| Nextcloud | 29.0.9 | `nextcloud.` | Personal cloud (files, calendar, contacts) | +| MinIO | RELEASE.2024-11-07 | `minio.` (UI), `s3.` (API) | S3-compatible object storage | +| FileBrowser | v2.31.2 | `files.` | Lightweight file manager | + +## Architecture + +``` +Users + │ + ├──► nextcloud. ── Nextcloud (files, PIM, sharing) + ├──► minio. ── MinIO Console (bucket management) + ├──► s3. ── MinIO S3 API (programmatic access) + └──► files. ── FileBrowser (quick file browse/upload) + │ + ├──► homelab-postgres (databases network) + └──► homelab-redis (databases network) +``` + +## Quick Start + +```bash +# Ensure base + databases stacks are running first +cd stacks/base && docker compose up -d +cd ../databases && docker compose up -d + +# Start storage +cd ../storage +ln -sf ../../.env .env +docker compose up -d +``` + +## Configuration + +### Environment Variables + +| Variable | Required | Default | Description | +|----------|----------|---------|-------------| +| `DOMAIN` | Yes | — | Base domain | +| `TZ` | No | `Asia/Shanghai` | Timezone | +| `NEXTCLOUD_ADMIN_USER` | No | `admin` | Nextcloud admin username | +| `NEXTCLOUD_ADMIN_PASSWORD` | Yes | — | Nextcloud admin password | +| `NEXTCLOUD_DB_PASSWORD` | Yes | — | PostgreSQL password for nextcloud user | +| `REDIS_PASSWORD` | Yes | — | Redis password (shared with databases stack) | +| `MINIO_ROOT_USER` | No | `minioadmin` | MinIO admin username | +| `MINIO_ROOT_PASSWORD` | Yes | — | MinIO admin password | +| `STORAGE_PATH` | No | `/data` | Host path for FileBrowser | + +### Nextcloud Setup + +1. Visit `https://nextcloud.` +2. Login with `NEXTCLOUD_ADMIN_USER` / `NEXTCLOUD_ADMIN_PASSWORD` +3. Install recommended apps: Calendar, Contacts, Tasks, Notes +4. Configure external storage (optional): Settings → External Storage → Add local/S3 mount + +**Nextcloud connects to the shared PostgreSQL and Redis instances** via the `databases` network. Make sure the databases stack is running first. + +### MinIO Setup + +1. Visit `https://minio.` +2. Login with `MINIO_ROOT_USER` / `MINIO_ROOT_PASSWORD` +3. Create buckets for your services (e.g., `backups`, `media`, `documents`) +4. Create access keys: Identity → Service Accounts → Create Access Key +5. Use the S3 API endpoint `https://s3.` in other services + +### FileBrowser Setup + +1. Visit `https://files.` +2. Default login: `admin` / `admin` +3. Change password immediately: Settings → User Management +4. Configure the storage path via `STORAGE_PATH` in `.env` + +## Integration with Other Stacks + +### Use MinIO as Nextcloud External Storage + +In Nextcloud: Settings → External Storage → Add: +- Type: Amazon S3 +- Bucket: `` +- Host: `s3.` +- Access Key / Secret: from MinIO service account + +### Use MinIO as Backup Target + +In backup scripts, set: +```env +AWS_ENDPOINT_URL=https://s3. +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +``` + +## SSO Integration + +Nextcloud is protected by Authentik ForwardAuth. To enable: + +1. Deploy the SSO stack (`stacks/sso/`) +2. Create an OIDC provider in Authentik for Nextcloud +3. Install Nextcloud OIDC Login app: `docker exec nextcloud occ app:install oidc_login` + +MinIO and FileBrowser use Traefik ForwardAuth middleware. + +## CN Network Adaptation + +All images available on Docker Hub. Nextcloud may be slow to pull: + +```bash +CN_MODE=true ./scripts/cn-pull.sh +``` + +## Health Check + +```bash +docker compose ps --format "table {{.Name}}\t{{.Status}}" +``` + +## Troubleshooting + +| Problem | Solution | +|---------|----------| +| Nextcloud DB error | Ensure databases stack is running; check `NEXTCLOUD_DB_PASSWORD` matches | +| Nextcloud slow first start | Normal — runs DB migrations on first launch (up to 5 min) | +| MinIO console redirect loop | Check `MINIO_BROWSER_REDIRECT_URL` matches `minio.` | +| FileBrowser empty | Set `STORAGE_PATH` to a valid host directory | +| WebDAV not working | Traefik middleware handles `.well-known` redirects | diff --git a/stacks/storage/docker-compose.yml b/stacks/storage/docker-compose.yml index 8dfe309d..0701e45b 100644 --- a/stacks/storage/docker-compose.yml +++ b/stacks/storage/docker-compose.yml @@ -15,18 +15,20 @@ services: - NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.${DOMAIN} - POSTGRES_HOST=homelab-postgres - POSTGRES_DB=nextcloud - - POSTGRES_USER=${POSTGRES_USER:-homelab} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-changeme} + - POSTGRES_USER=nextcloud + - POSTGRES_PASSWORD=${NEXTCLOUD_DB_PASSWORD:?NEXTCLOUD_DB_PASSWORD required} - REDIS_HOST=homelab-redis + - REDIS_HOST_PASSWORD=${REDIS_PASSWORD} labels: - traefik.enable=true - "traefik.http.routers.nextcloud.rule=Host(`nextcloud.${DOMAIN}`)" - traefik.http.routers.nextcloud.entrypoints=websecure - traefik.http.routers.nextcloud.tls=true + - traefik.http.routers.nextcloud.tls.certresolver=letsencrypt - traefik.http.services.nextcloud.loadbalancer.server.port=80 - "traefik.http.middlewares.nextcloud-dav.redirectregex.regex=https://(.*)/.well-known/(card|cal)dav" - "traefik.http.middlewares.nextcloud-dav.redirectregex.replacement=https://$${1}/remote.php/dav/" - - traefik.http.routers.nextcloud.middlewares=nextcloud-dav + - traefik.http.routers.nextcloud.middlewares=nextcloud-dav,authentik-forwardauth@docker healthcheck: test: [CMD-SHELL, "curl -sf http://localhost:80/status.php || exit 1"] interval: 30s @@ -52,10 +54,12 @@ services: - "traefik.http.routers.minio.rule=Host(`minio.${DOMAIN}`)" - traefik.http.routers.minio.entrypoints=websecure - traefik.http.routers.minio.tls=true + - traefik.http.routers.minio.tls.certresolver=letsencrypt - traefik.http.services.minio.loadbalancer.server.port=9001 - "traefik.http.routers.minio-api.rule=Host(`s3.${DOMAIN}`)" - traefik.http.routers.minio-api.entrypoints=websecure - traefik.http.routers.minio-api.tls=true + - traefik.http.routers.minio-api.tls.certresolver=letsencrypt - traefik.http.services.minio-api.loadbalancer.server.port=9000 healthcheck: test: [CMD-SHELL, "curl -sf http://localhost:9000/minio/health/live || exit 1"] @@ -80,6 +84,7 @@ services: - "traefik.http.routers.filebrowser.rule=Host(`files.${DOMAIN}`)" - traefik.http.routers.filebrowser.entrypoints=websecure - traefik.http.routers.filebrowser.tls=true + - traefik.http.routers.filebrowser.tls.certresolver=letsencrypt - traefik.http.services.filebrowser.loadbalancer.server.port=80 healthcheck: test: [CMD-SHELL, "curl -sf http://localhost:80/ || exit 1"]