From 72da841c2b7a26f20ff24a1883c1dd61bf445ca6 Mon Sep 17 00:00:00 2001 From: "M. van der Woord" Date: Tue, 17 Mar 2026 19:49:26 +0100 Subject: [PATCH] infra setup --- CLAUDE.md | 498 ++++-------------- ansible.cfg | 3 + backups/ce-backup-20260317-194405.tar | Bin 0 -> 122880 bytes credentials.md | 46 ++ docs/future-plans.md | 87 +++ docs/getting-started.md | 47 ++ docs/gitea-actions-guide.md | 232 ++++++++ docs/overview.md | 121 +++++ docs/runbook.md | 189 +++++++ inventory/group_vars/all.yml | 34 ++ inventory/hosts.yml | 7 + playbooks/bootstrap.yml | 9 + playbooks/deploy.yml | 7 + roles/common/handlers/main.yml | 5 + roles/common/tasks/main.yml | 127 +++++ roles/docker/tasks/main.yml | 50 ++ roles/services/tasks/main.yml | 157 ++++++ roles/services/templates/Caddyfile.j2 | 29 + roles/services/templates/dex-config.yml.j2 | 51 ++ .../services/templates/docker-compose.yml.j2 | 182 +++++++ scripts/backup.sh | 75 +++ scripts/restore.sh | 113 ++++ 22 files changed, 1685 insertions(+), 384 deletions(-) create mode 100644 ansible.cfg create mode 100644 backups/ce-backup-20260317-194405.tar create mode 100644 credentials.md create mode 100644 docs/future-plans.md create mode 100644 docs/getting-started.md create mode 100644 docs/gitea-actions-guide.md create mode 100644 docs/overview.md create mode 100644 docs/runbook.md create mode 100644 inventory/group_vars/all.yml create mode 100644 inventory/hosts.yml create mode 100644 playbooks/bootstrap.yml create mode 100644 playbooks/deploy.yml create mode 100644 roles/common/handlers/main.yml create mode 100644 roles/common/tasks/main.yml create mode 100644 roles/docker/tasks/main.yml create mode 100644 roles/services/tasks/main.yml create mode 100644 roles/services/templates/Caddyfile.j2 create mode 100644 roles/services/templates/dex-config.yml.j2 create mode 100644 roles/services/templates/docker-compose.yml.j2 create mode 100755 scripts/backup.sh create mode 100755 scripts/restore.sh diff --git a/CLAUDE.md b/CLAUDE.md index c87def4..bdd0785 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,8 @@ -# Infrastructure Bootstrap — Claude Code Operating Instructions +# Infrastructure — Claude Code Operating Instructions ## Your Role -You are a DevOps pair programmer helping bootstrap a production-grade single-node Docker Swarm +You are a DevOps pair programmer helping maintain and extend a production single-node Docker Compose infrastructure using Ansible. You work **one step at a time**. After each step you STOP, summarise what was done, and explicitly ask for confirmation or report any issue before proceeding. @@ -13,443 +13,173 @@ what was done, and explicitly ask for confirmation or report any issue before pr ## Principals - **Operator**: the human running this session -- **Target host**: a Linux VPS (Ubuntu 22.04 LTS assumed unless told otherwise) -- **Local machine**: where this repo lives and Ansible runs from +- **Target host**: Debian 13 (Trixie) VPS on DigitalOcean, hostname: `box.cloud-elves.eu` (188.166.60.12) +- **Local machine**: macOS, where this repo lives and Ansible runs from +- **SSH key**: `~/.ssh/id_ed25519_ce` --- -## Stack Overview (for context — do not implement all at once) +## Stack Overview ``` -Ansible (local) - └── Docker Swarm (single node on VPS) - ├── Traefik — reverse proxy, SSL termination, auto-discovery via labels - ├── Portainer — web UI for stack/container management - ├── Gitea — self-hosted git (the remote for this very repo, eventually) - └── [future] — Jenkins, custom services, etc. +Ansible (local machine) + └── Docker Compose (single node on box.cloud-elves.eu) + ├── Caddy — reverse proxy, automatic HTTPS via Let's Encrypt + ├── LLDAP — lightweight LDAP user directory (ldap.cloud-elves.eu) + ├── Dex — OIDC provider, backed by LLDAP (auth.cloud-elves.eu) + ├── Gitea — git hosting (git.cloud-elves.eu), SSH on port 2222 + ├── Outline — wiki/docs (docs.cloud-elves.eu) + └── Static site — cloud-elves.eu / www.cloud-elves.eu (rsync deploy) ``` -Backups: Restic → object storage (destination TBD by operator). +Supporting containers (internal only): Gitea Postgres, Outline Postgres, Outline Redis. + +Backups: not yet configured (Restic → object storage planned). --- ## Ground Rules You Must Follow 1. **One step at a time.** Complete one logical unit of work, then stop and check in. -2. **Show before you run.** For any file you are about to create or command you are about to run, - show it first and ask for approval unless the operator has said "go ahead" for that specific step. -3. **Validate after each step.** After applying anything to the remote host, run a quick verification - (e.g. `ansible -m ping`, `docker info`, `curl` health check) and report the result. -4. **Surface errors immediately.** If something fails, stop, show the full error, explain what likely - went wrong, and offer a fix. Do not attempt to auto-fix silently. -5. **Keep it simple.** Prefer the least complex solution that works. No over-engineering. -6. **Comment everything.** Every Ansible task and every non-obvious config block gets a comment. -7. **State is precious.** Before any destructive action (remove, redeploy with volume change, etc.) - warn the operator and suggest a backup or dry-run first. +2. **Research before writing.** Verify image versions, OS compatibility, and config options against + current documentation. Do not guess at configuration. +3. **Everything through Ansible.** No manual SSH fixes, no ad-hoc commands. If it needs to happen + on the server, it goes in a playbook or role. +4. **Validate after each step.** After applying anything, run a verification and report the result. +5. **Surface errors immediately.** If something fails, stop, show the error, explain, and offer a fix. +6. **Keep it simple.** Prefer the least complex solution. We moved away from Docker Swarm + Traefik + to Docker Compose + Caddy for exactly this reason. +7. **State is precious.** Before any destructive action, warn the operator and suggest a backup first. +8. **Comment everything.** Every Ansible task and every non-obvious config block gets a comment. --- -## Repository Layout (build this incrementally, not all at once) +## Repository Layout ``` -infra/ -├── CLAUDE.md ← this file +ce-infra/ +├── CLAUDE.md ← this file +├── ansible.cfg ← sets roles_path and default inventory +├── credentials.md ← all service credentials (DO NOT commit to public repo) +├── docs/ ← infrastructure documentation +│ ├── overview.md ← architecture and service overview +│ ├── runbook.md ← operational procedures +│ └── future-plans.md ← planned work and improvements ├── inventory/ -│ └── hosts.yml ← VPS connection details -├── group_vars/ -│ └── all.yml ← shared variables (domain, email, ports, versions) +│ ├── hosts.yml ← VPS connection details +│ └── group_vars/ +│ └── all.yml ← all variables (domain, secrets, versions) ├── roles/ -│ ├── common/ ← OS hardening, unattended-upgrades, useful packages -│ ├── docker/ ← Docker Engine + Swarm init -│ ├── traefik/ ← Traefik stack deploy -│ ├── portainer/ ← Portainer stack deploy -│ └── gitea/ ← Gitea stack + postgres, state/volume notes -├── stacks/ ← raw docker stack YAMLs (source of truth for each service) -│ ├── traefik.yml -│ ├── portainer.yml -│ └── gitea.yml -├── playbooks/ -│ ├── bootstrap.yml ← runs common + docker (idempotent, safe to re-run) -│ ├── deploy.yml ← deploys/updates one or all stacks -│ └── backup.yml ← triggers restic backup of named volumes -└── scripts/ - └── migrate-volume.sh ← helper for moving named volume data between hosts +│ ├── common/ ← OS hardening, packages, UFW, cloud-init disable +│ ├── docker/ ← Docker Engine install +│ └── services/ ← Docker Compose stack (all services) +│ ├── tasks/main.yml +│ └── templates/ +│ ├── docker-compose.yml.j2 ← all containers +│ ├── Caddyfile.j2 ← reverse proxy config +│ └── dex-config.yml.j2 ← Dex OIDC config +└── playbooks/ + ├── bootstrap.yml ← runs common + docker (idempotent, safe to re-run) + └── deploy.yml ← deploys/updates all services ``` --- -## Phase Sequence +## Key Technical Decisions -Work through these phases in order. Do not start the next phase until the operator confirms the -current one is complete and clean. - -### PHASE 0 — Prerequisites check (local machine) -### PHASE 1 — Inventory & variables -### PHASE 2 — VPS first contact & hardening -### PHASE 3 — Docker Engine + Swarm init -### PHASE 4 — Traefik deployment & SSL test -### PHASE 5 — Portainer deployment -### PHASE 6 — Gitea deployment (with state migration notes) -### PHASE 7 — Backup setup (Restic) -### PHASE 8 — Day-2 ops guide (adding new services) +| Decision | Rationale | +|---|---| +| Docker Compose over Swarm | Single node — Swarm adds overlay network complexity for zero benefit | +| Caddy over Traefik | Automatic HTTPS with zero config, simple Caddyfile, no label machinery | +| LLDAP + Dex over Keycloak/Authentik | Lightweight identity stack, minimal resource usage on 2GB RAM | +| Local file storage for Outline | No S3 dependency, simpler backup story | +| `server_hostname` variable name | `hostname` collides with Ansible built-in | +| Cloud-init disabled on first run | Prevents SSH key regeneration on hostname change (DigitalOcean) | +| `group_vars/` inside `inventory/` | Ansible auto-discovers it there without extra config | --- -## PHASE 0 — Prerequisites Check +## Authentication Flow -**Goal**: confirm the local machine has everything needed before touching the VPS. +``` +User → Outline / Gitea → Dex (OIDC) → LLDAP (user directory) +``` -Check for the following and report status of each: -- `ansible` (>= 2.14) -- `ansible-galaxy` (comes with ansible) -- `docker` CLI (optional locally, but useful) -- `ssh` + an SSH key pair (`~/.ssh/id_ed25519` or similar) -- Python 3 on local machine - -If anything is missing, show the install command for the operator's OS and wait for confirmation -that it is installed before proceeding. - -**Gate**: operator confirms all prerequisites are present. +- Manage users in LLDAP web UI (ldap.cloud-elves.eu) +- All services authenticate via Dex OIDC +- Gitea has auto-registration enabled — first SSO login creates the account +- Outline creates accounts on first SSO login automatically --- -## PHASE 1 — Inventory & Variables +## DNS Records -**Goal**: create `inventory/hosts.yml` and `group_vars/all.yml`. +All subdomains are CNAMEs pointing to `box.cloud-elves.eu`: -Ask the operator for: -1. VPS IP address or hostname -2. SSH user (typically `root` or `ubuntu` for a fresh VPS) -3. Path to SSH private key (default: `~/.ssh/id_ed25519`) -4. Domain name (e.g. `example.com`) -5. Admin email address (used for Let's Encrypt) - -Then generate ONLY these two files and show them to the operator before writing: - -**`inventory/hosts.yml`**: -```yaml -all: - hosts: - vps: - ansible_host: - ansible_user: - ansible_ssh_private_key_file: - ansible_python_interpreter: /usr/bin/python3 -``` - -**`group_vars/all.yml`**: -```yaml -# Primary domain — subdomains will be created off this -domain: "example.com" - -# Email for Let's Encrypt certificate notifications -acme_email: "admin@example.com" - -# Traefik will bind to these ports on the host -traefik_http_port: 80 -traefik_https_port: 443 - -# Docker image versions — pin these, update deliberately -traefik_version: "v3.1" -portainer_version: "latest" -gitea_version: "1.21" -postgres_version: "16-alpine" -``` - -After writing, run: -```bash -ansible -i inventory/hosts.yml all -m ping -``` - -Report the result. **Gate**: ping succeeds. +| Subdomain | Service | +|---|---| +| `box.cloud-elves.eu` | A record → 188.166.60.12 | +| `cloud-elves.eu` | A record → 188.166.60.12 | +| `www` | Static site | +| `git` | Gitea | +| `auth` | Dex OIDC | +| `ldap` | LLDAP web UI | +| `docs` | Outline wiki | --- -## PHASE 2 — VPS Hardening (role: common) +## Deployment -**Goal**: safe, minimal OS baseline. Idempotent — safe to re-run any time. - -Tasks to implement in `roles/common/tasks/main.yml`: -1. Set hostname -2. Update apt cache + upgrade packages -3. Install: `curl`, `git`, `htop`, `ufw`, `fail2ban`, `unattended-upgrades` -4. Configure UFW: deny all in, allow SSH (22), HTTP (80), HTTPS (443) -5. Enable UFW -6. Enable unattended-upgrades for security patches -7. Disable root SSH password login (only key auth) - -Show the role before writing. After applying: -```bash -ansible-playbook -i inventory/hosts.yml playbooks/bootstrap.yml --tags common -``` - -Verify UFW is active: -```bash -ansible -i inventory/hosts.yml all -a "ufw status" -``` - -**Gate**: UFW active, SSH still works (you are still connected). - ---- - -## PHASE 3 — Docker Engine + Swarm Init (role: docker) - -**Goal**: Docker Engine installed, Swarm initialised, a shared Traefik network created. - -Tasks in `roles/docker/tasks/main.yml`: -1. Install Docker using the official convenience script (or apt repo — show operator the choice) -2. Add ansible user to `docker` group -3. Enable + start `docker` service -4. Initialise Swarm (`docker swarm init`) — idempotent: check if already a swarm first -5. Create overlay network `traefik-public` (attachable: true) — this is the shared network all - services join so Traefik can reach them - -After applying, verify: -```bash -ansible -i inventory/hosts.yml all -a "docker info --format '{{.Swarm.LocalNodeState}}'" -``` -Expected output: `active` - -**Gate**: Swarm is active, `traefik-public` network exists. - ---- - -## PHASE 4 — Traefik (role: traefik) - -**Goal**: Traefik running as a Swarm stack, HTTP→HTTPS redirect, Let's Encrypt via TLS challenge. - -Generate `stacks/traefik.yml`. Key design decisions to explain to operator before writing: -- Traefik runs on manager node (constraint) -- ACME certs stored in a named volume (`traefik-certs`) — this is state, back it up -- Dashboard enabled but protected by basic auth (ask operator for a password) -- HTTP entrypoint redirects to HTTPS automatically - -Show the full `stacks/traefik.yml` before writing. Then deploy: -```bash -docker stack deploy -c stacks/traefik.yml traefik -``` - -Verify: -```bash -docker service ls -curl -I http:/// # should 301 to https -``` - -Also confirm Traefik dashboard is reachable at `https://traefik.`. - -**Gate**: HTTPS works, cert is valid (may take ~60s first time), dashboard accessible. - ---- - -## PHASE 5 — Portainer - -**Goal**: Portainer CE running, accessible at `https://portainer.`. - -Generate `stacks/portainer.yml`. Notes: -- Portainer needs access to Docker socket (mount `/var/run/docker.sock`) -- Named volume `portainer-data` for persistence -- Traefik labels for routing - -Show, confirm, deploy, verify. First-run: Portainer will prompt for admin password setup. - -**Gate**: Portainer UI accessible, operator has set admin password. - ---- - -## PHASE 6 — Gitea - -**Goal**: Gitea + Postgres running at `https://git.`, with notes on state migration. - -This phase has two sub-modes: - -**6a — Fresh install**: generate `stacks/gitea.yml` with: -- Gitea service + named volume `gitea-data` -- Postgres service + named volume `gitea-db` -- Internal overlay network `gitea-internal` (Postgres not exposed to Traefik network) -- Traefik labels on Gitea only - -**6b — Migrate existing state** (if operator has an existing Gitea elsewhere): -- Stop source Gitea -- Dump Postgres: `pg_dump -U gitea gitea > gitea-backup.sql` -- Tar gitea data volume: `tar czf gitea-data.tar.gz /var/lib/docker/volumes/gitea-data` -- Use `scripts/migrate-volume.sh` to transfer and restore on new host -- Then deploy stack and verify - -Ask operator which sub-mode applies before proceeding. - -Show all files, confirm, deploy. After deploy, complete Gitea web installer. - -**Gate**: Gitea accessible, can create repo, SSH clone works. - ---- - -## PHASE 7 — Backup (Restic) - -**Goal**: daily automated backup of all named volumes to object storage. - -Ask operator for: -1. Backup destination (S3 / Backblaze B2 / SFTP / etc.) -2. Bucket name + credentials -3. Retention policy preference (default: 7 daily, 4 weekly, 6 monthly) - -Generate `playbooks/backup.yml` which: -1. Installs Restic on the host -2. Initialises the Restic repo (idempotent) -3. Creates a backup script at `/opt/restic/backup.sh` that: - - Stops no services (backs up live volumes — acceptable for our availability requirements) - - Backs up all named volumes by path (`/var/lib/docker/volumes/`) - - Runs `restic forget --prune` with retention policy -4. Installs a systemd timer (preferred over cron) to run daily at 02:00 - -Show all files, confirm, test with a manual run, verify snapshot appears: -```bash -restic -r snapshots -``` - -**Gate**: snapshot confirmed in remote repo. - ---- - -## PHASE 8 — Day-2 Ops: Adding a New Service - -**Goal**: operator understands the pattern for spinning up any new service cleanly. - -When the operator wants to add a new service, follow this checklist: - -1. **Ask**: what is the service, what image, what subdomain, does it need persistent storage? -2. **Generate** a `stacks/.yml` based on the template below -3. **Show** it, wait for approval -4. **Deploy**: `docker stack deploy -c stacks/.yml ` -5. **Verify**: check service is running, subdomain resolves, SSL cert issued -6. **Commit**: remind operator to commit the stack file to git - -**Standard stack template for a new service**: -```yaml -# stacks/.yml -# Service: -# Subdomain: . - -networks: - traefik-public: - external: true - -volumes: - -data: - -services: - : - image: : - networks: - - traefik-public - volumes: - - -data:/data - environment: - - SOME_VAR=value - deploy: - replicas: 1 - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 - labels: - - "traefik.enable=true" - - "traefik.http.routers..rule=Host(`.`)" - - "traefik.http.routers..entrypoints=websecure" - - "traefik.http.routers..tls.certresolver=letsencrypt" - - "traefik.http.services..loadbalancer.server.port=" -``` - -**To remove a service cleanly**: -```bash -docker stack rm -# volumes are NOT removed automatically — data is safe -# to also remove volumes when sure: -docker volume rm -data -``` - ---- - -## State Migration Script Template - -Create `scripts/migrate-volume.sh`: +From a **fresh droplet** (Debian 13, SSH key injected): ```bash -#!/usr/bin/env bash -# migrate-volume.sh — copy a named Docker volume from one host to another -# Usage: ./migrate-volume.sh [ssh_key] -# -# Both hosts must have Docker installed. -# The volume must exist on the source host. -# A volume with the same name will be created on the dest host. +# 1. Accept new host keys +ssh-keygen -R box.cloud-elves.eu +ssh-keyscan box.cloud-elves.eu >> ~/.ssh/known_hosts -set -euo pipefail +# 2. Bootstrap (OS hardening, Docker install) +ansible-playbook -i inventory/hosts.yml playbooks/bootstrap.yml -VOLUME=$1 -SRC=$2 -DST=$3 -KEY=${4:-~/.ssh/id_ed25519} - -echo "==> Migrating volume '$VOLUME' from $SRC to $DST" - -echo "--> Creating volume on destination..." -ssh -i "$KEY" "$DST" "docker volume create $VOLUME" - -echo "--> Streaming data from source to destination..." -ssh -i "$KEY" "$SRC" \ - "docker run --rm -v $VOLUME:/data alpine tar czf - /data" \ - | ssh -i "$KEY" "$DST" \ - "docker run --rm -i -v $VOLUME:/data alpine tar xzf - -C /" - -echo "==> Done. Volume '$VOLUME' is available on $DST." +# 3. Deploy all services +ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml ``` ---- +To **update services** after config changes: -## How to Re-deploy After a VPS Swap - -When you get a permanent VPS and want to move from the test one: - -1. Run `playbooks/backup.yml` on old host (final snapshot) -2. Provision new VPS — run `bootstrap.yml` (phases 0–3) -3. Deploy Traefik + Portainer (phases 4–5) -4. For each stateful service (Gitea etc.): use `migrate-volume.sh` to transfer volumes -5. Deploy service stacks -6. Point DNS to new IP -7. Verify SSL certs renew on new host -8. Decommission old VPS +```bash +ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml +``` --- ## Quick Reference Commands ```bash -# Check all running services -docker service ls - -# View logs for a service -docker service logs -f - -# Update a service image -docker service update --image : _ - -# Re-deploy a stack (picks up config changes) -docker stack deploy -c stacks/.yml - -# Remove a stack (keeps volumes) -docker stack rm - -# List volumes -docker volume ls - -# Run ansible against host -ansible-playbook -i inventory/hosts.yml playbooks/bootstrap.yml - -# Check ansible connectivity +# Check Ansible connectivity ansible -i inventory/hosts.yml all -m ping + +# Check running containers on box +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose ps" + +# View logs for a specific service +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose logs --tail 50" + +# Deploy static site +rsync -avz --delete site/ root@box.cloud-elves.eu:/opt/www/ + +# Restart a single service +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose restart " ``` --- -## Begin +## Future Work -Start with **PHASE 0**. Check prerequisites on the local machine. Report findings and wait. +- **Backup setup** — Restic to object storage, systemd timer, retention policy +- **Security review** — firewall audit, container hardening, secret management (move secrets out of group_vars) +- **CI/CD** — automated deployments, documentation pipeline +- **Migration plan** — move to permanent VPS once company incorporation is complete +- **Portainer** — optional web UI for container management (low priority) diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..f34572b --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,3 @@ +[defaults] +roles_path = roles +inventory = inventory/hosts.yml diff --git a/backups/ce-backup-20260317-194405.tar b/backups/ce-backup-20260317-194405.tar new file mode 100644 index 0000000000000000000000000000000000000000..813c034aeb361c5eb6639fb2a560895759d97f68 GIT binary patch literal 122880 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 G0{;THoV7pz literal 0 HcmV?d00001 diff --git a/credentials.md b/credentials.md new file mode 100644 index 0000000..fdad10f --- /dev/null +++ b/credentials.md @@ -0,0 +1,46 @@ +# Credentials + +## LLDAP (User Directory) + +- URL: https://ldap.cloud-elves.eu +- Admin username: `admin` +- Admin password: `cio3LFvUwUzLhO6iMXTAbQPq` +- Base DN: `dc=cloud-elves,dc=eu` +- LDAP port: 3890 (internal only) + +## Dex (OIDC Provider) + +- URL: https://auth.cloud-elves.eu +- Discovery: https://auth.cloud-elves.eu/.well-known/openid-configuration + +### Dex Clients +| Client | ID | Secret | +|---|---|---| +| Outline | `outline` | `6edfe427944e50856e65e87ebf62217389f72963e8e6fe16d19536f1d31ffb56` | +| Gitea | `gitea` | `nWotT1z2AziFbmzscORURXlZ` | + +## Gitea + +- URL: https://git.cloud-elves.eu +- SSH clone: `ssh://git@git.cloud-elves.eu:2222` +- Auth: via Dex SSO (or local admin account) + +### Gitea Postgres Database +- Host: `gitea-db` (internal) +- Database / User: `gitea` +- Password: `0cGpEZ0Ph2mdLbPJjA4kbR` + +## Outline (Wiki) + +- URL: https://docs.cloud-elves.eu +- Auth: via Dex SSO (login button: "Cloud Elves SSO") + +### Outline Postgres Database +- Host: `outline-db` (internal) +- Database / User: `outline` +- Password: `oZEdt71Jd2zkto2qWKj1MI7K` + +## Static Site + +- URL: https://cloud-elves.eu (also https://www.cloud-elves.eu) +- Deploy: `rsync -avz --delete site/ root@box.cloud-elves.eu:/opt/www/` diff --git a/docs/future-plans.md b/docs/future-plans.md new file mode 100644 index 0000000..e0610db --- /dev/null +++ b/docs/future-plans.md @@ -0,0 +1,87 @@ +# Future Plans + +## Priority Overview + +| Priority | Item | Blocked on | +|---|---|---| +| High | Backup system (Restic) | Choosing backup destination | +| High | Security review | — | +| Medium | Migration to permanent VPS | Company incorporation | +| Medium | SMTP / Email | ProtonMail setup after incorporation | +| Medium | CI/CD pipeline | — | +| Low | Monitoring | — | +| Low | Group-based access control | Not needed yet (4 people) | +| Low | Move SSH to non-standard port | — | +| Low | Outline branding (remove badge) | Cosmetic, parked | + +## High Priority + +### Backup System (Restic) +- Daily automated backup of all Docker volumes to object storage +- Systemd timer (not cron) +- Retention policy: 7 daily, 4 weekly, 6 monthly +- Test restore procedure documented +- **Blocked on**: choosing a backup destination (S3 / Backblaze B2 / SFTP) + +### Security Review +- Firewall audit — verify only intended ports are exposed +- Container hardening — run containers as non-root where possible +- Secret management — move passwords/secrets out of `group_vars/all.yml` into Ansible Vault or environment files +- Review Dex/LLDAP security configuration +- Fail2ban rules review +- Check for unnecessary services or open ports +- HTTPS headers audit (HSTS, CSP, etc.) + +## Medium Priority + +### Migration to Permanent VPS + +Once company incorporation is complete and bank account is set up. + +```mermaid +sequenceDiagram + participant Old as Old VPS + participant Backup as Backup Storage + participant New as New VPS + participant DNS + + Old->>Backup: Final backup snapshot + Note over New: Provision Debian 13 + New->>New: Run bootstrap.yml + New->>New: Run deploy.yml + Backup->>New: Restore volumes + DNS->>New: Update A record to new IP + Note over New: Verify SSL certs renew + Note over Old: Decommission +``` + +### CI/CD Pipeline +- Automated deployment on git push +- Documentation pipeline (Markdown to Outline, or similar) +- Options to evaluate: Gitea Actions, Drone CI, or simple webhook-based deploy + +### SMTP / Email +- Set up ProtonMail for cloud-elves.eu (after incorporation) +- Configure Outline and Gitea to send transactional emails +- Update Let's Encrypt contact email from personal to company address + +## Low Priority + +### Monitoring +- Resource monitoring (CPU, memory, disk) +- Uptime monitoring for all services +- Options: simple solution like Uptime Kuma, or external service + +### Group-Based Access Control +- Configure Dex to pass LLDAP groups to applications +- Restrict certain services to specific groups (e.g., admin-only tools) +- Not needed now (4 people, everyone needs access everywhere) + +### Move SSH to Non-Standard Port +- Move host sshd from 22 to a high port (e.g., 2200) +- Reduces log noise from automated scanners +- Free up port 22 for Gitea SSH (nicer clone URLs) + +### Outline Branding +- Remove "Built with Outline" badge on public share pages +- Parked for now — cosmetic only diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 0000000..c81adfd --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,47 @@ +# Cloud Elves — Our Tools + +## What do we have? + +We run our own private server with a set of tools for the team. Everything is accessible from anywhere with a browser — just log in with your Cloud Elves account. + +## Your account + +You have one account that works across all our tools. Your login is managed centrally — if you can log into one tool, you can log into all of them. + +If you need an account or forgot your password, ask an admin. + +## Our tools + +### Documentation — https://docs.cloud-elves.eu + +This is where you're probably reading this. Our wiki for everything: internal docs, guides, meeting notes, public documentation — whatever we need to write down and share. + +- Log in to create and edit pages +- Some pages are public (anyone on the internet can read them) +- Private collections are only visible to the team + +### Git — https://git.cloud-elves.eu + +Our code lives here. This is like GitHub, but hosted by us. If you work with code, repositories, or anything version-controlled, this is where it goes. + +- Web interface for browsing code and pull requests +- SSH clone: `ssh://git@git.cloud-elves.eu:2222` + +### Website — https://cloud-elves.eu + +Our public website. Also available at https://www.cloud-elves.eu. + +### User Management (admin only) — https://ldap.cloud-elves.eu + +This is where admins create, edit, and remove team member accounts. Regular team members don't need to visit this — it's just for account administration. + +## How to log in + +1. Visit any of the tools above +2. Click the sign-in / SSO button +3. Enter your Cloud Elves username and password +4. You're in + +## Need help? + +Ask in the team chat, or reach out to whoever set up your account. diff --git a/docs/gitea-actions-guide.md b/docs/gitea-actions-guide.md new file mode 100644 index 0000000..ad2152d --- /dev/null +++ b/docs/gitea-actions-guide.md @@ -0,0 +1,232 @@ +# Gitea Actions — CI/CD Guide + +## What is this? + +Gitea Actions is our built-in CI/CD system. It lets you automate tasks when things happen in a git repository — like running tests on every push, deploying a site when you merge to main, or running a script on a schedule. + +If you've used GitHub Actions before, it's the same syntax. + +## How it works + +```mermaid +sequenceDiagram + participant Dev as Developer + participant Gitea as Gitea + participant Runner as Runner (box-runner) + participant Container as Job Container + + Dev->>Gitea: Push code + Gitea->>Runner: "There's a job to run" + Runner->>Container: Spin up temporary container + Container->>Container: Execute workflow steps + Container-->>Runner: Results + Runner-->>Gitea: Report status (pass/fail) + Note over Container: Container is cleaned up + Gitea-->>Dev: Show result in UI +``` + +Our runner (`box-runner`) runs on the same server as everything else. When a job triggers, it spins up a temporary Docker container, runs the steps, reports back, and cleans up. The runner itself is always running in the background, waiting for work. + +## Quick start + +### 1. Create a workflow file + +In any Gitea repository, create a file at `.gitea/workflows/` with a `.yml` extension: + +```yaml +# .gitea/workflows/hello.yml +name: Hello World +on: [push] + +jobs: + greet: + runs-on: ubuntu-latest + steps: + - run: echo "Hello from CI!" +``` + +### 2. Push it + +```bash +git add .gitea/workflows/hello.yml +git commit -m "Add CI workflow" +git push +``` + +### 3. Check the result + +Go to your repository on Gitea → **Actions** tab. You'll see the workflow run with its status. + +## Workflow syntax + +### When to run (triggers) + +```yaml +# Run on every push +on: [push] + +# Run on push to main only +on: + push: + branches: [main] + +# Run on pull request +on: [pull_request] + +# Run on a schedule (cron syntax) +on: + schedule: + - cron: "0 2 * * *" # Every day at 2 AM + +# Run manually from the UI +on: + workflow_dispatch: +``` + +### Available runners + +| Label | What it is | +|---|---| +| `ubuntu-latest` | Ubuntu container (default choice) | +| `ubuntu-24.04` | Ubuntu 24.04 specifically | +| `ubuntu-22.04` | Ubuntu 22.04 specifically | + +Use these in `runs-on`: + +```yaml +jobs: + my-job: + runs-on: ubuntu-latest +``` + +### Common steps + +**Check out the code:** +```yaml +steps: + - uses: actions/checkout@v4 +``` + +**Run a shell command:** +```yaml +steps: + - run: echo "Hello" +``` + +**Run multiple commands:** +```yaml +steps: + - run: | + echo "Step 1" + echo "Step 2" + ls -la +``` + +**Use environment variables:** +```yaml +jobs: + deploy: + runs-on: ubuntu-latest + env: + MY_VAR: "some value" + steps: + - run: echo $MY_VAR +``` + +**Use secrets (set in Gitea UI under repo Settings → Actions → Secrets):** +```yaml +steps: + - run: echo ${{ secrets.MY_SECRET }} +``` + +## Practical examples + +### Run tests on every push + +```yaml +name: Test +on: [push] + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: npm install + - run: npm test +``` + +### Deploy static site on push to main + +```yaml +name: Deploy Site +on: + push: + branches: [main] + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Deploy via rsync + run: | + mkdir -p ~/.ssh + echo "${{ secrets.DEPLOY_KEY }}" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan box.cloud-elves.eu >> ~/.ssh/known_hosts + rsync -avz --delete site/ root@box.cloud-elves.eu:/opt/www/ +``` + +> For this to work, add a `DEPLOY_KEY` secret in the repo settings containing a private SSH key that has access to the server. + +### Scheduled task (glorified cron) + +```yaml +name: Nightly Cleanup +on: + schedule: + - cron: "0 3 * * *" # 3 AM daily + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - run: echo "Running nightly task..." + # Add your actual commands here +``` + +### Build and push a Docker image + +```yaml +name: Build Image +on: + push: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: docker build -t my-app:latest . + - run: docker tag my-app:latest git.cloud-elves.eu/myorg/my-app:latest + # Push to Gitea's container registry if enabled +``` + +## Where to find things in the UI + +| What | Where | +|---|---| +| Workflow runs | Repository → **Actions** tab | +| Workflow files | Repository → `.gitea/workflows/` directory | +| Secrets | Repository → **Settings** → **Actions** → **Secrets** | +| Runner status | **Site Administration** → **Actions** → **Runners** (admin only) | + +## Tips + +- Workflows live in your repo as code — version controlled like everything else +- Each push shows a status check (green tick or red cross) next to the commit +- You can re-run failed workflows from the Actions tab +- Use `workflow_dispatch` trigger if you want a "run manually" button in the UI +- Keep workflows simple — if it's getting complex, it probably belongs in a script that the workflow just calls diff --git a/docs/overview.md b/docs/overview.md new file mode 100644 index 0000000..67ac130 --- /dev/null +++ b/docs/overview.md @@ -0,0 +1,121 @@ +# Cloud Elves Infrastructure Overview + +## Architecture + +All services run on a single DigitalOcean VPS (`box.cloud-elves.eu`, Debian 13) managed by Ansible and deployed as Docker Compose containers. + +### Services + +| Service | URL | Purpose | +|---|---|---| +| Caddy | (internal) | Reverse proxy, automatic HTTPS via Let's Encrypt | +| Gitea | https://git.cloud-elves.eu | Git hosting, SSH clone on port 2222 | +| Outline | https://docs.cloud-elves.eu | Wiki and documentation | +| Dex | https://auth.cloud-elves.eu | OIDC identity provider | +| LLDAP | https://ldap.cloud-elves.eu | User directory with web UI | +| Static site | https://cloud-elves.eu | Company website (also www) | + +### Supporting Services (internal only) + +| Service | Used by | +|---|---| +| Postgres (gitea-db) | Gitea | +| Postgres (outline-db) | Outline | +| Redis | Outline | + +### How a request reaches your app + +```mermaid +sequenceDiagram + participant Browser + participant Caddy + participant App as Gitea / Outline / etc. + + Browser->>Caddy: HTTPS request (port 443) + Note over Caddy: Terminates TLS
Auto-issued Let's Encrypt cert + Caddy->>App: Forward to internal port + App-->>Caddy: Response + Caddy-->>Browser: HTTPS response +``` + +## Authentication + +All authentication flows through a centralized identity stack. + +### SSO Login Flow + +```mermaid +sequenceDiagram + participant User + participant App as Gitea / Outline + participant Dex as Dex (OIDC) + participant LLDAP as LLDAP (Directory) + + User->>App: Visit app + App->>Dex: Redirect to SSO + Dex->>User: Show login form + User->>Dex: Enter credentials + Dex->>LLDAP: Verify credentials + LLDAP-->>Dex: OK + Dex-->>App: Auth token + App-->>User: Logged in +``` + +### Onboarding a new team member + +1. Create their account in LLDAP (https://ldap.cloud-elves.eu) +2. They can immediately log into all services via SSO — accounts are auto-created on first login + +### Removing a team member + +1. Delete or disable the user in LLDAP +2. Their SSO sessions will expire (existing sessions may persist until token expiry) + +## Networking + +### Exposed Ports + +| Port | Protocol | Service | +|---|---|---| +| 22 | TCP | SSH (host access) | +| 80 | TCP | HTTP (redirects to HTTPS) | +| 443 | TCP + UDP | HTTPS (all web services) | +| 2222 | TCP | Gitea SSH (git clone) | + +All other communication happens over internal Docker networks. UFW firewall blocks everything else. + +### Internal Networks + +| Network | Connects | +|---|---| +| frontend | Caddy to all web-facing services | +| identity | Dex to LLDAP | +| gitea-backend | Gitea to its Postgres | +| outline-backend | Outline to its Postgres and Redis | + +## DNS Records + +| Record | Type | Points to | +|---|---|---| +| `cloud-elves.eu` | A | 188.166.60.12 | +| `box.cloud-elves.eu` | A | 188.166.60.12 | +| `www.cloud-elves.eu` | CNAME | box.cloud-elves.eu | +| `git.cloud-elves.eu` | CNAME | box.cloud-elves.eu | +| `auth.cloud-elves.eu` | CNAME | box.cloud-elves.eu | +| `ldap.cloud-elves.eu` | CNAME | box.cloud-elves.eu | +| `docs.cloud-elves.eu` | CNAME | box.cloud-elves.eu | + +## Data & Persistence + +All persistent data is in Docker named volumes under `/var/lib/docker/volumes/` on the host. + +| Volume | Contains | +|---|---| +| `caddy-data` | TLS certificates | +| `caddy-config` | Caddy runtime config | +| `lldap-data` | User directory (SQLite) | +| `dex-data` | Dex database (SQLite) | +| `gitea-data` | Git repositories, Gitea config | +| `gitea-db` | Gitea Postgres data | +| `outline-data` | Uploaded files/attachments | +| `outline-db` | Outline Postgres data | diff --git a/docs/runbook.md b/docs/runbook.md new file mode 100644 index 0000000..081d9b4 --- /dev/null +++ b/docs/runbook.md @@ -0,0 +1,189 @@ +# Operational Runbook + +## Day-to-Day Operations + +### Check service health + +```bash +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose ps" +``` + +### View logs for a service + +```bash +# Replace with: caddy, gitea, outline, dex, lldap, gitea-db, outline-db, outline-redis +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose logs --tail 100" +``` + +### Restart a single service + +```bash +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose restart " +``` + +### Deploy config changes + +After editing any template in `roles/services/templates/`: + +```bash +ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml +``` + +### Deploy static site + +From your local `cloud-elves.eu` repo: + +```bash +rsync -avz --delete site/ root@box.cloud-elves.eu:/opt/www/ +``` + +## User Management + +### Onboarding flow + +```mermaid +sequenceDiagram + participant Admin + participant LLDAP + participant NewUser as New Team Member + participant App as Gitea / Outline + + Admin->>LLDAP: Create user account + LLDAP-->>Admin: Done + Admin->>NewUser: Share login details + NewUser->>App: Visit any app + App->>NewUser: Redirect to SSO + NewUser->>App: Log in with LLDAP credentials + Note over App: Account auto-created on first login +``` + +1. Go to https://ldap.cloud-elves.eu and log in as admin +2. Click "Create user" — fill in username, email, display name, password +3. Share credentials with the new team member +4. They can immediately log into Gitea and Outline via SSO + +### Removing a team member + +1. Go to https://ldap.cloud-elves.eu +2. Delete or disable the user + +## Adding a New Service + +### Checklist + +| Step | What | Where | +|---|---|---| +| 1 | Add container definition | `roles/services/templates/docker-compose.yml.j2` | +| 2 | Add reverse proxy entry | `roles/services/templates/Caddyfile.j2` | +| 3 | Add OIDC client (if SSO needed) | `roles/services/templates/dex-config.yml.j2` | +| 4 | Add variables (passwords, versions) | `inventory/group_vars/all.yml` | +| 5 | Create DNS CNAME | DNS provider: `` → `box.cloud-elves.eu` | +| 6 | Deploy | `ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml` | +| 7 | Verify | Caddy auto-issues TLS cert on first request | + +### How it connects + +```mermaid +sequenceDiagram + participant Dev as Developer + participant Ansible + participant Box as box.cloud-elves.eu + participant Caddy + participant LE as Let's Encrypt + + Dev->>Ansible: Run deploy.yml + Ansible->>Box: Template configs + docker compose up + Box-->>Ansible: Services running + Note over Caddy: New subdomain in Caddyfile + Caddy->>LE: Request certificate + LE-->>Caddy: Certificate issued + Note over Caddy: Service live with HTTPS +``` + +## Full Rebuild from Scratch + +### When you need this + +- Droplet is destroyed +- Migrating to a new server +- Starting fresh + +### Procedure + +```bash +# 1. Provision new Debian 13 droplet with SSH key (id_ed25519_ce) + +# 2. Update DNS: point box.cloud-elves.eu A record to new IP +# Flush local DNS: sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder + +# 3. Accept new host keys +ssh-keygen -R box.cloud-elves.eu +ssh-keyscan box.cloud-elves.eu >> ~/.ssh/known_hosts + +# 4. Bootstrap (OS hardening, Docker install) +ansible-playbook -i inventory/hosts.yml playbooks/bootstrap.yml + +# 5. Deploy all services +ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml + +# 6. Restore data from backup (once backup system is in place) +``` + +### After a fresh deploy you'll need to + +- Set up a Gitea admin account (first registered user via SSO becomes admin) +- Re-create users in LLDAP +- All Outline content will be empty (unless restored from backup) + +## Upgrading a Service + +### Procedure + +1. Check the current version in `inventory/group_vars/all.yml` +2. Look up the latest version on Docker Hub +3. Update the version variable +4. Run: `ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml` +5. Check logs for migration output: `docker compose logs --tail 50` +6. Verify the service is healthy + +### Example: upgrading Outline + +```bash +# In inventory/group_vars/all.yml, change: +# outline_version: "1.6.0" +# to: +# outline_version: "1.7.0" + +ansible-playbook -i inventory/hosts.yml playbooks/deploy.yml +``` + +## Troubleshooting + +### Service won't start + +```bash +ansible -i inventory/hosts.yml all -m ansible.builtin.shell \ + -a "cd /opt/services && docker compose logs --tail 50" +``` + +### SSL certificate not issued + +Caddy issues certs on first request. If a cert is missing: +1. Verify DNS resolves: `dig +short .cloud-elves.eu` +2. Check Caddy logs for ACME errors +3. Restart Caddy: `docker compose restart caddy` + +### Can't SSH to the box + +1. Check if DNS is stale: `dig +short box.cloud-elves.eu` +2. Flush DNS: `sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder` +3. If host key changed (rebuild): `ssh-keygen -R box.cloud-elves.eu` + +### Ansible can't connect + +1. Verify SSH works: `ssh -i ~/.ssh/id_ed25519_ce root@box.cloud-elves.eu` +2. Check known_hosts for stale entries +3. Run: `ansible -i inventory/hosts.yml all -m ping` diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml new file mode 100644 index 0000000..ee300ba --- /dev/null +++ b/inventory/group_vars/all.yml @@ -0,0 +1,34 @@ +# Primary domain — subdomains will be created off this +domain: "cloud-elves.eu" + +# Hostname for the server +server_hostname: "box" + +# Email for Let's Encrypt certificate notifications (used by Caddy automatically) +acme_email: "maarten@lambda-m.nl" + +# Docker image versions — pin these, update deliberately +gitea_version: "1.21" +postgres_version: "16-alpine" +outline_version: "1.6.0" +redis_version: "7-alpine" + +# LDAP base DN +ldap_base_dn: "dc=cloud-elves,dc=eu" + +# Gitea database password +gitea_db_password: "0cGpEZ0Ph2mdLbPJjA4kbR" + +# LLDAP secrets +lldap_jwt_secret: "371bc1a40f93dc2229fbaa5e080ac323" +lldap_key_seed: "1a5873dd243b29f60043d2e69ec9b7f7" +lldap_admin_password: "cio3LFvUwUzLhO6iMXTAbQPq" + +# Dex OIDC client secrets +dex_outline_client_secret: "6edfe427944e50856e65e87ebf62217389f72963e8e6fe16d19536f1d31ffb56" +dex_gitea_client_secret: "nWotT1z2AziFbmzscORURXlZ" + +# Outline secrets +outline_secret_key: "72a81e9516e29c249ad8543866b1275a34b6a15014527f81d1becab363c82fb4" +outline_utils_secret: "9219100ad29e330c0a7ea8032adc0c5831de14e487a7c3c5e050b757d022f5da" +outline_db_password: "oZEdt71Jd2zkto2qWKj1MI7K" diff --git a/inventory/hosts.yml b/inventory/hosts.yml new file mode 100644 index 0000000..ed0add0 --- /dev/null +++ b/inventory/hosts.yml @@ -0,0 +1,7 @@ +all: + hosts: + box: + ansible_host: box.cloud-elves.eu + ansible_user: root + ansible_ssh_private_key_file: ~/.ssh/id_ed25519_ce + ansible_python_interpreter: /usr/bin/python3 diff --git a/playbooks/bootstrap.yml b/playbooks/bootstrap.yml new file mode 100644 index 0000000..071531c --- /dev/null +++ b/playbooks/bootstrap.yml @@ -0,0 +1,9 @@ +--- +- name: Bootstrap and harden the VPS + hosts: all + become: true + roles: + - role: common + tags: [common] + - role: docker + tags: [docker] diff --git a/playbooks/deploy.yml b/playbooks/deploy.yml new file mode 100644 index 0000000..61ec99b --- /dev/null +++ b/playbooks/deploy.yml @@ -0,0 +1,7 @@ +--- +- name: Deploy services + hosts: all + become: true + roles: + - role: services + tags: [services] diff --git a/roles/common/handlers/main.yml b/roles/common/handlers/main.yml new file mode 100644 index 0000000..cad74d8 --- /dev/null +++ b/roles/common/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: Restart sshd + ansible.builtin.service: + name: ssh + state: restarted diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..caa1359 --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,127 @@ +--- +# Disable cloud-init so it never regenerates SSH keys or resets config on reboot +- name: Disable cloud-init + ansible.builtin.file: + path: /etc/cloud/cloud-init.disabled + state: touch + mode: "0644" + +- name: Find active cloud-init services + ansible.builtin.shell: systemctl list-unit-files 'cloud-*' --no-legend | awk '{print $1}' + register: cloud_init_services + changed_when: false + +- name: Stop cloud-init services + ansible.builtin.service: + name: "{{ item }}" + state: stopped + enabled: false + loop: "{{ cloud_init_services.stdout_lines }}" + when: cloud_init_services.stdout_lines | length > 0 + +# Set the hostname to match our inventory name +- name: Set hostname + ansible.builtin.hostname: + name: "{{ server_hostname }}" + +# Update /etc/hosts to include the new hostname +- name: Update /etc/hosts with hostname + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^127\.0\.1\.1' + line: "127.0.1.1 {{ server_hostname }}.{{ domain }} {{ server_hostname }}" + state: present + +# Refresh apt cache before installing anything +- name: Update apt cache + ansible.builtin.apt: + update_cache: true + cache_valid_time: 3600 + +# Upgrade all installed packages to latest +- name: Upgrade all packages + ansible.builtin.apt: + upgrade: dist + autoremove: true + +# Install essential tools and security packages +- name: Install base packages + ansible.builtin.apt: + name: + - curl + - git + - htop + - rsync + - ufw + - fail2ban + - unattended-upgrades + - apt-listchanges + state: present + +# Allow SSH before enabling the firewall (don't lock ourselves out) +- name: UFW — allow SSH + community.general.ufw: + rule: allow + port: "22" + proto: tcp + +# Allow HTTP for Caddy +- name: UFW — allow HTTP + community.general.ufw: + rule: allow + port: "80" + proto: tcp + +# Allow HTTPS for Caddy +- name: UFW — allow HTTPS + community.general.ufw: + rule: allow + port: "443" + proto: tcp + +# Allow Gitea SSH +- name: UFW — allow Gitea SSH + community.general.ufw: + rule: allow + port: "2222" + proto: tcp + +# Default deny incoming, allow outgoing, then enable +- name: UFW — enable with default deny incoming + community.general.ufw: + state: enabled + default: deny + direction: incoming + +- name: UFW — default allow outgoing + community.general.ufw: + default: allow + direction: outgoing + +# Enable automatic security updates +- name: Enable unattended-upgrades + ansible.builtin.copy: + dest: /etc/apt/apt.conf.d/20auto-upgrades + content: | + APT::Periodic::Update-Package-Lists "1"; + APT::Periodic::Unattended-Upgrade "1"; + APT::Periodic::AutocleanInterval "7"; + mode: "0644" + +# Disable root password login — key-only auth +- name: Disable SSH password authentication + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?PasswordAuthentication' + line: 'PasswordAuthentication no' + state: present + notify: Restart sshd + +# Disable root login via password (permit key-based only) +- name: Set SSH to permit root login with key only + ansible.builtin.lineinfile: + path: /etc/ssh/sshd_config + regexp: '^#?PermitRootLogin' + line: 'PermitRootLogin prohibit-password' + state: present + notify: Restart sshd diff --git a/roles/docker/tasks/main.yml b/roles/docker/tasks/main.yml new file mode 100644 index 0000000..332a957 --- /dev/null +++ b/roles/docker/tasks/main.yml @@ -0,0 +1,50 @@ +--- +# Install Docker prerequisites +- name: Install Docker dependencies + ansible.builtin.apt: + name: + - ca-certificates + - curl + - gnupg + state: present + +# Add Docker's official GPG key +- name: Create keyrings directory + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + +- name: Add Docker GPG key + ansible.builtin.get_url: + url: https://download.docker.com/linux/debian/gpg + dest: /etc/apt/keyrings/docker.asc + mode: "0644" + +# Add Docker apt repository for Debian +- name: Add Docker apt repository + ansible.builtin.apt_repository: + repo: >- + deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] + https://download.docker.com/linux/debian + {{ ansible_facts['distribution_release'] }} stable + state: present + filename: docker + +# Install Docker Engine + Compose plugin +- name: Install Docker Engine + ansible.builtin.apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-compose-plugin + state: present + update_cache: true + +# Ensure Docker service is running and enabled at boot +- name: Enable and start Docker + ansible.builtin.service: + name: docker + state: started + enabled: true diff --git a/roles/services/tasks/main.yml b/roles/services/tasks/main.yml new file mode 100644 index 0000000..b89d593 --- /dev/null +++ b/roles/services/tasks/main.yml @@ -0,0 +1,157 @@ +--- +# Create the services directory on the host +- name: Create services directory + ansible.builtin.file: + path: /opt/services + state: directory + mode: "0755" + +# Create a placeholder index page for the static site +- name: Create www directory + ansible.builtin.file: + path: /opt/www + state: directory + mode: "0755" + +- name: Create placeholder index.html + ansible.builtin.copy: + dest: /opt/www/index.html + content: | + + + Cloud Elves +

cloud-elves.eu

Coming soon.

+ + mode: "0644" + force: false + +# Template config files +- name: Deploy Caddyfile + ansible.builtin.template: + src: Caddyfile.j2 + dest: /opt/services/Caddyfile + mode: "0644" + register: caddyfile_changed + +- name: Deploy Dex config + ansible.builtin.template: + src: dex-config.yml.j2 + dest: /opt/services/dex-config.yml + mode: "0644" + +# Check if we already have a runner token saved +- name: Check for existing runner token + ansible.builtin.stat: + path: /opt/services/.runner-token + register: runner_token_file + +# Use a placeholder token for first deploy (runner won't start yet) +- name: Set runner token from file if exists + ansible.builtin.slurp: + src: /opt/services/.runner-token + register: runner_token_content + when: runner_token_file.stat.exists + +- name: Set runner token variable + ansible.builtin.set_fact: + gitea_runner_token: "{{ runner_token_content.content | b64decode | trim }}" + when: runner_token_file.stat.exists + +- name: Set placeholder runner token for first deploy + ansible.builtin.set_fact: + gitea_runner_token: "placeholder" + when: not runner_token_file.stat.exists + +# Deploy compose file +- name: Deploy docker-compose.yml + ansible.builtin.template: + src: docker-compose.yml.j2 + dest: /opt/services/docker-compose.yml + mode: "0644" + +# Start everything (runner will fail to register with placeholder token — that's OK) +- name: Start all services + ansible.builtin.command: + cmd: docker compose up -d --remove-orphans + chdir: /opt/services + changed_when: true + +# Reload Caddy if Caddyfile changed (zero-downtime) +- name: Reload Caddy config + ansible.builtin.command: + cmd: docker compose exec -T caddy caddy reload --config /etc/caddy/Caddyfile + chdir: /opt/services + when: caddyfile_changed.changed + changed_when: true + +# Wait for Gitea to be ready +- name: Wait for Gitea to be ready + ansible.builtin.command: + cmd: docker compose exec -T -u git gitea gitea admin user list + chdir: /opt/services + register: gitea_ready + retries: 10 + delay: 5 + until: gitea_ready.rc == 0 + changed_when: false + +# --- Gitea OIDC setup --- + +- name: Check if Dex auth source exists in Gitea + ansible.builtin.shell: + cmd: docker compose exec -T -u git gitea gitea admin auth list 2>&1 | grep -q dex + chdir: /opt/services + register: gitea_auth_check + changed_when: false + failed_when: false + +- name: Add Dex OIDC auth source to Gitea + ansible.builtin.command: + cmd: > + docker compose exec -T -u git gitea gitea admin auth add-oauth + --name dex + --provider openidConnect + --key gitea + --secret {{ dex_gitea_client_secret }} + --auto-discover-url https://auth.{{ domain }}/.well-known/openid-configuration + --scopes "openid profile email" + chdir: /opt/services + when: gitea_auth_check.rc != 0 + changed_when: true + +# --- Gitea Actions runner setup --- + +- name: Generate runner registration token + ansible.builtin.shell: + cmd: docker compose exec -T -u git gitea gitea actions generate-runner-token 2>/dev/null + chdir: /opt/services + register: runner_token_result + changed_when: false + when: not runner_token_file.stat.exists + +- name: Save runner token + ansible.builtin.copy: + content: "{{ runner_token_result.stdout | trim }}" + dest: /opt/services/.runner-token + mode: "0600" + when: not runner_token_file.stat.exists + +# Re-template compose with real token and restart runner +- name: Set real runner token + ansible.builtin.set_fact: + gitea_runner_token: "{{ runner_token_result.stdout | trim }}" + when: not runner_token_file.stat.exists + +- name: Re-deploy docker-compose with real runner token + ansible.builtin.template: + src: docker-compose.yml.j2 + dest: /opt/services/docker-compose.yml + mode: "0644" + when: not runner_token_file.stat.exists + +- name: Restart runner with real token + ansible.builtin.command: + cmd: docker compose up -d --remove-orphans + chdir: /opt/services + when: not runner_token_file.stat.exists + changed_when: true diff --git a/roles/services/templates/Caddyfile.j2 b/roles/services/templates/Caddyfile.j2 new file mode 100644 index 0000000..cc040ea --- /dev/null +++ b/roles/services/templates/Caddyfile.j2 @@ -0,0 +1,29 @@ +{ + email {{ acme_email }} +} + +# Gitea +git.{{ domain }} { + reverse_proxy gitea:3000 +} + +# LLDAP web UI +ldap.{{ domain }} { + reverse_proxy lldap:17170 +} + +# Dex OIDC provider +auth.{{ domain }} { + reverse_proxy dex:5556 +} + +# Outline wiki +docs.{{ domain }} { + reverse_proxy outline:3000 +} + +# Static site +{{ domain }}, www.{{ domain }} { + root * /srv/www + file_server +} diff --git a/roles/services/templates/dex-config.yml.j2 b/roles/services/templates/dex-config.yml.j2 new file mode 100644 index 0000000..e6c5fe9 --- /dev/null +++ b/roles/services/templates/dex-config.yml.j2 @@ -0,0 +1,51 @@ +# Dex OIDC provider configuration +issuer: https://auth.{{ domain }} + +storage: + type: sqlite3 + config: + file: /var/dex/dex.db + +web: + http: 0.0.0.0:5556 + +connectors: + - type: ldap + id: lldap + name: LLDAP + config: + host: lldap:3890 + insecureNoSSL: true + bindDN: uid=admin,ou=people,{{ ldap_base_dn }} + bindPW: "{{ lldap_admin_password }}" + userSearch: + baseDN: ou=people,{{ ldap_base_dn }} + filter: "(objectClass=person)" + username: uid + idAttr: uid + emailAttr: mail + nameAttr: displayName + preferredUsernameAttr: uid + groupSearch: + baseDN: ou=groups,{{ ldap_base_dn }} + filter: "(objectClass=groupOfUniqueNames)" + userMatchers: + - userAttr: DN + groupAttr: uniqueMember + nameAttr: cn + +staticClients: + - id: outline + name: Outline + secret: "{{ dex_outline_client_secret }}" + redirectURIs: + - https://docs.{{ domain }}/auth/oidc.callback + + - id: gitea + name: Gitea + secret: "{{ dex_gitea_client_secret }}" + redirectURIs: + - https://git.{{ domain }}/user/oauth2/dex/callback + +oauth2: + skipApprovalScreen: true diff --git a/roles/services/templates/docker-compose.yml.j2 b/roles/services/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..3933689 --- /dev/null +++ b/roles/services/templates/docker-compose.yml.j2 @@ -0,0 +1,182 @@ +# /opt/services/docker-compose.yml +# All services for box.cloud-elves.eu + +services: + + # --- Reverse Proxy --- + + caddy: + image: caddy:2 + restart: unless-stopped + ports: + - "80:80" + - "443:443" + - "443:443/udp" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile:ro + - caddy-data:/data + - caddy-config:/config + # Static site served from host directory + - /opt/www:/srv/www:ro + networks: + - frontend + + # --- Identity --- + + lldap: + image: lldap/lldap:stable + restart: unless-stopped + environment: + - LLDAP_JWT_SECRET={{ lldap_jwt_secret }} + - LLDAP_KEY_SEED={{ lldap_key_seed }} + - LLDAP_LDAP_USER_PASS={{ lldap_admin_password }} + - LLDAP_LDAP_BASE_DN={{ ldap_base_dn }} + - LLDAP_HTTP_URL=https://ldap.{{ domain }} + volumes: + - lldap-data:/data + networks: + - frontend + - identity + + dex: + image: dexidp/dex:latest + restart: unless-stopped + command: ["dex", "serve", "/etc/dex/config.yaml"] + volumes: + - ./dex-config.yml:/etc/dex/config.yaml:ro + - dex-data:/var/dex + networks: + - frontend + - identity + depends_on: + - lldap + + # --- Gitea --- + + gitea: + image: gitea/gitea:{{ gitea_version }} + restart: unless-stopped + ports: + # Gitea SSH on host port 2222 + - "2222:22" + environment: + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=gitea-db:5432 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD={{ gitea_db_password }} + - GITEA__server__DOMAIN=git.{{ domain }} + - GITEA__server__SSH_DOMAIN=git.{{ domain }} + - GITEA__server__SSH_PORT=2222 + - GITEA__server__ROOT_URL=https://git.{{ domain }}/ + # Auto-create Gitea accounts on first SSO login + - GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=true + - GITEA__oauth2_client__ENABLE_AUTO_REGISTRATION=true + - GITEA__oauth2_client__ACCOUNT_LINKING=auto + # Enable Gitea Actions + - GITEA__actions__ENABLED=true + volumes: + - gitea-data:/data + - /etc/localtime:/etc/localtime:ro + networks: + - frontend + - gitea-backend + depends_on: + - gitea-db + + gitea-db: + image: postgres:{{ postgres_version }} + restart: unless-stopped + environment: + - POSTGRES_DB=gitea + - POSTGRES_USER=gitea + - POSTGRES_PASSWORD={{ gitea_db_password }} + volumes: + - gitea-db:/var/lib/postgresql/data + networks: + - gitea-backend + + # --- Gitea Runner --- + + gitea-runner: + image: gitea/act_runner:latest + restart: unless-stopped + environment: + - GITEA_INSTANCE_URL=http://gitea:3000 + - GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_token }} + - GITEA_RUNNER_NAME=box-runner + volumes: + # Runner needs Docker socket to spin up job containers + - /var/run/docker.sock:/var/run/docker.sock + - gitea-runner-data:/data + networks: + - frontend + depends_on: + - gitea + + # --- Outline --- + + outline: + image: outlinewiki/outline:{{ outline_version }} + restart: unless-stopped + environment: + - URL=https://docs.{{ domain }} + - SECRET_KEY={{ outline_secret_key }} + - UTILS_SECRET={{ outline_utils_secret }} + - DATABASE_URL=postgres://outline:{{ outline_db_password }}@outline-db:5432/outline + - PGSSLMODE=disable + - REDIS_URL=redis://outline-redis:6379 + - FILE_STORAGE=local + - FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data + - FORCE_HTTPS=false + - OIDC_CLIENT_ID=outline + - OIDC_CLIENT_SECRET={{ dex_outline_client_secret }} + - OIDC_AUTH_URI=https://auth.{{ domain }}/auth + - OIDC_TOKEN_URI=https://auth.{{ domain }}/token + - OIDC_USERINFO_URI=https://auth.{{ domain }}/userinfo + - OIDC_DISPLAY_NAME=Cloud Elves SSO + - OIDC_SCOPES=openid profile email offline_access + volumes: + - outline-data:/var/lib/outline/data + networks: + - frontend + - outline-backend + depends_on: + - outline-db + - outline-redis + - dex + + outline-db: + image: postgres:{{ postgres_version }} + restart: unless-stopped + environment: + - POSTGRES_DB=outline + - POSTGRES_USER=outline + - POSTGRES_PASSWORD={{ outline_db_password }} + volumes: + - outline-db:/var/lib/postgresql/data + networks: + - outline-backend + + outline-redis: + image: redis:{{ redis_version }} + restart: unless-stopped + networks: + - outline-backend + +networks: + frontend: + identity: + gitea-backend: + outline-backend: + +volumes: + caddy-data: + caddy-config: + lldap-data: + dex-data: + gitea-data: + gitea-db: + gitea-runner-data: + outline-data: + outline-db: diff --git a/scripts/backup.sh b/scripts/backup.sh new file mode 100755 index 0000000..673cefa --- /dev/null +++ b/scripts/backup.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# backup.sh — Create a full backup of all Cloud Elves services +# +# Usage: ./scripts/backup.sh [destination_dir] +# +# Creates a timestamped tarball containing volume-level backups of all services. +# Run from the ce-infra repo root directory. +# Requires SSH access to box.cloud-elves.eu as root. + +set -euo pipefail + +HOST="root@box.cloud-elves.eu" +SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_ce}" +SSH="ssh -i $SSH_KEY $HOST" +SCP="scp -i $SSH_KEY" +TIMESTAMP=$(date +%Y%m%d-%H%M%S) +DEST_DIR="${1:-./backups}" +BACKUP_NAME="ce-backup-${TIMESTAMP}" +REMOTE_TMP="/tmp/${BACKUP_NAME}" + +echo "=== Cloud Elves Backup — ${TIMESTAMP} ===" +echo "" + +# Create local destination +mkdir -p "${DEST_DIR}" + +# Create remote temp directory +echo "[1/7] Preparing..." +$SSH "mkdir -p ${REMOTE_TMP}" + +# Stop services for consistent backup (databases stay up for pg_dump) +echo "[2/7] Stopping application services for consistent backup..." +$SSH "cd /opt/services && docker compose stop gitea outline dex lldap gitea-runner caddy" + +# Gitea: pg_dump + data volume +echo "[3/7] Backing up Gitea (database + data)..." +$SSH "cd /opt/services && docker compose exec -T gitea-db pg_dump -U gitea gitea | gzip > ${REMOTE_TMP}/gitea-db.sql.gz" +$SSH "docker run --rm -v services_gitea-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/gitea-data.tar.gz -C /data ." + +# Outline: pg_dump + data volume +echo "[4/7] Backing up Outline (database + uploads)..." +$SSH "cd /opt/services && docker compose exec -T outline-db pg_dump -U outline outline | gzip > ${REMOTE_TMP}/outline-db.sql.gz" +$SSH "docker run --rm -v services_outline-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/outline-data.tar.gz -C /data ." + +# LLDAP: SQLite volume +echo "[5/7] Backing up LLDAP (user directory)..." +$SSH "docker run --rm -v services_lldap-data:/data -v ${REMOTE_TMP}:/backup alpine tar czf /backup/lldap-data.tar.gz -C /data ." + +# Dex: SQLite volume +echo "[6/7] Backing up Dex (auth database)..." +$SSH "docker run --rm -v services_dex-data:/dex -v ${REMOTE_TMP}:/backup alpine tar czf /backup/dex-data.tar.gz -C /dex ." + +# Restart services +echo "[7/7] Restarting services..." +$SSH "cd /opt/services && docker compose up -d" + +# Bundle everything and download +echo "" +echo "Downloading backup..." +$SSH "cd /tmp && tar cf ${BACKUP_NAME}.tar -C ${REMOTE_TMP} ." +$SCP "${HOST}:/tmp/${BACKUP_NAME}.tar" "${DEST_DIR}/${BACKUP_NAME}.tar" + +# Clean up remote +$SSH "rm -rf ${REMOTE_TMP} /tmp/${BACKUP_NAME}.tar" + +# Show result +BACKUP_SIZE=$(du -h "${DEST_DIR}/${BACKUP_NAME}.tar" | cut -f1) +echo "" +echo "=== Backup complete ===" +echo "File: ${DEST_DIR}/${BACKUP_NAME}.tar (${BACKUP_SIZE})" +echo "" +echo "Contents:" +tar tf "${DEST_DIR}/${BACKUP_NAME}.tar" | sed 's/^/ /' +echo "" +echo "Downtime was ~30 seconds while services were stopped for consistency." diff --git a/scripts/restore.sh b/scripts/restore.sh new file mode 100755 index 0000000..f21fa26 --- /dev/null +++ b/scripts/restore.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash +# restore.sh — Restore Cloud Elves services from a backup +# +# Usage: ./scripts/restore.sh +# +# Prerequisites: +# - Target server already bootstrapped: ansible-playbook playbooks/bootstrap.yml +# - Services already deployed: ansible-playbook playbooks/deploy.yml +# - This script stops services, replaces data, and restarts +# +# Run from the ce-infra repo root directory. +# Requires SSH access to box.cloud-elves.eu as root. + +set -euo pipefail + +if [ $# -eq 0 ]; then + echo "Usage: $0 " + echo "Example: $0 ./backups/ce-backup-20260317-180000.tar" + exit 1 +fi + +BACKUP_FILE="$1" +HOST="root@box.cloud-elves.eu" +SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_ce}" +SSH="ssh -i $SSH_KEY $HOST" +SCP="scp -i $SSH_KEY" +REMOTE_TMP="/tmp/ce-restore" + +if [ ! -f "${BACKUP_FILE}" ]; then + echo "Error: Backup file not found: ${BACKUP_FILE}" + exit 1 +fi + +echo "=== Cloud Elves Restore ===" +echo "Backup: ${BACKUP_FILE}" +echo "" +echo "Contents:" +tar tf "${BACKUP_FILE}" | sed 's/^/ /' +echo "" +echo "WARNING: This will stop all services and replace their data." +echo "Press Enter to continue, Ctrl+C to abort." +read -r + +# Upload backup +echo "[1/7] Uploading backup to server..." +$SSH "mkdir -p ${REMOTE_TMP}" +$SCP "${BACKUP_FILE}" "${HOST}:${REMOTE_TMP}/backup.tar" +$SSH "cd ${REMOTE_TMP} && tar xf backup.tar && rm backup.tar" + +# Stop all services +echo "[2/7] Stopping all services..." +$SSH "cd /opt/services && docker compose down" + +# Restore LLDAP volume +echo "[3/7] Restoring LLDAP (user directory)..." +$SSH "docker volume rm services_lldap-data 2>/dev/null || true && docker volume create services_lldap-data" +$SSH "docker run --rm -v services_lldap-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/lldap-data.tar.gz -C /data" + +# Restore Dex volume +echo "[4/7] Restoring Dex (auth database)..." +$SSH "docker volume rm services_dex-data 2>/dev/null || true && docker volume create services_dex-data" +$SSH "docker run --rm -v services_dex-data:/dex -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/dex-data.tar.gz -C /dex" + +# Restore Gitea data volume +echo "[5/7] Restoring Gitea (data + database)..." +$SSH "docker volume rm services_gitea-data 2>/dev/null || true && docker volume create services_gitea-data" +$SSH "docker run --rm -v services_gitea-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/gitea-data.tar.gz -C /data" + +# Start databases only so we can restore into them +$SSH "cd /opt/services && docker compose up -d gitea-db outline-db" +echo " Waiting for databases to start..." +sleep 5 + +# Restore Gitea database +$SSH "cd /opt/services && docker compose exec -T gitea-db dropdb -U gitea --if-exists gitea" +$SSH "cd /opt/services && docker compose exec -T gitea-db createdb -U gitea gitea" +$SSH "gunzip -c ${REMOTE_TMP}/gitea-db.sql.gz | docker compose -f /opt/services/docker-compose.yml exec -T gitea-db psql -U gitea gitea" + +# Restore Outline data volume +echo "[6/7] Restoring Outline (uploads + database)..." +$SSH "docker volume rm services_outline-data 2>/dev/null || true && docker volume create services_outline-data" +$SSH "docker run --rm -v services_outline-data:/data -v ${REMOTE_TMP}:/backup alpine tar xzf /backup/outline-data.tar.gz -C /data" + +# Restore Outline database +$SSH "cd /opt/services && docker compose exec -T outline-db dropdb -U outline --if-exists outline" +$SSH "cd /opt/services && docker compose exec -T outline-db createdb -U outline outline" +$SSH "gunzip -c ${REMOTE_TMP}/outline-db.sql.gz | docker compose -f /opt/services/docker-compose.yml exec -T outline-db psql -U outline outline" + +# Start everything +echo "[7/7] Starting all services..." +$SSH "cd /opt/services && docker compose up -d" + +# Wait for Gitea and regenerate hooks +echo " Waiting for services to start..." +sleep 10 + +echo " Regenerating Gitea hooks..." +$SSH "cd /opt/services && docker compose exec -T -u git gitea gitea admin regenerate hooks" || echo " (no repos to regenerate hooks for)" + +# Clean up +$SSH "rm -rf ${REMOTE_TMP}" + +echo "" +echo "=== Restore complete ===" +echo "" +echo "Please verify:" +echo " - https://ldap.cloud-elves.eu — LLDAP (users should be there)" +echo " - https://auth.cloud-elves.eu — Dex (SSO should work)" +echo " - https://git.cloud-elves.eu — Gitea (repos, users)" +echo " - https://docs.cloud-elves.eu — Outline (documents)" +echo " - https://cloud-elves.eu — Static site (deploy via rsync separately)" +echo "" +echo "Note: Users will need to log in again (SSO sessions were reset)."