Document Gitea domain and retire Prometheus DuckDNS

This commit is contained in:
Fabio Scotto di Santolo
2026-10-03 15:09:34 +02:00
parent 2dfe766b7b
commit 269fb13665
12 changed files with 190 additions and 4 deletions

View File

@@ -25,6 +25,9 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora
- Preserve layering `all -> platform -> role -> desktop -> host`.
- Keep `ansible/site.yml` small; orchestration belongs there, implementation belongs in roles.
- Prefer minimal, targeted edits. Preserve idempotency and existing ordering.
- Keep completed one-time cleanup operations out of the playbook. Execute them directly
with explicit authorization; retain only the ongoing desired-state configuration and
historical documentation, not permanent cleanup flags or tasks.
- Use Git Flow branch prefixes: `feature/` for new functionality, `bugfix/` for non-urgent fixes,
`hotfix/` for urgent production fixes, `release/` for release preparation, and `support/` for
maintained release lines. Do not use abbreviated prefixes such as `feat/`.
@@ -61,6 +64,8 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora
`ansible-playbook ansible/site.yml --limit atlas --tags storage,sharing,containers --check --diff`
- Atlas rootless Gitea staging (does not start Gitea):
`ansible-playbook ansible/site.yml --limit atlas --tags gitea --check --diff`
- Atlas canonical Gitea domain (restarts only Gitea on a real configuration change):
`ansible-playbook ansible/site.yml --limit atlas --tags gitea_public_domain --check --diff`
- Atlas iCloudPD storage and boot-started Quadlet:
`ansible-playbook ansible/site.yml --limit atlas --tags icloudpd --check --diff`
- Atlas explicit Gitea host-owner migration (live outage; never a normal run):
@@ -94,7 +99,7 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora
`ansible-playbook ansible/site.yml --limit prometheus,aegis --tags wireguard --check --diff`
- Prometheus NPM Quadlet steady state (does not perform a cutover):
`ansible-playbook ansible/site.yml --limit prometheus --tags npm_quadlet --check --diff`
- DuckDNS config only: `ansible-playbook ansible/site.yml --limit prometheus --tags duckdns --check --diff`
- DuckDNS config only (skipped on Prometheus): `ansible-playbook ansible/site.yml --limit prometheus --tags duckdns --check --diff`
## Conventions
- Use FQCN Ansible modules.
@@ -138,7 +143,10 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i
- Windows applications are installed manually and are not managed from the WSL profile.
## Rocky Server Notes
- DuckDNS is rendered by `profile_server` from host-local `server_duckdns_domain` and
- Prometheus disables DuckDNS provisioning with `server_duckdns_enabled: false`. Its updater,
log and five-minute cron entry were explicitly retired; the external DuckDNS name and Vault
token remain untouched. The completed one-time cleanup has no remaining playbook tasks.
- When enabled, DuckDNS is rendered by `profile_server` from host-local `server_duckdns_domain` and
`vault_duckdns_token`. Keep the rotated token in encrypted Vault or untracked local vars, never in
dotfiles. The private `~/duckdns/duck.sh` keeps the existing entrypoint; rendering uses `no_log`
and disables diffs. Provisioning does not execute the updater or change its external schedule.
@@ -368,6 +376,18 @@ successfully. The first monthly scrub remains a runtime check.
separate persistent application, database, and cache storage; keep credentials in Vault; publish it only
through NPM over the Prometheus--Aegis gateway; and define backup, upgrade, and eventual Uranus-migration
procedures before exposing user data. Do not deploy Nextcloud before the data-protection checklist is complete.
- [x] Move Gitea canonical HTTPS and SSH hostname to `git.fscotto.co` on
2026-10-03 through Ansible. Only Gitea restarted; second run changed nothing.
HTTPS and authenticated SSH reads returned the same repository HEAD.
The new NPM hostnames passed TLS/HTTP checks; old DuckDNS Proxy Hosts were
observed disabled. Details are in `docs/domain-fscotto-co.md`.
- [ ] Confirm login on the new Gitea hostname and update remaining client remotes/integrations.
The operator confirmed SSH pull; transport/authentication work, but the agent did not test push.
- [x] Retire Prometheus' local DuckDNS updater on 2026-10-03 through Ansible:
the five-minute cron entry and private updater/log directory were removed.
Provisioning is disabled; repeat cleanup changed nothing. HTTPS services, private NPM
administration and the export timer stayed healthy. The external name and Vault token
remain untouched for possible future use on a local host.
- [ ] Keep `atlas_manage_media_stack` disabled until the future Immich deployment has validated `/dev/dri`,
container paths, and the required Vault database secret.

View File

@@ -182,6 +182,10 @@ Le applicazioni Windows sono installate e gestite manualmente; il profilo WSL no
## Server
La migrazione dei servizi pubblici a `fscotto.co`, la gestione Ansible
degli URL Gitea e i passaggi ancora aperti per ritirare DuckDNS sono in
[`docs/domain-fscotto-co.md`](docs/domain-fscotto-co.md).
Sistema operativo:
- Rocky Linux 9
@@ -227,7 +231,11 @@ Mantenere l'autenticazione Syncthing e una policy di accesso NPM adeguata.
### DuckDNS
`profile_server` genera `~/duckdns/duck.sh` con permessi `0700`, mantenendo il percorso dello
`server_duckdns_enabled: false` disabilita il provisioning su Prometheus, che usa IP statico
e `fscotto.co`. Updater, log e cron ogni cinque minuti sono stati rimossi una sola volta;
non restano task o flag di pulizia. Il nome DuckDNS esterno e il token Vault restano invariati.
Sui server con `server_duckdns_enabled: true`, `profile_server` genera `~/duckdns/duck.sh` con permessi `0700`, mantenendo il percorso dello
script e `duck.log`. Definire `server_duckdns_domain` negli host vars del server e salvare il
**nuovo token rigenerato** in `vault_duckdns_token`, nel Vault cifrato `secrets/vault.yml`
(`ansible-vault edit secrets/vault.yml`) oppure negli override non versionati `secrets/vault.local.yml`.

View File

@@ -125,6 +125,10 @@ That gives it Fedora packages through DNF, Docker from the official repository,
## Server
The public service domain transition to `fscotto.co`, Gitea canonical URL
management, and remaining DuckDNS retirement steps are documented in
[`docs/domain-fscotto-co.md`](docs/domain-fscotto-co.md).
`prometheus` is the Rocky Linux 9 server. It has no graphical environment and gets server-specific
dotfiles and templates. The profile does not transfer application data, update DNS, or perform an
implicit service cutover.
@@ -167,7 +171,11 @@ Prometheus authorizes its declared SSH public keys through separate files below
### DuckDNS
`profile_server` renders `~/duckdns/duck.sh` with mode `0700`, keeping the existing updater path
`server_duckdns_enabled: false` disables provisioning on Prometheus, which uses its static IP
and `fscotto.co`. The local updater, log and five-minute cron job were removed once;
no cleanup tasks or flags remain. The external DuckDNS name and Vault token remain untouched.
For servers with `server_duckdns_enabled: true`, `profile_server` renders `~/duckdns/duck.sh` with mode `0700`, keeping the existing updater path
and `duck.log`. Set `server_duckdns_domain` in the server's host vars and store the **rotated**
`vault_duckdns_token` in encrypted `secrets/vault.yml` (using `ansible-vault edit secrets/vault.yml`)
or untracked `secrets/vault.local.yml`. Never commit the rendered script or put the token on a

View File

@@ -10,6 +10,7 @@ server_npm_quadlet_stage: false
server_npm_quadlet_cutover: false
server_legacy_stack_retired: false
server_legacy_cleanup: false
server_duckdns_enabled: true
ai_agents: {}
vim_plugins_enabled: false

View File

@@ -52,6 +52,7 @@ atlas_manage_storage: true
# Rootless Gitea was restored from the stopped-source export before production activation.
atlas_manage_gitea: true
atlas_gitea_production_enabled: true
atlas_gitea_public_domain: git.fscotto.co
atlas_prometheus_pull_start_timer: true
atlas_manage_zfs_snapshots: true
atlas_zfs_snapshot_prefix: atlas-auto

View File

@@ -27,6 +27,7 @@ server_gitea_on_atlas: true
server_gitea_npm_domains:
- git.fscotto.duckdns.org
server_duckdns_domain: fscotto
server_duckdns_enabled: false
server_ssh_authorized_keys:
- name: ikaros
key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINrIxXjA3ffPwziKGR5gzc4gAoBehQPlnEMcXF4Wl0ZS ikaros"

View File

@@ -184,6 +184,7 @@ atlas_gitea_quadlet_dir: "{{ atlas_gitea_home }}/.config/containers/systemd"
atlas_gitea_image: localhost/atlas-gitea:1.25.2-user-gitea-v1
atlas_gitea_image_build_dir: "{{ atlas_gitea_home }}/.local/share/atlas-gitea-image"
atlas_gitea_production_enabled: false
atlas_gitea_public_domain: ""
atlas_gitea_bind_address: "{{ ansible_host }}"
atlas_gitea_http_port: 3000
atlas_gitea_ssh_port: 2222

View File

@@ -0,0 +1,58 @@
---
- name: Manage the public domain of the restored production Gitea
tags: [atlas, gitea, gitea_public_domain]
when:
- atlas_manage_gitea | bool
- atlas_gitea_production_enabled | bool
- atlas_gitea_public_domain | length > 0
block:
- name: Require an explicit public Gitea hostname
ansible.builtin.assert:
that:
- atlas_gitea_public_domain is match('^[a-zA-Z0-9][a-zA-Z0-9.-]*\.[a-zA-Z]{2,}$')
- name: Inspect the restored private Gitea configuration
ansible.builtin.stat:
path: "{{ atlas_gitea_mountpoint }}/config/app.ini"
follow: false
register: atlas_gitea_public_config
- name: Refuse to create or replace an unprepared Gitea configuration
ansible.builtin.assert:
that:
- atlas_gitea_public_config.stat.isreg | default(false)
- atlas_gitea_public_config.stat.uid | int == atlas_gitea_uid | int
- atlas_gitea_public_config.stat.mode == '0600'
# app.ini contains secrets: preserve all unrelated settings and suppress diffs.
- name: Set only the declared public Gitea server fields
community.general.ini_file:
path: "{{ atlas_gitea_mountpoint }}/config/app.ini"
section: server
option: "{{ item.option }}"
value: "{{ item.value }}"
create: false
backup: true
owner: "{{ atlas_gitea_username }}"
group: "{{ atlas_gitea_group }}"
mode: "0600"
loop:
- { option: DOMAIN, value: "{{ atlas_gitea_public_domain }}" }
- { option: ROOT_URL, value: "https://{{ atlas_gitea_public_domain }}/" }
- { option: SSH_DOMAIN, value: "{{ atlas_gitea_public_domain }}" }
register: atlas_gitea_public_domain_update
no_log: true
diff: false
- name: Restart only Gitea when its public configuration changes
become_user: "{{ atlas_gitea_username }}"
ansible.builtin.systemd:
name: atlas-gitea.service
scope: user
state: restarted
environment:
XDG_RUNTIME_DIR: "/run/user/{{ atlas_gitea_uid }}"
DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/{{ atlas_gitea_uid }}/bus"
when:
- atlas_gitea_public_domain_update is changed
- not ansible_check_mode

View File

@@ -20,6 +20,9 @@
- name: Import staged Atlas rootless Gitea tasks
ansible.builtin.import_tasks: gitea.yml
- name: Import the declared Atlas Gitea public domain
ansible.builtin.import_tasks: gitea_public_domain.yml
- name: Import Atlas iCloudPD storage and boot-started Quadlet tasks
ansible.builtin.import_tasks: icloudpd.yml

View File

@@ -11,6 +11,7 @@
- name: Configure DuckDNS updater
tags: [dotfiles, dotfiles:server, duckdns]
ansible.builtin.import_tasks: duckdns.yml
when: server_duckdns_enabled | bool
- name: Ensure server directories exist
tags: [dotfiles, services]

View File

@@ -1,5 +1,10 @@
# Gitea migration from Prometheus to Atlas
The later 2026-10-03 canonical-domain change to `git.fscotto.co` is recorded
in `docs/domain-fscotto-co.md`. Public SSH remains on TCP/2222; the old
DuckDNS Proxy Host was observed disabled. Earlier domain references below
describe migration evidence, not the current canonical URL.
This records the staged migration and its observed partial cutover. Gitea is
temporary on Atlas until Uranus; NPM remains on Prometheus. On 2026-10-03
the operator explicitly approved removal of the old Prometheus Gitea data,

79
docs/domain-fscotto-co.md Normal file
View File

@@ -0,0 +1,79 @@
# fscotto.co domain transition
## Observed state (2026-10-03)
Namecheap remains the DNS provider. The operator moved GitHub Pages to
`blog.fscotto.co` in `fscotto/fscotto.github.io`, aligned Hugo and Pages
settings, and changed the apex A record to `179.237.102.172`. The blog
remains a CNAME to `fscotto.github.io`; mail records were left unchanged.
A new Hugo deployment and cache clearing resolved the initial stale DNS
and generated URLs. Blog HTTPS returned 200 with valid TLS.
The `git`, `music` and `syncthing` subdomains are CNAMEs to `fscotto.co`.
The operator added NPM Proxy Hosts with certificates, WebSocket support
and Force SSL:
| Hostname | HTTP upstream |
| --- | --- |
| git.fscotto.co | 192.168.178.55:3000 |
| music.fscotto.co | 192.168.178.55:4533 |
| syncthing.fscotto.co | 192.168.178.55:8384 |
All three redirected HTTP to HTTPS and returned final HTTPS 200 with valid
TLS. Only the Syncthing GUI uses NPM; native synchronization is unchanged.
NPM administration remains loopback-only on port 81 via SSH tunnel.
## Gitea canonical hostname
Atlas declares `atlas_gitea_public_domain: git.fscotto.co`. Ansible manages
only `[server] DOMAIN`, `ROOT_URL` and `SSH_DOMAIN` in the existing private
app.ini, preserving unrelated settings and mode 0600. Private configuration
backups are created; diffs and secret-bearing results are suppressed.
Only Gitea restarts when these fields change; a repeat run changed nothing.
HTTPS uses `https://git.fscotto.co/`; public SSH remains TCP/2222.
Agent read-only checks returned the same HEAD from `fscotto/infra.git`
over HTTPS and authenticated SSH. SSH host identity was checked against
the already-trusted old endpoint key. No test push or user-authenticated
web login was performed by the agent.
```bash
ansible-playbook ansible/site.yml --limit atlas --tags gitea_public_domain --check --diff
```
Client remotes do not update automatically. Update them deliberately after
checking repository paths; integrations and webhooks are separate operations.
For the verified infrastructure repository only:
```bash
git remote set-url origin ssh://git@git.fscotto.co:2222/fscotto/infra.git
```
Do not copy this path into unrelated clones. Verify Gitea's known SSH key
before accepting the new hostname's identity.
## Local DuckDNS retirement
Prometheus declares `server_duckdns_enabled: false`. On 2026-10-03 the explicit
Ansible cleanup removed the five-minute rocky cron entry and the private
`~/duckdns` directory containing only `duck.sh` and `duck.log`. The temporary
cleanup tasks and flag were subsequently removed from the playbook at the
operator's request. Only the disabled provisioning state remains; ordinary
provisioning cannot recreate the updater.
The external DuckDNS name, Vault token, disabled NPM hosts and certificates
remain untouched for a separate future decision.
The repeat cleanup changed nothing; ordinary DuckDNS provisioning was skipped.
The cron table had no remaining entries, NPM and the export timer were active,
and NPM administration still listened only on `127.0.0.1:81`.
## Remaining transition work
- Confirm user-authenticated login and push on the new Gitea hostname.
- Update existing remotes and callback/webhook URLs explicitly.
- Retire obsolete NPM hosts/certificates and the old upstream override
after confirming they are no longer needed.
At inspection the three old DuckDNS Proxy Hosts were already disabled,
not deleted. They are not working HTTPS rollback endpoints. Existing backup
archives remain preserved. DNS/Pages/NPM changes were operator actions;
the Gitea application configuration change was deployed through Ansible.