xmpp_cert_sync: renew the XMPP certificate through Traefik
All checks were successful
deploy / ansible (push) Successful in 7m22s

The ejabberd certificate (asxp.io, conference., xmpp.) was issued by
hand and expires 2027-01-28 with nothing renewing it. Traefik now
obtains it alongside the sites' certificates, through a router that
only exists to request it, and a systemd path unit on ops pushes it to
services whenever acme.json changes, with a daily run as fallback.

The push uses its own SSH key, accepted from ops' VPC address only and
forced to xmpp-cert-install, which checks the certificate is valid for
another day and matches its key before replacing server.pem and
reloading ejabberd.

Two alerts: the sync hasn't succeeded for two days, or ejabberd serves
an older certificate than Traefik holds for six hours. The existing
expiry alert already covers port 5223.

Assisted-by: Claude:opus-5-5
This commit is contained in:
Sergei Poljanski 2026-11-13 08:16:00 +04:00
commit 5e009c4a47
Signed by: asxpi
GPG key ID: 4F8851660FA4121B
11 changed files with 217 additions and 1 deletions

View file

@ -0,0 +1,57 @@
---
# Runs on asxpio-ops (where Traefik keeps the certificate); sets up the
# receiving end on asxpio-services through delegate_to.
- name: Generate the sync SSH key
community.crypto.openssh_keypair:
path: /root/.ssh/xmpp_cert_sync
type: ed25519
comment: xmpp-cert-sync@{{ inventory_hostname }}
register: xmpp_cert_sync_key
- name: Install the receiving script on asxpio-services
ansible.builtin.copy:
src: xmpp-cert-install
dest: /usr/local/bin/xmpp-cert-install
mode: "0755"
delegate_to: asxpio-services
- name: Authorize the key for that script only, from ops only
ansible.posix.authorized_key:
user: root
key: "{{ xmpp_cert_sync_key.public_key }}"
key_options: 'restrict,from="{{ asxpio_ops_vpc_ip }}",command="/usr/local/bin/xmpp-cert-install"'
comment: xmpp-cert-sync
delegate_to: asxpio-services
# In a dry run on a fresh host the key does not exist yet
when: xmpp_cert_sync_key.public_key is defined
- name: Install the sync script
ansible.builtin.template:
src: xmpp-cert-sync.j2
dest: /usr/local/bin/xmpp-cert-sync
mode: "0755"
- name: Install the sync units
ansible.builtin.copy:
src: "{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: "0644"
loop:
- xmpp-cert-sync.service
- xmpp-cert-sync.path
- xmpp-cert-sync.timer
notify: Reload systemd
- name: Flush handlers
ansible.builtin.meta: flush_handlers
- name: Enable the path watch and the daily fallback
ansible.builtin.systemd:
name: "{{ item }}"
enabled: true
state: started
loop:
- xmpp-cert-sync.path
- xmpp-cert-sync.timer
# A dry run installs no new unit files
ignore_errors: "{{ ansible_check_mode }}"