Files
server_cloud_ladkau_de/docs/runbook.md
T
ml 75a0f21f74 Implemented all service roles
- docker: install Docker Engine from official apt repo, configure log rotation,
  create shared traefik_public network
- traefik: reverse proxy with automatic Let's Encrypt TLS, dashboard on
  cloud.ladkau.de behind basic auth
- gitea: self-hosted Git with PostgreSQL, Git-over-SSH on port 2222
- sso: Keycloak with PostgreSQL for OIDC/OAuth2 single sign-on
- nextcloud: file storage with PostgreSQL, Redis, cron sidecar, CalDAV/CardDAV
  well-known redirects
- mail: Roundcube webmail client with PostgreSQL
- registry: Docker Registry v2 with htpasswd auth, no upload size limit
- k8s: placeholder nginx page

All secrets documented in vault.yml; runbook updated with per-service
first-run notes.
2026-06-27 15:35:15 +02:00

158 lines
4.0 KiB
Markdown

# Reinstall Runbook
Follow these steps to provision a fresh server from scratch.
## Prerequisites
On your local machine:
- Ansible installed (`pip install ansible`)
- SSH access to the server as root using `keys/root_cloud_ladkau_de`
## Steps
### 1. Install Ansible collections
From the repo root:
```bash
ansible-galaxy collection install -r ansible/requirements.yml
```
Required collections:
- `community.general` — ufw, timezone modules
- `ansible.posix` — authorized_key module
### 2. Initial root login
Connect as root and verify the server is reachable:
```
ssh -i keys/root_cloud_ladkau_de root@217.154.207.148
```
### 3. Create the deploy user (one-time, manual)
On the server as root:
```bash
adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
cat >> /home/deploy/.ssh/authorized_keys <<'EOF'
<paste contents of keys/notroot_cloud_ladkau_de.pub>
EOF
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
```
### 4. Set secrets (Ansible Vault)
Before running the playbook, populate secrets that must not be committed in plain text.
Create `ansible/group_vars/vault.yml` (gitignored) and encrypt it with Ansible Vault:
```bash
ansible-vault create ansible/group_vars/vault.yml
```
Required secrets:
```yaml
# Traefik dashboard basic auth — generate with:
# echo $(htpasswd -nB admin) | sed -e 's/\$/\$\$/g'
traefik_dashboard_users: "admin:$$2y$$05$$..."
# Gitea — generate secrets with: openssl rand -hex 32
gitea_db_password: ""
gitea_secret_key: ""
gitea_internal_token: ""
# Keycloak
keycloak_db_password: ""
keycloak_admin_password: ""
# Nextcloud
nextcloud_db_password: ""
nextcloud_admin_password: ""
# Roundcube — des_key must be exactly 24 characters: openssl rand -hex 12
roundcube_db_password: ""
roundcube_des_key: ""
# Container registry — generate with:
# docker run --entrypoint htpasswd httpd:2 -Bbn <user> <password>
registry_htpasswd: "user:$2y$05$..."
```
**Registry usage after deploy:**
```bash
# Login
docker login cr.ladkau.de
# Push an image
docker tag myimage:latest cr.ladkau.de/myimage:latest
docker push cr.ladkau.de/myimage:latest
# Pull an image
docker pull cr.ladkau.de/myimage:latest
```
**Gitea first-run note:** `gitea_disable_registration` defaults to `true` in
`group_vars/all.yml`. For the very first deploy, override it to `false` in
`vault.yml` so the Gitea setup wizard can create the admin account. After
the admin account exists, remove the override and redeploy.
**Keycloak first-run note:** The `KEYCLOAK_ADMIN` / `KEYCLOAK_ADMIN_PASSWORD`
environment variables bootstrap the initial admin account on first start only.
After logging in at `https://sso.ladkau.de`, change the admin password via the
Keycloak UI and remove the `keycloak_admin_password` reference from vault (or
rotate it). Keycloak ignores these env vars once the admin account already exists.
To run the playbook with vault:
```bash
ansible-playbook -i ansible/inventory.ini ansible/site.yml --ask-vault-pass
```
### 5. Run the Ansible master playbook
From the repo root:
```bash
ansible-playbook -i ansible/inventory.ini ansible/site.yml
```
This runs all roles in order:
1. `base` — OS hardening, SSH config, ufw firewall
2. `docker` — Docker Engine + Compose plugin
3. `traefik` — reverse proxy, TLS via Let's Encrypt
4. `gitea` — self-hosted Git
5. `nextcloud` — file storage
6. `sso` — Single Sign-On
7. `mail` — mail server
8. `registry` — container registry
9. `k8s` — k3s node
### 6. DNS
Ensure the following DNS A records point to `217.154.207.148` before running:
- cloud.ladkau.de
- gitea.ladkau.de
- nextcloud.ladkau.de
- sso.ladkau.de
- mail.ladkau.de
- cr.ladkau.de
- k8s.ladkau.de
Traefik will attempt ACME certificate issuance on first start; DNS must resolve first.
## Re-running after changes
The playbook is idempotent. To apply a single role only:
```bash
ansible-playbook -i ansible/inventory.ini ansible/site.yml --tags <role>
```