From d82c9afbe52f2c903089750a06b0d7a3b260a22b Mon Sep 17 00:00:00 2001 From: counterweight Date: Sun, 14 Dec 2025 22:15:29 +0100 Subject: [PATCH] mempool working --- .../mempool/deploy_mempool_playbook.yml | 751 ++++++++++++++++++ ansible/services/mempool/mempool_vars.yml | 33 + ansible/services_config.yml | 3 + tofu/nodito/main.tf | 11 +- 4 files changed, 788 insertions(+), 10 deletions(-) create mode 100644 ansible/services/mempool/deploy_mempool_playbook.yml create mode 100644 ansible/services/mempool/mempool_vars.yml diff --git a/ansible/services/mempool/deploy_mempool_playbook.yml b/ansible/services/mempool/deploy_mempool_playbook.yml new file mode 100644 index 0000000..862e21b --- /dev/null +++ b/ansible/services/mempool/deploy_mempool_playbook.yml @@ -0,0 +1,751 @@ +- name: Deploy Mempool Block Explorer with Docker + hosts: mempool_box_local + become: yes + vars_files: + - ../../infra_vars.yml + - ../../services_config.yml + - ../../infra_secrets.yml + - ./mempool_vars.yml + vars: + mempool_subdomain: "{{ subdomains.mempool }}" + mempool_domain: "{{ mempool_subdomain }}.{{ root_domain }}" + uptime_kuma_api_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}" + + tasks: + # =========================================== + # Docker Installation (from 910_docker_playbook.yml) + # =========================================== + - name: Remove old Docker-related packages + apt: + name: + - docker.io + - docker-doc + - docker-compose + - podman-docker + - containerd + - runc + state: absent + purge: yes + autoremove: yes + + - name: Update apt cache + apt: + update_cache: yes + + - name: Install prerequisites + apt: + name: + - ca-certificates + - curl + state: present + + - name: Create directory for Docker GPG key + file: + path: /etc/apt/keyrings + state: directory + mode: '0755' + + - name: Download Docker GPG key + get_url: + url: https://download.docker.com/linux/debian/gpg + dest: /etc/apt/keyrings/docker.asc + mode: '0644' + + - name: Get Debian architecture + command: dpkg --print-architecture + register: deb_arch + changed_when: false + + - name: Add Docker repository + apt_repository: + repo: "deb [arch={{ deb_arch.stdout }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable" + filename: docker + state: present + update_cache: yes + + - name: Install Docker packages + apt: + name: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + state: present + update_cache: yes + + - name: Ensure Docker is started and enabled + systemd: + name: docker + enabled: yes + state: started + + - name: Add user to docker group + user: + name: "{{ ansible_user }}" + groups: docker + append: yes + + # =========================================== + # Mempool Deployment + # =========================================== + - name: Create mempool directories + file: + path: "{{ item }}" + state: directory + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0755' + loop: + - "{{ mempool_dir }}" + - "{{ mempool_data_dir }}" + - "{{ mempool_mysql_dir }}" + + - name: Create docker-compose.yml for Mempool + copy: + dest: "{{ mempool_dir }}/docker-compose.yml" + content: | + # All containers use host network for Tailscale MagicDNS resolution + services: + mariadb: + image: mariadb:10.11 + container_name: mempool-db + restart: unless-stopped + network_mode: host + environment: + MYSQL_DATABASE: "{{ mariadb_database }}" + MYSQL_USER: "{{ mariadb_user }}" + MYSQL_PASSWORD: "{{ mariadb_mempool_password }}" + MYSQL_ROOT_PASSWORD: "{{ mariadb_mempool_password }}" + volumes: + - {{ mempool_mysql_dir }}:/var/lib/mysql + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + mempool-backend: + image: mempool/backend:{{ mempool_version }} + container_name: mempool-backend + restart: unless-stopped + network_mode: host + environment: + # Database (localhost since all containers share host network) + DATABASE_ENABLED: "true" + DATABASE_HOST: "127.0.0.1" + DATABASE_DATABASE: "{{ mariadb_database }}" + DATABASE_USERNAME: "{{ mariadb_user }}" + DATABASE_PASSWORD: "{{ mariadb_mempool_password }}" + # Bitcoin Core/Knots (via Tailnet MagicDNS) + CORE_RPC_HOST: "{{ bitcoin_host }}" + CORE_RPC_PORT: "{{ bitcoin_rpc_port }}" + CORE_RPC_USERNAME: "{{ bitcoin_rpc_user }}" + CORE_RPC_PASSWORD: "{{ bitcoin_rpc_password }}" + # Electrum (Fulcrum via Tailnet MagicDNS) + ELECTRUM_HOST: "{{ fulcrum_host }}" + ELECTRUM_PORT: "{{ fulcrum_port }}" + ELECTRUM_TLS_ENABLED: "{{ fulcrum_tls }}" + # Mempool settings + MEMPOOL_NETWORK: "{{ mempool_network }}" + MEMPOOL_BACKEND: "electrum" + MEMPOOL_CLEAR_PROTECTION_MINUTES: "20" + MEMPOOL_INDEXING_BLOCKS_AMOUNT: "52560" + volumes: + - {{ mempool_data_dir }}:/backend/cache + depends_on: + mariadb: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8999/api/v1/backend-info"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + + mempool-frontend: + image: mempool/frontend:{{ mempool_version }} + container_name: mempool-frontend + restart: unless-stopped + network_mode: host + environment: + FRONTEND_HTTP_PORT: "{{ mempool_frontend_port }}" + BACKEND_MAINNET_HTTP_HOST: "127.0.0.1" + depends_on: + - mempool-backend + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:{{ mempool_frontend_port }}"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + owner: "{{ ansible_user }}" + group: "{{ ansible_user }}" + mode: '0644' + + - name: Pull Mempool images + command: docker compose pull + args: + chdir: "{{ mempool_dir }}" + + - name: Deploy Mempool containers with docker compose + command: docker compose up -d + args: + chdir: "{{ mempool_dir }}" + + - name: Wait for MariaDB to be healthy + command: docker inspect --format='{{ '{{' }}.State.Health.Status{{ '}}' }}' mempool-db + register: mariadb_health + until: mariadb_health.stdout == 'healthy' + retries: 30 + delay: 10 + changed_when: false + + - name: Wait for Mempool backend to start + uri: + url: "http://localhost:{{ mempool_backend_port }}/api/v1/backend-info" + method: GET + status_code: 200 + timeout: 10 + register: backend_check + until: backend_check.status == 200 + retries: 30 + delay: 10 + ignore_errors: yes + + - name: Wait for Mempool frontend to be available + uri: + url: "http://localhost:{{ mempool_frontend_port }}" + method: GET + status_code: 200 + timeout: 10 + register: frontend_check + until: frontend_check.status == 200 + retries: 20 + delay: 5 + ignore_errors: yes + + - name: Display deployment status + debug: + msg: + - "Mempool deployment complete!" + - "Frontend: http://localhost:{{ mempool_frontend_port }}" + - "Backend API: http://localhost:{{ mempool_backend_port }}/api/v1/backend-info" + - "Backend check: {{ 'OK' if backend_check.status == 200 else 'Still initializing...' }}" + - "Frontend check: {{ 'OK' if frontend_check.status == 200 else 'Still initializing...' }}" + + # =========================================== + # Health Check Scripts for Uptime Kuma Push Monitors + # =========================================== + - name: Create Mempool MariaDB health check script + copy: + dest: /usr/local/bin/mempool-mariadb-healthcheck-push.sh + content: | + #!/bin/bash + UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}" + + check_container() { + local status=$(docker inspect --format='{{ '{{' }}.State.Health.Status{{ '}}' }}' mempool-db 2>/dev/null) + [ "$status" = "healthy" ] + } + + 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_container; then + push_to_uptime_kuma "up" "OK" + exit 0 + else + push_to_uptime_kuma "down" "MariaDB container unhealthy" + exit 1 + fi + owner: root + group: root + mode: '0755' + + - name: Create Mempool backend health check script + copy: + dest: /usr/local/bin/mempool-backend-healthcheck-push.sh + content: | + #!/bin/bash + UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}" + BACKEND_PORT={{ mempool_backend_port }} + + check_backend() { + curl -sf --max-time 5 "http://localhost:${BACKEND_PORT}/api/v1/backend-info" > /dev/null 2>&1 + } + + 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_backend; then + push_to_uptime_kuma "up" "OK" + exit 0 + else + push_to_uptime_kuma "down" "Backend API not responding" + exit 1 + fi + owner: root + group: root + mode: '0755' + + - name: Create Mempool frontend health check script + copy: + dest: /usr/local/bin/mempool-frontend-healthcheck-push.sh + content: | + #!/bin/bash + UPTIME_KUMA_PUSH_URL="${UPTIME_KUMA_PUSH_URL}" + FRONTEND_PORT={{ mempool_frontend_port }} + + check_frontend() { + curl -sf --max-time 5 "http://localhost:${FRONTEND_PORT}" > /dev/null 2>&1 + } + + 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_frontend; then + push_to_uptime_kuma "up" "OK" + exit 0 + else + push_to_uptime_kuma "down" "Frontend not responding" + exit 1 + fi + owner: root + group: root + mode: '0755' + + # =========================================== + # Systemd Timers for Health Checks + # =========================================== + - name: Create systemd services for health checks + copy: + dest: "/etc/systemd/system/mempool-{{ item.name }}-healthcheck.service" + content: | + [Unit] + Description=Mempool {{ item.label }} Health Check + After=network.target docker.service + + [Service] + Type=oneshot + User=root + ExecStart=/usr/local/bin/mempool-{{ item.name }}-healthcheck-push.sh + Environment=UPTIME_KUMA_PUSH_URL= + StandardOutput=journal + StandardError=journal + + [Install] + WantedBy=multi-user.target + owner: root + group: root + mode: '0644' + loop: + - { name: "mariadb", label: "MariaDB" } + - { name: "backend", label: "Backend" } + - { name: "frontend", label: "Frontend" } + + - name: Create systemd timers for health checks + copy: + dest: "/etc/systemd/system/mempool-{{ item }}-healthcheck.timer" + content: | + [Unit] + Description=Mempool {{ item }} Health Check Timer + + [Timer] + OnBootSec=2min + OnUnitActiveSec=1min + Persistent=true + + [Install] + WantedBy=timers.target + owner: root + group: root + mode: '0644' + loop: + - mariadb + - backend + - frontend + + - name: Reload systemd daemon + systemd: + daemon_reload: yes + + - name: Enable and start health check timers + systemd: + name: "mempool-{{ item }}-healthcheck.timer" + enabled: yes + state: started + loop: + - mariadb + - backend + - frontend + + # =========================================== + # Uptime Kuma Push Monitor Setup + # =========================================== + - name: Create Uptime Kuma push monitor setup script for Mempool + delegate_to: localhost + become: no + copy: + dest: /tmp/setup_mempool_monitors.py + content: | + #!/usr/bin/env python3 + import sys + import traceback + import yaml + from uptime_kuma_api import UptimeKumaApi, MonitorType + + try: + with open('/tmp/ansible_mempool_config.yml', 'r') as f: + config = yaml.safe_load(f) + + url = config['uptime_kuma_url'] + username = config['username'] + password = config['password'] + monitors_to_create = config['monitors'] + + 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: + api.add_monitor(type='group', name='services') + 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 + + results = {} + for monitor_name in monitors_to_create: + existing = next((m for m in monitors if m.get('name') == monitor_name), 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: + results[monitor_name] = f"{url}/api/push/{push_token}" + print(f"Push URL ({monitor_name}): {results[monitor_name]}") + else: + print(f"Creating push monitor '{monitor_name}'...") + api.add_monitor( + type=MonitorType.PUSH, + name=monitor_name, + parent=group['id'], + interval=60, + maxretries=3, + retryInterval=60, + notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {} + ) + 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: + results[monitor_name] = f"{url}/api/push/{push_token}" + print(f"Push URL ({monitor_name}): {results[monitor_name]}") + + api.disconnect() + print("SUCCESS") + + # Write results to file for Ansible to read + with open('/tmp/mempool_push_urls.yml', 'w') as f: + yaml.dump(results, f) + + 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 monitor setup + delegate_to: localhost + become: no + copy: + dest: /tmp/ansible_mempool_config.yml + content: | + uptime_kuma_url: "{{ uptime_kuma_api_url }}" + username: "{{ uptime_kuma_username }}" + password: "{{ uptime_kuma_password }}" + monitors: + - "Mempool MariaDB" + - "Mempool Backend" + - "Mempool Frontend" + mode: '0644' + + - name: Run Uptime Kuma push monitor setup + command: python3 /tmp/setup_mempool_monitors.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 URLs from file + slurp: + src: /tmp/mempool_push_urls.yml + delegate_to: localhost + become: no + register: push_urls_file + ignore_errors: yes + + - name: Parse push URLs + set_fact: + push_urls: "{{ push_urls_file.content | b64decode | from_yaml }}" + when: push_urls_file.content is defined + ignore_errors: yes + + - name: Update MariaDB health check service with push URL + lineinfile: + path: /etc/systemd/system/mempool-mariadb-healthcheck.service + regexp: '^Environment=UPTIME_KUMA_PUSH_URL=' + line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool MariaDB'] }}" + insertafter: '^\[Service\]' + when: push_urls is defined and push_urls['Mempool MariaDB'] is defined + + - name: Update Backend health check service with push URL + lineinfile: + path: /etc/systemd/system/mempool-backend-healthcheck.service + regexp: '^Environment=UPTIME_KUMA_PUSH_URL=' + line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool Backend'] }}" + insertafter: '^\[Service\]' + when: push_urls is defined and push_urls['Mempool Backend'] is defined + + - name: Update Frontend health check service with push URL + lineinfile: + path: /etc/systemd/system/mempool-frontend-healthcheck.service + regexp: '^Environment=UPTIME_KUMA_PUSH_URL=' + line: "Environment=UPTIME_KUMA_PUSH_URL={{ push_urls['Mempool Frontend'] }}" + insertafter: '^\[Service\]' + when: push_urls is defined and push_urls['Mempool Frontend'] is defined + + - name: Reload systemd after push URL updates + systemd: + daemon_reload: yes + when: push_urls is defined + + - name: Restart health check timers + systemd: + name: "mempool-{{ item }}-healthcheck.timer" + state: restarted + loop: + - mariadb + - backend + - frontend + when: push_urls is defined + + - name: Clean up temporary files + delegate_to: localhost + become: no + file: + path: "{{ item }}" + state: absent + loop: + - /tmp/setup_mempool_monitors.py + - /tmp/ansible_mempool_config.yml + - /tmp/mempool_push_urls.yml + +- name: Configure Caddy reverse proxy for Mempool on vipy + hosts: vipy + become: yes + vars_files: + - ../../infra_vars.yml + - ../../services_config.yml + - ../../infra_secrets.yml + - ./mempool_vars.yml + vars: + mempool_subdomain: "{{ subdomains.mempool }}" + mempool_domain: "{{ mempool_subdomain }}.{{ root_domain }}" + caddy_sites_dir: "{{ caddy_sites_dir }}" + + tasks: + - name: Ensure Caddy sites-enabled directory exists + file: + path: "{{ caddy_sites_dir }}" + state: directory + owner: root + group: root + mode: '0755' + + - name: Ensure Caddyfile includes import directive for sites-enabled + lineinfile: + path: /etc/caddy/Caddyfile + line: 'import sites-enabled/*' + insertafter: EOF + state: present + backup: yes + create: yes + mode: '0644' + + - name: Create Caddy reverse proxy configuration for Mempool + copy: + dest: "{{ caddy_sites_dir }}/mempool.conf" + content: | + {{ mempool_domain }} { + reverse_proxy mempool-box:{{ mempool_frontend_port }} { + # Use Tailscale MagicDNS to resolve the upstream hostname + transport http { + resolvers 100.100.100.100 + } + } + } + owner: root + group: root + mode: '0644' + + - name: Reload Caddy to apply new config + systemd: + name: caddy + state: reloaded + + - name: Display Mempool URL + debug: + msg: "Mempool is now available at https://{{ mempool_domain }}" + + # =========================================== + # Uptime Kuma HTTP Monitor for Public Endpoint + # =========================================== + - name: Create Uptime Kuma HTTP monitor setup script for Mempool + delegate_to: localhost + become: no + copy: + dest: /tmp/setup_mempool_http_monitor.py + content: | + #!/usr/bin/env python3 + import sys + import traceback + import yaml + from uptime_kuma_api import UptimeKumaApi, MonitorType + + try: + with open('/tmp/ansible_mempool_http_config.yml', 'r') as f: + config = yaml.safe_load(f) + + url = config['uptime_kuma_url'] + username = config['username'] + password = config['password'] + monitor_url = config['monitor_url'] + 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: + api.add_monitor(type='group', name='services') + monitors = api.get_monitors() + group = next((m for m in monitors if m.get('name') == 'services' and m.get('type') == 'group'), None) + + # Check if monitor already exists + existing = next((m for m in monitors if m.get('name') == monitor_name), 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 + + if existing: + print(f"Monitor '{monitor_name}' already exists (ID: {existing['id']})") + print("Skipping - monitor already configured") + else: + print(f"Creating HTTP monitor '{monitor_name}'...") + api.add_monitor( + type=MonitorType.HTTP, + name=monitor_name, + url=monitor_url, + parent=group['id'], + interval=60, + maxretries=3, + retryInterval=60, + notificationIDList={ntfy_notification_id: True} if ntfy_notification_id else {} + ) + + api.disconnect() + 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 HTTP monitor setup + delegate_to: localhost + become: no + copy: + dest: /tmp/ansible_mempool_http_config.yml + content: | + uptime_kuma_url: "https://{{ subdomains.uptime_kuma }}.{{ root_domain }}" + username: "{{ uptime_kuma_username }}" + password: "{{ uptime_kuma_password }}" + monitor_url: "https://{{ mempool_domain }}" + monitor_name: "Mempool" + mode: '0644' + + - name: Run Uptime Kuma HTTP monitor setup + command: python3 /tmp/setup_mempool_http_monitor.py + delegate_to: localhost + become: no + register: http_monitor_setup + changed_when: "'SUCCESS' in http_monitor_setup.stdout" + ignore_errors: yes + + - name: Display HTTP monitor setup output + debug: + msg: "{{ http_monitor_setup.stdout_lines }}" + when: http_monitor_setup.stdout is defined + + - name: Clean up HTTP monitor temporary files + delegate_to: localhost + become: no + file: + path: "{{ item }}" + state: absent + loop: + - /tmp/setup_mempool_http_monitor.py + - /tmp/ansible_mempool_http_config.yml + diff --git a/ansible/services/mempool/mempool_vars.yml b/ansible/services/mempool/mempool_vars.yml new file mode 100644 index 0000000..d3051c3 --- /dev/null +++ b/ansible/services/mempool/mempool_vars.yml @@ -0,0 +1,33 @@ +# Mempool Configuration Variables + +# Version - Pinned to specific release +mempool_version: "v3.2.1" + +# Directories +mempool_dir: /opt/mempool +mempool_data_dir: "{{ mempool_dir }}/data" +mempool_mysql_dir: "{{ mempool_dir }}/mysql" + +# Network - Bitcoin Core/Knots connection (via Tailnet Magic DNS) +bitcoin_host: "knots-box" +bitcoin_rpc_port: 8332 +# Note: bitcoin_rpc_user and bitcoin_rpc_password are loaded from infra_secrets.yml + +# Network - Fulcrum Electrum server (via Tailnet Magic DNS) +fulcrum_host: "fulcrum-box" +fulcrum_port: 50001 +fulcrum_tls: "false" + +# Mempool network mode +mempool_network: "mainnet" + +# Container ports (internal) +mempool_frontend_port: 8080 +mempool_backend_port: 8999 + +# MariaDB settings +mariadb_database: "mempool" +mariadb_user: "mempool" +# Note: mariadb_mempool_password is loaded from infra_secrets.yml + + diff --git a/ansible/services_config.yml b/ansible/services_config.yml index b497c51..56cc570 100644 --- a/ansible/services_config.yml +++ b/ansible/services_config.yml @@ -21,6 +21,9 @@ subdomains: # Memos (on memos-box) memos: memos + + # Mempool Block Explorer (on mempool_box, proxied via vipy) + mempool: mempool # Caddy configuration caddy_sites_dir: /etc/caddy/sites-enabled diff --git a/tofu/nodito/main.tf b/tofu/nodito/main.tf index bfd400c..9123175 100644 --- a/tofu/nodito/main.tf +++ b/tofu/nodito/main.tf @@ -30,16 +30,7 @@ resource "proxmox_vm_qemu" "vm" { lifecycle { prevent_destroy = true - ignore_changes = [ - name, - cpu, - memory, - network, - ipconfig0, - ciuser, - sshkeys, - cicustom, - ] + ignore_changes = all } serial {