# Configuration Runbook First-run configuration steps to perform after the Ansible playbook has provisioned the server. See `runbook-provisioning.md` for the provisioning steps. ## 1. Verify all services are reachable Before configuring individual services, confirm every HTTPS endpoint is up and TLS certificates are valid. Run this from your local machine: ```bash bash scripts/check-services.sh ``` The script checks these endpoints and verifies the expected HTTP status code: | URL | Expected | Notes | |-----|----------|-------| | `https://cloud.ladkau.de/dashboard/` | 401 | Basic-auth prompt — correct without credentials | | `https://gitea.ladkau.de` | 200 | Gitea sign-in page | | `https://nextcloud.ladkau.de` | 200 | First visit triggers setup and takes 1–2 min | | `https://sso.ladkau.de/realms/master` | 200 | Keycloak realm JSON — first start takes ~90 s | | `https://mail.ladkau.de` | 200 | Roundcube webmail login | | `https://cr.ladkau.de/v2/` | 401 | Registry API — auth required, correct without credentials | | `https://k8s.ladkau.de` | 200 | Placeholder page | | `https://vault.ladkau.de` | 200 | Vaultwarden web vault | | `https://dl.ladkau.de` | 200 | Public download server | A `000` result means the connection was refused or timed out — a container that did not start. Keycloak and Nextcloud may return `502` for up to 90 seconds on first boot; wait and retry before investigating. Once the script passes, open `https://cloud.ladkau.de/dashboard/` in a browser and authenticate with the `traefik_dashboard_users` credentials to verify the dashboard loads correctly. ## 2. Keycloak Keycloak is the identity provider for all services. Configure it first so that Gitea and Nextcloud can be wired up to SSO in the steps that follow. Keycloak takes ~90 seconds to start on first boot. If the login page at `https://sso.ladkau.de` is not immediately available, wait and retry. ### 2.1 Log in and change the admin password 1. Go to `https://sso.ladkau.de` and sign in with username `admin` and the value of `keycloak_admin_password` from the vault. 2. Click the **admin** dropdown (top right) → **Manage account** → **Password** → set a new password. The bootstrap credentials are only used on first start. After changing the password, the vault value is no longer authoritative — store the new password in your password manager. ### 2.2 Create an application realm 1. In the left sidebar, click the realm dropdown (shows **master**) → **Create realm**. 2. Set **Realm name** to `ladkau` and click **Create**. 3. Make sure the `ladkau` realm is selected in the sidebar for all steps below. The `master` realm is for Keycloak administration only. All application users and clients live in `ladkau`. ### 2.3 Create users For each user you want to be able to log in to Gitea and Nextcloud: 1. **Users** → **Add user**. 2. Fill in **Username**, **Email**, **First name**, **Last name** → **Create**. 3. Go to the **Credentials** tab → **Set password**. 4. Enter a password, turn off **Temporary**, and click **Save**. ### 2.4 Create the Gitea OIDC client 1. **Clients** → **Create client**. 2. **Client type**: OpenID Connect — **Client ID**: `gitea` → **Next**. 3. Turn **Client authentication** on (confidential client) → **Next**. 4. **Valid redirect URIs**: `https://gitea.ladkau.de/user/oauth2/keycloak/callback` 5. **Web origins**: `https://gitea.ladkau.de` → **Save**. 6. Go to the **Credentials** tab and copy the **Client secret** — you will need it in step 3. ### 2.5 Create the Nextcloud OIDC client 1. **Clients** → **Create client**. 2. **Client type**: OpenID Connect — **Client ID**: `nextcloud` → **Next**. 3. Turn **Client authentication** on → **Next**. 4. **Valid redirect URIs**: `https://nextcloud.ladkau.de/apps/user_oidc/code` 5. **Valid post logout redirect URIs**: `https://nextcloud.ladkau.de/*` 6. **Web origins**: `https://nextcloud.ladkau.de` → **Save**. 7. Go to the **Credentials** tab and copy the **Client secret** — you will need it in step 4. ### 2.6 Create the Vaultwarden OIDC client 1. **Clients** → **Create client**. 2. **Client type**: OpenID Connect — **Client ID**: `vaultwarden` → **Next**. 3. Turn **Client authentication** on → **Next**. 4. **Valid redirect URIs**: `https://vault.ladkau.de/*` 5. **Valid post logout redirect URIs**: `https://vault.ladkau.de/*` 6. **Web origins**: `https://vault.ladkau.de` → **Save**. 7. Go to the **Credentials** tab and copy the **Client secret**. 8. Add it to the vault as `vaultwarden_sso_client_secret` and redeploy: ```bash ansible-vault edit ansible/group_vars/all/vault.yml ansible-playbook -i ansible/inventory.ini ansible/site.yml --tags vaultwarden --ask-vault-pass ``` ## 3. Gitea ### 3.1 Create the admin account 1. Go to `https://gitea.ladkau.de` — Gitea shows an initial configuration dialog on the first visit. 2. Scroll to the bottom of the form to the **Administrator Account Settings** section and fill in the admin username, email, and password. 3. Click **Install Gitea**. Gitea initialises the database and creates the admin account in one step. Public registration is closed — only users authenticating via Keycloak can get an account (controlled by `ALLOW_ONLY_EXTERNAL_REGISTRATION`). ### 3.2 Connect Gitea to Keycloak 1. In Gitea, go to **Site Administration** → **Identity & Access** → **Authentication Sources** → **Add Authentication Source**. 2. Set **Authentication type** to **OAuth2**. 3. Set **OAuth2 provider** to **OpenID Connect**. 4. Fill in: - **Name**: `keycloak` - **Client ID**: `gitea` - **Client secret**: the secret copied in step 2.4 - **OpenID Connect Auto Discovery URL**: `https://sso.ladkau.de/realms/ladkau/.well-known/openid-configuration` 5. Click **Add Authentication Source**. Users can now sign in via **Sign in with keycloak** on the Gitea login page. ### 3.3 Use SSH key authentication for Git Gitea exposes SSH on port **2222** (host port mapped from the container's port 22). Clone URLs use the full `ssh://` form because the port is non-standard. **Generate an SSH key** If you do not already have a key, generate a dedicated one for Gitea: ```bash ssh-keygen -t ed25519 -C "gitea.ladkau.de" -f ~/.ssh/id_ed25519_gitea ``` Leave the passphrase empty for unattended use, or set one for additional security. The command creates two files: - `~/.ssh/id_ed25519_gitea` — private key (never share this) - `~/.ssh/id_ed25519_gitea.pub` — public key (upload this to Gitea) **Add your key to Gitea** 1. Go to `https://gitea.ladkau.de` → click your avatar (top right) → **Settings** → **SSH / GPG Keys** → **Add Key**. 2. Paste the contents of `~/.ssh/id_ed25519_gitea.pub`. 3. Click **Add Key**. **Test the connection** ```bash ssh -p 2222 -i ~/.ssh/id_ed25519_gitea -T git@gitea.ladkau.de ``` A successful response looks like: ``` Hi ! You've successfully authenticated, but Gitea does not provide shell access. ``` **Clone, push, and pull** Gitea shows the correct SSH URL on every repository page. It takes the form: ``` ssh://git@gitea.ladkau.de:2222//.git ``` ```bash # Clone git clone ssh://git@gitea.ladkau.de:2222//myrepo.git # Add remote on an existing repo git remote add origin ssh://git@gitea.ladkau.de:2222//myrepo.git ``` **Optional: SSH config alias** Add this to `~/.ssh/config` to avoid repeating the port: ``` Host gitea.ladkau.de User git Port 2222 IdentityFile ~/.ssh/id_ed25519_gitea ``` With the alias in place you can use the shorter SCP-like URL: ```bash git clone git@gitea.ladkau.de:/myrepo.git ``` ### 3.4 Deploy Gitea Actions runners Three `act_runner` containers (Docker executor) are provisioned by the `act_runner` Ansible role. Each runner handles one concurrent job; together they allow up to three parallel workflow jobs. **This step requires Gitea to be running and the admin account to exist (step 3.1). Runners cannot register until a token is obtained from Gitea.** **Step 1 — Get a runner registration token** 1. Go to `https://gitea.ladkau.de` → sign in as admin. 2. Navigate to **Site Administration** (top-right menu) → **Actions** → **Runners**. 3. Click **Create runner token** and copy the token. **Step 2 — Add the token to the vault** ```bash ansible-vault edit ansible/group_vars/all/vault.yml ``` Add the key: ```yaml gitea_runner_registration_token: "" ``` **Step 3 — Deploy the runners** ```bash ansible-playbook -i ansible/inventory.ini ansible/site.yml \ --tags act_runner --ask-vault-pass ``` Ansible creates `/opt/act_runner/` with a shared `config.yml` and three per-runner data directories (`runner-1/`, `runner-2/`, `runner-3/`). On first start each container auto-registers with Gitea and writes a `.runner` file to its data directory. Subsequent restarts reuse the saved registration. **Verify** Back in Gitea **Site Administration → Actions → Runners**, all three runners should appear as **Online** within a few seconds. > **Security note:** Each runner container mounts `/var/run/docker.sock`. > This gives workflow jobs root-equivalent access to the host Docker daemon. > Only run workflows from trusted repositories. ## 4. Nextcloud The admin credentials are set via `nextcloud_admin_user` and `nextcloud_admin_password` in the vault. The first HTTP request triggers installation, which takes a minute or two. ### 4.1 Log in 1. Go to `https://nextcloud.ladkau.de` and sign in with the admin credentials from the vault. ### 4.2 Connect Nextcloud to Keycloak 1. Go to **Apps** → search for **OpenID Connect user backend** → **Download and enable**. 2. Go to **Administration settings** → **OpenID Connect** → **Add provider**. 3. Fill in: - **Identifier**: `keycloak` - **Client ID**: `nextcloud` - **Client secret**: the secret copied in step 2.5 - **Discovery endpoint**: `https://sso.ladkau.de/realms/ladkau/.well-known/openid-configuration` 4. Click **Save**. Users can now sign in to Nextcloud with their Keycloak credentials via the **Log in with keycloak** button. ## 5. Mail (Dovecot + Roundcube + Fetchmail) The mail stack runs a local Dovecot IMAP server. Roundcube connects to it internally. External IMAP clients connect to `mail.ladkau.de:993` (IMAPS — TLS terminated by Traefik). Fetchmail polls external POP3 accounts and delivers to Dovecot. Dovecot users and fetchmail accounts are configured in the vault before provisioning — see step 4 of `runbook-provisioning.md`. To add users or accounts after initial deployment, edit the vault and redeploy: ```bash ansible-vault edit ansible/group_vars/all/vault.yml ansible-playbook -i ansible/inventory.ini ansible/site.yml --tags mail --ask-vault-pass ``` ### 5.1 Import mail from an old Dovecot server If the old server uses **Maildir** format, rsync directly: ```bash # Run on the old server — syncs to the new server's maildir volume rsync -av -e "ssh -i keys/root_cloud_ladkau_de" --progress ./* \ root@217.154.207.148:/opt/mail/maildir/alice/Maildir/ # Fix ownership for Dovecot's vmail user (UID 5000) ssh -i keys/root_cloud_ladkau_de root@217.154.207.148 "chown -R 5000:5000 /opt/mail/maildir/alice" ``` If the old server uses **mbox** format (e.g. `mail_location = mbox:~/mail:...`), see `runbook-mail-import.md` for the conversion procedure. Alternatively, use `imapsync` to copy via IMAP from the old server to the new one (works without direct server access): ```bash imapsync \ --host1 old.server.com --user1 alice --password1 oldpass \ --host2 mail.ladkau.de --user2 alice --password2 newpass \ --port2 993 --ssl2 ``` ### 5.2 Connect an IMAP client | Setting | Value | |-----------|----------------------| | Server | `mail.ladkau.de` | | Port | `993` | | Security | SSL/TLS | | Username | as set in vault | ## 6. Vaultwarden Vaultwarden is a self-hosted Bitwarden-compatible password vault. Any official Bitwarden client (browser extension, desktop, mobile) can connect to it. ### 6.1 Log in to the admin panel Go to `https://vault.ladkau.de/admin/` and enter the `vaultwarden_admin_token` from the vault. From here you can invite users and manage the instance. ### 6.2 Sign in with Keycloak SSO Users can sign in at `https://vault.ladkau.de` using the **Enterprise Single Sign-On** button — enter `https://sso.ladkau.de/realms/ladkau` as the organisation identifier. On first login Vaultwarden creates an account automatically (public self-registration is otherwise disabled). ### 6.3 Connect a Bitwarden client In any official Bitwarden client, set the **Server URL** to `https://vault.ladkau.de` before logging in. ## 7. Download server Files placed under `dl.ladkau.de` are publicly browsable and downloadable over HTTPS. Upload is via SFTP on port 2223, key auth only. ### 7.1 Generate the deploy key Run this once locally and keep both files: ```bash ssh-keygen -t ed25519 -f dl_deploy_key -N "" -C "gitea-actions" ``` - Add the contents of `dl_deploy_key.pub` to the vault as `dl_sftp_authorized_keys` and redeploy (`--tags dl`) to authorise the key. - Store `dl_deploy_key` (the private key) as a Gitea Actions secret named `DL_SSH_KEY` in any repository that needs to publish releases. ### 7.2 Upload from Gitea Actions Add a step to your workflow after building the binary: ```yaml - name: Upload release run: | echo "${{ secrets.DL_SSH_KEY }}" > /tmp/deploy_key chmod 600 /tmp/deploy_key ssh -i /tmp/deploy_key -p 2223 \ -o StrictHostKeyChecking=no \ uploader@dl.ladkau.de \ "mkdir -p files/releases/${{ gitea.ref_name }}" scp -i /tmp/deploy_key -P 2223 \ -o StrictHostKeyChecking=no \ dist/myapp-linux-amd64 \ uploader@dl.ladkau.de:files/releases/${{ gitea.ref_name }}/ rm /tmp/deploy_key ``` The file is then available at: `https://dl.ladkau.de/releases/v1.2.3/myapp-linux-amd64` ### 7.3 Connect an SFTP client | Setting | Value | |-----------|--------------------| | Host | `dl.ladkau.de` | | Port | `2223` | | User | `uploader` | | Auth | SSH key | | Root path | `files/` | ## 8. Container registry ### 8.1 Docker CLI usage ```bash # Login docker login cr.ladkau.de # Push docker tag myimage:latest cr.ladkau.de/myimage:latest docker push cr.ladkau.de/myimage:latest # Pull docker pull cr.ladkau.de/myimage:latest ``` Registry users are managed via `registry_users` in the vault — store plaintext passwords, Ansible generates bcrypt hashes at deploy time. To add or rotate a user, edit the vault and redeploy: ```bash ansible-vault edit ansible/group_vars/all/vault.yml ansible-playbook -i ansible/inventory.ini ansible/site.yml --tags registry --ask-vault-pass ``` ### 8.2 Registry web UI A web dashboard is available at `https://cr.ladkau.de/`. Sign in with any `registry_users` credential from the vault. The UI allows browsing repositories and tags, inspecting image manifests and digests, and deleting images. Traefik routes `/v2/` (Docker API) to the registry container and everything else to the UI container — both on the same domain, so no CORS configuration is needed. `docker push` and `docker pull` work exactly as before.