phoenixd upgrade

This commit is contained in:
counterweight 2026-08-08 15:19:11 +02:00
parent ba4ba504d0
commit d0bfc2650d
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
5 changed files with 795 additions and 5 deletions

View file

@ -13,17 +13,34 @@
state: present
update_cache: yes
# Caddy's signing subkey carries an expiry date, and Cloudsmith republishes
# the key with a refreshed binding signature before it lapses. Re-fetch on
# every run: pinning the keyring with `creates:` leaves the host stuck on a
# key that eventually expires and breaks `apt update` with an sqv error.
- name: Ensure apt keyrings directory exists
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
owner: root
group: root
mode: '0755'
- name: Download Caddy GPG armored key
ansible.builtin.get_url:
url: https://dl.cloudsmith.io/public/caddy/stable/gpg.key
dest: /tmp/caddy-stable-archive-keyring.asc
dest: /etc/apt/keyrings/caddy-stable-archive-keyring.asc
mode: '0644'
register: caddy_key_download
- name: Check for existing Caddy keyring
ansible.builtin.stat:
path: /usr/share/keyrings/caddy-stable-archive-keyring.gpg
register: caddy_keyring
- name: Convert ASCII armored key to binary keyring
ansible.builtin.command:
cmd: gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg /tmp/caddy-stable-archive-keyring.asc
args:
creates: /usr/share/keyrings/caddy-stable-archive-keyring.gpg
cmd: gpg --batch --yes --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg /etc/apt/keyrings/caddy-stable-archive-keyring.asc
when: caddy_key_download.changed or not caddy_keyring.stat.exists
- name: Ensure permissions on keyring file
ansible.builtin.file:

View file

@ -0,0 +1,535 @@
---
# phoenixd Deployment Playbook
#
# Deploys phoenixd (https://phoenix.acinq.co/server), the server version of the
# Phoenix Lightning wallet, on vipy so LNBits can use it as a wallet backend
# over loopback.
#
# What this does:
# 1. Downloads the pinned phoenixd release and installs phoenixd + phoenix-cli
# 2. Creates a dedicated system user and a 0700 data directory
# 3. Creates and enables a systemd service
# 4. Creates a push-monitor health check script + systemd timer
# 5. Registers a push monitor in Uptime Kuma
#
# The HTTP API stays bound to 127.0.0.1 and is NOT proxied by Caddy: phoenixd
# holds funds and its API is protected by a single password. Anything that needs
# it either runs on this host or reaches it over the Tailscale mesh.
#
# ⚠️ After the first run, back up {{ phoenixd_data_dir }}/seed.dat. Losing it
# means losing the funds. See setup_backup_phoenixd_to_lapy.yml.
- name: Deploy phoenixd on vipy
hosts: vipy
become: yes
vars_files:
- ../../infra_vars.yml
- ../../services_config.yml
- ../../infra_secrets.yml
- ./phoenixd_vars.yml
vars:
uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}"
tasks:
# ===========================================
# Prerequisites
# ===========================================
- name: Install phoenixd runtime dependencies
apt:
name:
- unzip
- curl
state: present
update_cache: yes
# ===========================================
# System User and Directories
# ===========================================
- name: Create phoenixd system group
group:
name: "{{ phoenixd_group }}"
system: yes
- name: Create phoenixd system user
user:
name: "{{ phoenixd_user }}"
group: "{{ phoenixd_group }}"
system: yes
shell: /usr/sbin/nologin
home: "{{ phoenixd_home }}"
create_home: yes
comment: "phoenixd Lightning node"
- name: Create phoenixd home directory
file:
path: "{{ phoenixd_home }}"
state: directory
owner: "{{ phoenixd_user }}"
group: "{{ phoenixd_group }}"
mode: "0750"
- name: Create phoenixd data directory
file:
path: "{{ phoenixd_data_dir }}"
state: directory
owner: "{{ phoenixd_user }}"
group: "{{ phoenixd_group }}"
mode: "0700"
# ===========================================
# Download and Install
# ===========================================
- name: Check if phoenixd is already installed
stat:
path: "{{ phoenixd_bin_dir }}/phoenixd"
register: phoenixd_binary
- name: Check installed phoenixd version
command: "{{ phoenixd_bin_dir }}/phoenixd --version"
register: phoenixd_installed_version
changed_when: false
failed_when: false
when: phoenixd_binary.stat.exists
- name: Decide whether phoenixd needs installing
set_fact:
phoenixd_needs_install: >-
{{ not phoenixd_binary.stat.exists
or phoenixd_version not in (phoenixd_installed_version.stdout | default('')) }}
- name: Download phoenixd {{ phoenixd_version }}
get_url:
url: "{{ phoenixd_url }}"
dest: "/tmp/phoenixd-{{ phoenixd_version }}.zip"
mode: "0644"
when: phoenixd_needs_install | bool
- name: Create temporary extraction directory
file:
path: /tmp/phoenixd-extract
state: directory
mode: "0755"
when: phoenixd_needs_install | bool
- name: Extract phoenixd archive
unarchive:
src: "/tmp/phoenixd-{{ phoenixd_version }}.zip"
dest: /tmp/phoenixd-extract
remote_src: yes
when: phoenixd_needs_install | bool
- name: Locate extracted binaries
find:
paths: /tmp/phoenixd-extract
patterns: "{{ item }}"
recurse: yes
file_type: file
register: phoenixd_extracted
loop:
- phoenixd
- phoenix-cli
when: phoenixd_needs_install | bool
- name: Fail if the archive did not contain the expected binaries
assert:
that:
- item.files | length > 0
fail_msg: "Could not find '{{ item.item }}' in the phoenixd {{ phoenixd_version }} archive"
loop: "{{ phoenixd_extracted.results }}"
loop_control:
label: "{{ item.item }}"
when: phoenixd_needs_install | bool
- name: Install phoenixd and phoenix-cli binaries
copy:
src: "{{ item.files[0].path }}"
dest: "{{ phoenixd_bin_dir }}/{{ item.item }}"
remote_src: yes
owner: root
group: root
mode: "0755"
loop: "{{ phoenixd_extracted.results }}"
loop_control:
label: "{{ item.item }}"
when: phoenixd_needs_install | bool
notify: Restart phoenixd
- name: Clean up phoenixd download artifacts
file:
path: "{{ item }}"
state: absent
loop:
- "/tmp/phoenixd-{{ phoenixd_version }}.zip"
- /tmp/phoenixd-extract
# ===========================================
# Systemd Service
# ===========================================
- name: Build phoenixd command line arguments
set_fact:
phoenixd_args: >-
{{ (['--agree-to-terms-of-service'] if phoenixd_agree_tos else [])
+ ['--chain', phoenixd_chain]
+ ['--auto-liquidity', phoenixd_auto_liquidity]
+ ['--http-bind-ip', phoenixd_http_bind_ip]
+ ['--http-bind-port', phoenixd_http_bind_port | string]
+ (['--max-mining-fee', phoenixd_max_mining_fee | string] if phoenixd_max_mining_fee else [])
+ (['--webhook', phoenixd_webhook_url] if phoenixd_webhook_url else [])
+ ['--silent'] }}
- name: Create phoenixd systemd service
copy:
dest: /etc/systemd/system/phoenixd.service
content: |
[Unit]
Description=phoenixd - Lightning Network Node
Documentation=https://phoenix.acinq.co/server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User={{ phoenixd_user }}
Group={{ phoenixd_group }}
WorkingDirectory={{ phoenixd_home }}
Environment=PHOENIX_DATADIR={{ phoenixd_data_dir }}
ExecStart={{ phoenixd_bin_dir }}/phoenixd {{ phoenixd_args | join(' ') }}
Restart=always
RestartSec=30
TimeoutStartSec=120
TimeoutStopSec=120
StandardOutput=journal
StandardError=journal
# Hardening: the node only ever writes to its own data directory
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths={{ phoenixd_data_dir }}
LimitNOFILE=65535
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: "0644"
notify: Restart phoenixd
- name: Reload systemd daemon
systemd:
daemon_reload: yes
- name: Enable and start phoenixd
systemd:
name: phoenixd
enabled: yes
state: started
- name: Flush handlers so phoenixd is running before we inspect its data dir
meta: flush_handlers
# ===========================================
# First Boot Checks
# ===========================================
- name: Wait for phoenixd to write its config file
wait_for:
path: "{{ phoenixd_data_dir }}/phoenix.conf"
state: present
timeout: 120
- name: Check that the seed file exists
stat:
path: "{{ phoenixd_data_dir }}/seed.dat"
register: phoenixd_seed_file
- name: Fail if phoenixd did not create a seed
assert:
that:
- phoenixd_seed_file.stat.exists
fail_msg: "phoenixd started but {{ phoenixd_data_dir }}/seed.dat is missing - check 'journalctl -u phoenixd'"
# ===========================================
# Health Check Script + Systemd Timer
# ===========================================
- name: Create phoenixd health check script
copy:
dest: "{{ phoenixd_healthcheck_script_path }}"
content: |
#!/bin/bash
# Checks phoenixd and pushes the result to Uptime Kuma.
UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}"
export PHOENIX_DATADIR="{{ phoenixd_data_dir }}"
check_phoenixd() {
# Service must be active and the node must answer getinfo.
# phoenix-cli reads the api password from $PHOENIX_DATADIR/phoenix.conf,
# but not the bind address, so pass it explicitly.
systemctl is-active --quiet phoenixd && \
{{ phoenixd_bin_dir }}/phoenix-cli \
--http-bind-ip {{ phoenixd_http_bind_ip }} \
--http-bind-port {{ phoenixd_http_bind_port }} \
getinfo 2>/dev/null | grep -q '"nodeId"'
}
push_to_uptime_kuma() {
local status=$1
local msg=$2
if [ -z "$UPTIME_KUMA_PUSH_URL" ]; then
echo "ERROR: UPTIME_KUMA_PUSH_URL not set"
return 1
fi
curl -s --max-time 10 --retry 2 -o /dev/null \
"${UPTIME_KUMA_PUSH_URL}?status=${status}&msg=${msg// /%20}&ping=" || true
}
if check_phoenixd; then
push_to_uptime_kuma "up" "OK"
exit 0
else
push_to_uptime_kuma "down" "phoenixd not responding"
exit 1
fi
owner: root
group: root
mode: "0755"
- name: Create phoenixd health check systemd service
copy:
dest: "/etc/systemd/system/{{ phoenixd_healthcheck_service_name }}.service"
content: |
[Unit]
Description=phoenixd Health Check
After=network.target phoenixd.service
[Service]
Type=oneshot
User=root
ExecStart={{ phoenixd_healthcheck_script_path }}
Environment=UPTIME_KUMA_PUSH_URL=
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=multi-user.target
owner: root
group: root
mode: "0644"
- name: Create phoenixd health check systemd timer
copy:
dest: "/etc/systemd/system/{{ phoenixd_healthcheck_service_name }}.timer"
content: |
[Unit]
Description=phoenixd Health Check Timer
[Timer]
OnBootSec=2min
OnUnitActiveSec=1min
Persistent=true
[Install]
WantedBy=timers.target
owner: root
group: root
mode: "0644"
- name: Reload systemd daemon after health check units
systemd:
daemon_reload: yes
- name: Enable and start phoenixd health check timer
systemd:
name: "{{ phoenixd_healthcheck_service_name }}.timer"
enabled: yes
state: started
# ===========================================
# Uptime Kuma Push Monitor Setup
# ===========================================
- name: Create Uptime Kuma push monitor setup script for phoenixd
delegate_to: localhost
become: no
copy:
dest: /tmp/setup_phoenixd_monitor.py
content: |
#!/usr/bin/env python3
import sys
import time
import traceback
import yaml
from uptime_kuma_api import UptimeKumaApi, MonitorType
try:
with open('/tmp/ansible_phoenixd_config.yml', 'r') as f:
config = yaml.safe_load(f)
url = config['uptime_kuma_url']
username = config['username']
password = config['password']
monitor_name = config['monitor_name']
api = UptimeKumaApi(url, timeout=30)
api.login(username, password)
monitors = api.get_monitors()
# Find or create "services" group
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
if not group:
try:
api.add_monitor(type='group', name='services')
except Exception:
time.sleep(2)
monitors = api.get_monitors()
group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None)
# Get ntfy notification ID
notifications = api.get_notifications()
ntfy_notification_id = None
for notif in notifications:
if notif.get('type') == 'ntfy':
ntfy_notification_id = notif.get('id')
break
existing = next((m for m in monitors if m.get('name') == monitor_name), None)
push_url = None
if existing:
print(f"Monitor '{monitor_name}' already exists (ID: {existing['id']})")
push_token = existing.get('pushToken') or existing.get('push_token')
if push_token:
push_url = f"{url}/api/push/{push_token}"
else:
print(f"Creating push monitor '{monitor_name}'...")
try:
api.add_monitor(
type=MonitorType.PUSH,
name=monitor_name,
parent=group['id'],
interval=90,
maxretries=3,
retryInterval=60,
notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {}
)
except Exception as e:
# socketio timeout: add_monitor may have succeeded server-side
print(f"add_monitor raised (possibly timeout): {e}", file=sys.stderr)
time.sleep(2)
monitors = api.get_monitors()
new_monitor = next((m for m in monitors if m.get('name') == monitor_name), None)
if new_monitor:
push_token = new_monitor.get('pushToken') or new_monitor.get('push_token')
if push_token:
push_url = f"{url}/api/push/{push_token}"
api.disconnect()
if push_url:
print(f"PUSH_URL={push_url}")
with open('/tmp/phoenixd_push_url.txt', 'w') as f:
f.write(push_url)
print("SUCCESS")
except Exception as e:
print(f"ERROR: {str(e)}", file=sys.stderr)
traceback.print_exc(file=sys.stderr)
sys.exit(1)
mode: "0755"
- name: Create temporary config for push monitor setup
delegate_to: localhost
become: no
copy:
dest: /tmp/ansible_phoenixd_config.yml
content: |
uptime_kuma_url: "{{ uptime_kuma_api_url }}"
username: "{{ uptime_kuma_username }}"
password: "{{ uptime_kuma_password }}"
monitor_name: "{{ phoenixd_monitor_name }}"
mode: "0644"
- name: Run Uptime Kuma push monitor setup
command: python3 /tmp/setup_phoenixd_monitor.py
delegate_to: localhost
become: no
register: monitor_setup
changed_when: "'SUCCESS' in monitor_setup.stdout"
ignore_errors: yes
- name: Display monitor setup output
debug:
msg: "{{ monitor_setup.stdout_lines }}"
when: monitor_setup.stdout is defined
- name: Read push URL from file
slurp:
src: /tmp/phoenixd_push_url.txt
delegate_to: localhost
become: no
register: push_url_file
ignore_errors: yes
- name: Parse push URL
set_fact:
phoenixd_push_url: "{{ push_url_file.content | b64decode | trim }}"
when: push_url_file.content is defined
- name: Update health check service with push URL
lineinfile:
path: "/etc/systemd/system/{{ phoenixd_healthcheck_service_name }}.service"
regexp: "^Environment=UPTIME_KUMA_PUSH_URL="
line: "Environment=UPTIME_KUMA_PUSH_URL={{ phoenixd_push_url }}"
when: phoenixd_push_url is defined
notify: Restart phoenixd health check timer
- name: Clean up temporary files
delegate_to: localhost
become: no
file:
path: "{{ item }}"
state: absent
loop:
- /tmp/setup_phoenixd_monitor.py
- /tmp/ansible_phoenixd_config.yml
- /tmp/phoenixd_push_url.txt
# ===========================================
# Post-install Notes
# ===========================================
- name: Display post-install information
debug:
msg: |
✓ phoenixd {{ phoenixd_version }} deployed
Status: systemctl status phoenixd
Logs: journalctl -u phoenixd -f
CLI: sudo PHOENIX_DATADIR={{ phoenixd_data_dir }} phoenix-cli --http-bind-port {{ phoenixd_http_bind_port }} getinfo
HTTP API: http://{{ phoenixd_http_bind_ip }}:{{ phoenixd_http_bind_port }} (loopback only)
Data dir: {{ phoenixd_data_dir }}
API password (needed to wire LNBits up to this node):
sudo grep '^http-password=' {{ phoenixd_data_dir }}/phoenix.conf
⚠️ BACK UP THE SEED NOW: {{ phoenixd_data_dir }}/seed.dat
Losing it means losing the funds. Run
services/phoenixd/setup_backup_phoenixd_to_lapy.yml and also keep
the 12 words somewhere offline.
handlers:
- name: Restart phoenixd
systemd:
name: phoenixd
state: restarted
daemon_reload: yes
- name: Restart phoenixd health check timer
systemd:
name: "{{ phoenixd_healthcheck_service_name }}.timer"
state: restarted
daemon_reload: yes

View file

@ -0,0 +1,52 @@
# phoenixd Configuration Variables
# https://phoenix.acinq.co/server
# Version - pin to a specific release tag
phoenixd_version: "0.9.0"
phoenixd_arch: "linux-x64"
phoenixd_url: "https://github.com/ACINQ/phoenixd/releases/download/v{{ phoenixd_version }}/phoenixd-{{ phoenixd_version }}-{{ phoenixd_arch }}.zip"
# Service user
phoenixd_user: phoenix
phoenixd_group: phoenix
# Directories
phoenixd_home: /opt/phoenixd
# phoenixd resolves its data dir from PHOENIX_DATADIR; seed.dat, phoenix.conf
# and the channel db all live here.
phoenixd_data_dir: "{{ phoenixd_home }}/.phoenix"
phoenixd_bin_dir: /usr/local/bin
# Lightning settings
phoenixd_chain: mainnet
# Amount automatically requested when inbound liquidity is needed: off, 2m, 5m, 10m
phoenixd_auto_liquidity: "2m"
# Max mining fee for on-chain operations, in sats. Empty means phoenixd's default.
phoenixd_max_mining_fee: ""
# Required for non-interactive deployment
phoenixd_agree_tos: true
# HTTP API
# Stays on loopback: phoenixd is never exposed through Caddy, only local
# consumers (e.g. LNBits on the same host) talk to it.
phoenixd_http_bind_ip: "127.0.0.1"
phoenixd_http_bind_port: 9740
# Optional webhook for payment events. Leave empty to disable.
phoenixd_webhook_url: ""
# Monitoring
phoenixd_healthcheck_script_path: /usr/local/bin/phoenixd-healthcheck-push.sh
phoenixd_healthcheck_service_name: phoenixd-healthcheck
phoenixd_monitor_name: "Phoenixd"
# Remote access
remote_host_name: "vipy"
remote_host: "{{ hostvars.get(remote_host_name, {}).get('ansible_host', remote_host_name) }}"
remote_user: "{{ hostvars.get(remote_host_name, {}).get('ansible_user', 'counterweight') }}"
remote_key_file: "{{ hostvars.get(remote_host_name, {}).get('ansible_ssh_private_key_file', '') }}"
remote_port: "{{ hostvars.get(remote_host_name, {}).get('ansible_port', 22) }}"
# Local backup
local_backup_dir: "{{ lookup('env', 'HOME') }}/phoenixd-backups"
backup_script_path: "{{ lookup('env', 'HOME') }}/.local/bin/phoenixd_backup.sh"

View file

@ -0,0 +1,136 @@
---
# Backs up the phoenixd seed and config from vipy to Lapy, gpg encrypted.
#
# Only seed.dat and phoenix.conf are backed up, on purpose:
# - seed.dat is what actually recovers the funds. phoenixd keeps its channel
# state with the ACINQ peer, so a wallet is restored from the seed alone.
# - restoring a *stale* channel database to a running Lightning node is
# dangerous (it can trigger a force close and a penalty), so we do not keep
# copies of phoenix.db around to be tempted by.
# - phoenix.conf holds the http api password, which is what LNBits and any
# other local consumer authenticate with.
#
# Because both files are static, phoenixd does not need to be stopped.
- name: Configure local backup for phoenixd from remote
hosts: lapy
gather_facts: no
vars_files:
- ../../infra_vars.yml
- ./phoenixd_vars.yml
vars:
remote_data_path: "{{ phoenixd_data_dir }}"
gpg_recipient: "{{ hostvars['localhost']['gpg_recipient'] | default('') }}"
gpg_key_id: "{{ hostvars['localhost']['gpg_key_id'] | default('') }}"
tasks:
- name: Debug phoenixd backup vars
debug:
msg:
- "remote_host={{ remote_host }}"
- "remote_user={{ remote_user }}"
- "remote_data_path='{{ remote_data_path }}'"
- "local_backup_dir={{ local_backup_dir }}"
- "gpg_recipient={{ gpg_recipient }}"
- "gpg_key_id={{ gpg_key_id }}"
- name: Ensure local backup directory exists
ansible.builtin.file:
path: "{{ local_backup_dir }}"
state: directory
mode: "0700"
- name: Ensure ~/.local/bin exists
ansible.builtin.file:
path: "{{ lookup('env', 'HOME') }}/.local/bin"
state: directory
mode: "0755"
- name: Create phoenixd backup script
ansible.builtin.copy:
dest: "{{ backup_script_path }}"
mode: "0750"
content: |
#!/bin/bash
set -euo pipefail
if [ -z "{{ gpg_recipient }}" ]; then
echo "GPG recipient is not configured. Aborting."
exit 1
fi
TIMESTAMP=$(date +'%Y-%m-%d')
ENCRYPTED_BACKUP="{{ local_backup_dir }}/phoenixd-backup-$TIMESTAMP.tar.gz.gpg"
{% if remote_key_file %}
SSH_CMD="ssh -i {{ remote_key_file }} -p {{ remote_port }}"
{% else %}
SSH_CMD="ssh -p {{ remote_port }}"
{% endif %}
# seed.dat + phoenix.conf only, see the header of the playbook.
echo "Creating encrypted backup archive..."
$SSH_CMD {{ remote_user }}@{{ remote_host }} \
"sudo tar -czf - -C {{ remote_data_path }} seed.dat phoenix.conf" | \
gpg --batch --yes --encrypt --recipient "{{ gpg_recipient }}" --output "$ENCRYPTED_BACKUP"
chmod 600 "$ENCRYPTED_BACKUP"
# Rotate old backups (keep 14 days)
CUTOFF_DATE=$(date -d '14 days ago' +'%Y-%m-%d')
for backup_file in "{{ local_backup_dir }}"/phoenixd-backup-*.tar.gz.gpg; do
if [ -f "$backup_file" ]; then
# Extract date from filename: phoenixd-backup-YYYY-MM-DD.tar.gz.gpg
file_date=$(basename "$backup_file" | sed -n 's/phoenixd-backup-\([0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}\)\.tar\.gz\.gpg/\1/p')
if [ -n "$file_date" ] && [ "$file_date" != "$TIMESTAMP" ] && [ "$file_date" \< "$CUTOFF_DATE" ]; then
rm -f "$backup_file"
fi
fi
done
echo "Backup completed successfully"
- name: Ensure cronjob for phoenixd backup exists
ansible.builtin.cron:
name: "phoenixd backup"
user: "{{ lookup('env', 'USER') }}"
job: "{{ backup_script_path }}"
minute: 15
hour: "9"
- name: Run phoenixd backup script to create initial backup
ansible.builtin.command: "{{ backup_script_path }}"
- name: Verify backup was created
block:
- name: Get today's date
command: date +'%Y-%m-%d'
register: today_date
changed_when: false
- name: Check if backup file exists
stat:
path: "{{ local_backup_dir }}/phoenixd-backup-{{ today_date.stdout }}.tar.gz.gpg"
register: backup_file_stat
- name: Verify backup file exists
assert:
that:
- backup_file_stat.stat.exists
- backup_file_stat.stat.isreg
fail_msg: "Backup file {{ local_backup_dir }}/phoenixd-backup-{{ today_date.stdout }}.tar.gz.gpg was not created"
success_msg: "Backup file {{ local_backup_dir }}/phoenixd-backup-{{ today_date.stdout }}.tar.gz.gpg exists"
- name: Verify backup file is not empty
assert:
that:
- backup_file_stat.stat.size > 0
fail_msg: "Backup file {{ local_backup_dir }}/phoenixd-backup-{{ today_date.stdout }}.tar.gz.gpg exists but is empty"
success_msg: "Backup file size is {{ backup_file_stat.stat.size }} bytes"
- name: Remind about the offline seed copy
debug:
msg: |
These encrypted backups are only as safe as your GPG key.
Also write the 12 words down offline once:
ssh {{ remote_user }}@{{ remote_host }} "sudo cat {{ remote_data_path }}/seed.dat"