Compare commits

...

2 Commits

Author SHA1 Message Date
Fabio Scotto di Santolo
569e6ef24e Fix desktop dotfile idempotency 2026-09-08 23:24:53 +02:00
Fabio Scotto di Santolo
ab8c51a57d Migrate Prometheus stack to Podman 2026-09-08 23:12:41 +02:00
16 changed files with 92 additions and 118 deletions

View File

@@ -52,7 +52,7 @@ Ansible-driven personal infrastructure repo for Fedora and Void desktops, Fedora
- Emacs is disabled by default; temporary Emacs check: `ansible-playbook ansible/site.yml --limit <host> --tags emacs --check --diff -e emacs_enabled=true`
- AI coding agents: `ansible-playbook ansible/site.yml --limit <host> --tags ai_agents --check --diff`
- Mail bootstrap: `sh -n scripts/bootstrap_mail.sh` and `shellcheck scripts/bootstrap_mail.sh`
- Server compose render: `docker compose -f /opt/docker/server/docker-compose.yml config`
- Server compose render: `podman-compose -f /opt/docker/server/docker-compose.yml config` and `systemctl status podman-compose-server`
- DuckDNS config only: `ansible-playbook ansible/site.yml --limit prometheus --tags duckdns --check --diff`
## Conventions
@@ -103,12 +103,17 @@ The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-i
and disables diffs. Provisioning does not execute the updater or change its external schedule.
- `rocky_server` is a child of both `platform_rocky` and `server`; `prometheus` is its active target.
- The target must already provide `server_username` with local sudo access before the profile runs.
- The Rocky profile installs Docker CE, uses firewalld, preserves SELinux enforcement, and renders the
same server Compose stack. It does not transfer data, start containers, update DNS, or cut over traffic.
- The Rocky profile installs Podman and podman-compose, uses firewalld, preserves SELinux enforcement, and renders the
same server Compose stack with a `podman-compose-server` systemd unit. It does not start, enable, transfer data,
update DNS, or cut over traffic; activating the stack is a manual step.
- Firewalld enables SSH, Cockpit (`9090/tcp`), HTTP and HTTPS. Nginx Proxy Manager publishes `80/tcp` and
`443/tcp`; bind its administration interface only to `127.0.0.1:81` and use `npm-tunnel` from Ikaros or Nymph.
Nextcloud remains disabled; do not provision `/srv/nextcloud` directories.
- `scripts/migrate_prometheus_data.sh` is the separate, source-host-run migration path. It dry-runs by
default and requires explicit source-stack quiescing before copying persistent Docker data with rsync.
- Atlas-only OpenZFS, NFS, Samba, Cockpit, and Syncthing stay selected through Atlas host variables
and must not leak into `rocky_server`.
- Atlas-only OpenZFS, NFS, Samba, and Syncthing stay selected through Atlas host variables and must not
leak into `rocky_server`. Cockpit plus its Navigator and Podman extensions are selected explicitly for
Prometheus through its host variables.
## Atlas NAS Notes
- `atlas` is a remote Rocky Linux 9 NAS. Keep its connection, LAN, pool and mountpoint values in

View File

@@ -178,12 +178,16 @@ Profilo orientato a servizi server e gestione di dotfiles dedicati.
Lo stato attuale del profilo server include:
- installazione pacchetti Rocky via DNF, EPEL e CRB
- installazione e configurazione di Docker dal repository ufficiale
- installazione di Podman e podman-compose
- abilitazione dei servizi systemd dichiarati in inventory/group vars
- copia dei dotfiles server e rendering dei template server, incluso il `docker-compose.yml` dello stack servizi
- attivazione di firewalld con servizio SSH esplicitamente abilitato
- copia dei dotfiles server e rendering dei template server, incluso il `docker-compose.yml` dello stack servizi e dell'unit `podman-compose-server` (attivazione manuale)
- attivazione di firewalld con SSH, Cockpit (`9090/tcp`), HTTP e HTTPS abilitati
- Syncthing escluso dal profilo server Rocky
Nginx Proxy Manager pubblica solo `80/tcp` e `443/tcp`; la sua interfaccia di amministrazione e
associata a `127.0.0.1:81` ed e raggiungibile da Ikaros o Nymph con l'alias Bash `npm-tunnel`.
Nextcloud resta disabilitato e il profilo non crea directory `/srv/nextcloud`.
### DuckDNS
`profile_server` genera `~/duckdns/duck.sh` con permessi `0700`, mantenendo il percorso dello
@@ -450,7 +454,7 @@ ansible-playbook ansible/site.yml --limit <host> --tags <tag1>,<tag2> --check --
ansible-playbook ansible/site.yml --limit <host> --start-at-task "<task name>" --check --diff
ansible-lint ansible/roles/<role>
yamllint ansible/path/to/file.yml
docker compose -f /opt/docker/server/docker-compose.yml config
podman-compose -f /opt/docker/server/docker-compose.yml config
```
## Tag supportati dal playbook

View File

@@ -104,11 +104,16 @@ That gives it Fedora packages through DNF, Docker from the official repository,
dotfiles and templates. The profile provisions configuration only: it does not transfer data, start
the Compose stack, update DNS, or perform a cutover.
The server profile installs platform-specific packages, Docker CE from the official repository,
declared systemd services, the server Compose stack, and firewalld. The Rocky server excludes
The server profile installs platform-specific packages, Podman and podman-compose,
declared systemd services, the server Compose stack behind the `podman-compose-server` systemd unit, and firewalld. The Rocky server excludes
Syncthing. Rocky bind mounts use private SELinux relabeling for application data while host system
files remain unchanged.
Firewalld enables SSH, Cockpit (`9090/tcp`), HTTP and HTTPS. Nginx Proxy Manager publishes only
`80/tcp` and `443/tcp`; its administration interface is bound to `127.0.0.1:81` and can be reached
from Ikaros or Nymph with the `npm-tunnel` Bash alias. Nextcloud remains disabled and the profile
does not provision any `/srv/nextcloud` directories.
Server identity comes from `server_username`, `server_user_group`, and `server_user_home` in `ansible/inventory/group_vars/server.yml`. `server_username` defaults to `username`, but it can be overridden, for example:
```bash
@@ -378,7 +383,7 @@ ansible-playbook ansible/site.yml --limit <host> --tags <tag1>,<tag2> --check --
ansible-playbook ansible/site.yml --limit <host> --start-at-task "<task name>" --check --diff
ansible-lint ansible/roles/<role>
yamllint ansible/path/to/file.yml
docker compose -f /opt/docker/server/docker-compose.yml config
podman-compose -f /opt/docker/server/docker-compose.yml config
```
## Tags

View File

@@ -18,11 +18,9 @@ rocky_syncthing_archive_url: >-
rocky_manage_openzfs_repo: false
rocky_manage_syncthing_binary: false
rocky_manage_docker_repo: false
rocky_manage_podman: false
rocky_manage_github_cli_repo: false
rocky_docker_repo_url: https://download.docker.com/linux/rhel/docker-ce.repo
rocky_docker_repo_file: /etc/yum.repos.d/docker-ce.repo
rocky_github_cli_repo_url: https://cli.github.com/packages/rpm/gh-cli.repo
rocky_github_cli_repo_file: /etc/yum.repos.d/gh-cli.repo
@@ -47,8 +45,8 @@ rocky_packages_base:
- firewalld
- openssh-server
- rsync
- selinux-policy-targeted
- sudo
rocky_profile_packages: []
rocky_docker_packages: []
rocky_docker_conflicting_packages: []
rocky_podman_packages: []

View File

@@ -1,5 +1,5 @@
---
rocky_manage_docker_repo: true
rocky_manage_podman: true
rocky_manage_github_cli_repo: true
rocky_profile_packages:
@@ -22,37 +22,22 @@ rocky_profile_packages:
- ranger
- ripgrep
rocky_docker_packages:
- containerd.io
- docker-buildx-plugin
- docker-ce
- docker-ce-cli
- docker-compose-plugin
rocky_docker_conflicting_packages:
- docker
- docker-client
- docker-client-latest
- docker-common
- docker-engine
- docker-latest
- docker-latest-logrotate
- docker-logrotate
- runc
rocky_podman_packages:
- podman
- podman-compose
enabled_services:
- firewalld
- docker
- podman.socket
server_firewall_backend: firewalld
server_firewalld_zone: public
server_firewalld_services:
- ssh
- cockpit
- http
- https
server_firewalld_ports: []
server_firewalld_absent_ports:
- 22000/tcp
- 22000/udp
- 21027/udp
server_sshd_service_name: sshd
server_compose_selinux_mount_option: Z
server_syncthing_enabled: false

View File

@@ -13,12 +13,4 @@ personal_workstation_directories:
- path: "{{ user_home }}/Remotes"
mode: "0755"
personal_workstation_dotfiles:
- src: .gitignore_global
dest: .gitignore_global
mode: "0644"
- src: .themes.gitignore
dest: .themes.gitignore
mode: "0644"
personal_workstation_flatpak_packages: []

View File

@@ -86,14 +86,6 @@ server_directories:
owner: root
group: root
mode: "0755"
- path: /srv/nextcloud
owner: root
group: root
mode: "0755"
- path: /srv/nextcloud/data
owner: root
group: root
mode: "0755"
server_syncthing_enabled: true
server_syncthing_directories:

View File

@@ -23,6 +23,7 @@
dest: "{{ effective_user_home }}/Templates"
owner: "{{ effective_username }}"
group: "{{ effective_user_group }}"
creates: "{{ effective_user_home }}/Templates/code/main.c"
when: "'desktop' in group_names"
- name: Ensure Emacs authoring directories exist

View File

@@ -50,16 +50,6 @@
state: enabled
when: rocky_manage_openzfs_repo | bool
- name: Configure official Docker RPM repository
tags: [packages, docker]
ansible.builtin.get_url:
url: "{{ rocky_docker_repo_url }}"
dest: "{{ rocky_docker_repo_file }}"
owner: root
group: root
mode: "0644"
when: rocky_manage_docker_repo | bool
- name: Configure official GitHub CLI RPM repository
tags: [packages]
ansible.builtin.get_url:
@@ -70,15 +60,6 @@
mode: "0644"
when: rocky_manage_github_cli_repo | bool
- name: Remove packages conflicting with Docker CE
tags: [packages, docker]
ansible.builtin.dnf:
name: "{{ rocky_docker_conflicting_packages }}"
state: absent
when:
- rocky_manage_docker_repo | bool
- rocky_docker_conflicting_packages | length > 0
- name: Refresh Rocky package metadata
tags: [packages]
ansible.builtin.dnf:
@@ -93,19 +74,21 @@
(rocky_common_packages | default([]))
+ (rocky_packages_base | default([]))
+ (rocky_profile_packages | default([]))
+ (rocky_docker_packages | default([]))
+ (rocky_podman_packages | default([]))
+ (host_packages | default([]))
) | unique
}}
state: present
- name: Add Rocky user to docker group
tags: [packages, docker]
ansible.builtin.user:
name: "{{ effective_username }}"
groups: docker
append: true
when: rocky_docker_packages | length > 0
- name: Ensure Podman runtime socket directory exists
tags: [packages, podman]
ansible.builtin.file:
path: /run/podman
state: directory
owner: root
group: root
mode: "0700"
when: rocky_manage_podman | bool
- name: Require supported architecture for Syncthing
tags: [packages, syncthing]

View File

@@ -10,15 +10,3 @@
loop: "{{ personal_workstation_directories | default([]) }}"
loop_control:
label: "{{ item.path }}"
- name: Copy personal workstation dotfiles
tags: [dotfiles, dotfiles:workstation]
ansible.builtin.copy:
src: "{{ playbook_dir }}/../dotfiles/workstation/{{ item.src }}"
dest: "{{ user_home }}/{{ item.dest }}"
owner: "{{ username }}"
group: "{{ user_group }}"
mode: "{{ item.mode }}"
loop: "{{ personal_workstation_dotfiles | default([]) }}"
loop_control:
label: "{{ item.dest }}"

View File

@@ -4,3 +4,8 @@
ansible.builtin.service:
name: "{{ server_sshd_service_name }}"
state: reloaded
- name: Reload systemd for Podman Compose
tags: [services]
ansible.builtin.systemd:
daemon_reload: true

View File

@@ -67,6 +67,10 @@
label: "{{ item.dest }}"
no_log: "{{ item.no_log | default(false) }}"
- name: Manage Podman Compose stack
tags: [services, podman]
ansible.builtin.include_tasks: podman-compose.yml
- name: Disable SSH root login on server
tags: [services]
ansible.builtin.lineinfile:
@@ -113,16 +117,3 @@
loop_control:
label: "{{ item }}"
when: server_firewall_backend == 'firewalld'
- name: Remove disabled server ports from firewalld
tags: [services, packages]
ansible.posix.firewalld:
port: "{{ item }}"
zone: "{{ server_firewalld_zone }}"
state: disabled
permanent: true
immediate: true
loop: "{{ server_firewalld_absent_ports | default([]) }}"
loop_control:
label: "{{ item }}"
when: server_firewall_backend == 'firewalld'

View File

@@ -0,0 +1,10 @@
---
- name: Render Podman Compose systemd unit
tags: [services, podman]
ansible.builtin.template:
src: podman-compose-server.service.j2
dest: /etc/systemd/system/podman-compose-server.service
owner: root
group: root
mode: "0644"
notify: Reload systemd for Podman Compose

View File

@@ -0,0 +1,15 @@
[Unit]
Description=Podman Compose stack for {{ server_username }}
Requires=network-online.target
After=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory={{ server_container_stack_dir }}
ExecStart=/usr/bin/podman-compose up -d
ExecStop=/usr/bin/podman-compose down
ExecReload=/usr/bin/podman-compose up -d
[Install]
WantedBy=multi-user.target

View File

@@ -1,10 +1,10 @@
---
{% set selinux_volume_option = server_compose_selinux_mount_option | default('') %}
version: "3.8"
name: server
services:
navidrome:
image: deluan/navidrome:latest
image: docker.io/deluan/navidrome:latest
container_name: navidrome
restart: unless-stopped
expose:
@@ -23,19 +23,18 @@ services:
depends_on:
- navidromedb
nginx-proxy-manager:
image: jc21/nginx-proxy-manager:latest
image: docker.io/jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "81:81"
- "127.0.0.1:81:81"
volumes:
- "/opt/npm/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
- "/opt/npm/letsencrypt:/etc/letsencrypt{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}"
networks:
- web
- gitea
# Disabled: prometheus does not have enough resources to run Nextcloud AIO.
# nextcloud-aio-mastercontainer:
@@ -57,7 +56,7 @@ services:
# - web
navidromedb:
image: postgres:13
image: docker.io/library/postgres:13
container_name: navidromedb
restart: unless-stopped
mem_limit: 2048m
@@ -78,7 +77,7 @@ services:
- USER_GID=1100
restart: always
networks:
- gitea
- web
volumes:
- /opt/gitea/data:/data{{ ':' ~ selinux_volume_option if selinux_volume_option else '' }}
- /etc/timezone:/etc/timezone:ro
@@ -90,7 +89,7 @@ services:
{% if server_syncthing_enabled | default(true) | bool %}
syncthing:
image: syncthing/syncthing:2
image: docker.io/syncthing/syncthing:2
container_name: syncthing
hostname: syncthing
restart: unless-stopped
@@ -111,8 +110,6 @@ networks:
web:
name: server_web
external: false
gitea:
external: false
# volumes:
# nextcloud_aio_mastercontainer:

View File

@@ -1,2 +1,5 @@
# Additional Bash aliases.
# Keep this file as the extension point for shared aliases.
# Nginx Proxy Manager administration tunnel on Prometheus.
alias npm-tunnel='ssh -N -o ExitOnForwardFailure=yes -L 8181:127.0.0.1:81 rocky@179.237.102.172'