Files
homelab/ansible/roles/paperclip-docker
rblundon 881e2e24a8 Add shared nginx-proxy role; deploy Hermes in Docker; rename Paperclip
nginx-proxy (new role):
- Shared nginx + certbot under /opt/nginx, replacing the copies that
  lived inside the Paperclip compose project
- Apps publish via tasks_from: add_vhost (cert marker -> issue cert ->
  write vhost -> nginx -t -> reload); a vhost that fails nginx -t is
  rolled back
- Certs issued one per domain via Cloudflare DNS challenge; domains
  registered as marker files in cert-domains/; optional LE staging
- Stock nginx.conf plus conf.d (directory mounts, not single-file
  mounts); catch-all server drops unknown Host/SNI
- Containers renamed to nginx and certbot

hermes_docker (new role):
- Official Hermes image, host networking, gateway and dashboard bound
  to loopback and published through nginx-proxy
- Dashboard login via basic-auth provider, secrets from the vault
- Main model set from hermes_model (fantasmic endpoint, key from vault);
  config.yaml overrides are merged from a 0600 staged file that is
  removed afterwards, so the key never appears in a command line
- Data dir owner-only (HERMES_HOME_MODE=0700)

paperclip-docker:
- Remove nginx, certbot and docker-compose download tasks; deploy with
  community.docker.docker_compose_v2 (idempotent, remove_orphans)
- Stop passing the Cloudflare token and certbot email to the Paperclip
  container via env_file
- Bind Postgres to 127.0.0.1 (host networking exposed it on all
  interfaces); stop chowning pgdata, which the postgres image owns
- Handler recreates the paperclip service so .env changes apply
- Domain m-v.wdw-labs.cloud -> cranium-command.wdw-labs.cloud

Playbooks:
- Add day1_deploy_nginx_proxy.yml and day1_deploy_hermes_docker.yml
- deploy_paperclip_stack.yml: run nginx-proxy before paperclip-docker,
  CLI-based container checks (no Docker SDK dependency)
- Remove deploy-hermes.yml

Host vars: add nginx_proxy_certbot_email and nginx_proxy_certbot_staging
(staging stays on until the switch to real certs).
2026-09-30 23:12:40 -05:00
..


  • name: Install Docker SDK for Python apt: name: python3-docker state: present become: yes

  • name: Download latest docker-compose from GitHub shell: | curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose become: yes

  • name: Verify docker-compose installation shell: /usr/local/bin/docker-compose --version register: compose_version become: yes

  • name: Show docker-compose version debug: msg: "{{ compose_version.stdout }}"

  • name: Create paperclip directories file: path: "{{ item }}" state: directory mode: '0755' owner: root group: root loop:

    • "{{ paperclip_base_path }}"
    • "{{ paperclip_data_dir }}"
    • "{{ paperclip_certs_dir }}"
    • "{{ paperclip_base_path }}/pgdata" become: yes
  • name: Generate BETTER_AUTH_SECRET shell: openssl rand -hex 24 register: better_auth_secret changed_when: false no_log: yes

  • name: Generate PAPERCLIP_AGENT_JWT_SECRET shell: openssl rand -hex 24 register: paperclip_jwt_secret changed_when: false no_log: yes

  • name: Write secrets and configuration to .env copy: content: | # Authentication secrets (auto-generated during deployment) BETTER_AUTH_SECRET={{ better_auth_secret.stdout }} PAPERCLIP_AGENT_JWT_SECRET={{ paperclip_jwt_secret.stdout }}

    # Infrastructure configuration
    CLOUDFLARE_API_TOKEN={{ vault_cloudflare_api_token }}
    CERTBOT_EMAIL={{ certbot_email }}
    PAPERCLIP_DOMAIN={{ paperclip_domain }}
    VLLM_ENDPOINT={{ vllm_endpoint }}
    

    dest: "{{ paperclip_base_path }}/.env" mode: '0600' owner: root group: root become: yes no_log: yes

  • name: Template docker-compose.yml template: src: docker-compose.yml.j2 dest: "{{ paperclip_base_path }}/docker-compose.yml" mode: '0644' owner: root group: root become: yes notify: Restart paperclip stack

  • name: Template nginx config template: src: nginx.conf.j2 dest: "{{ paperclip_base_path }}/nginx.conf" mode: '0644' owner: root group: root become: yes notify: Reload nginx

  • name: Template certbot init script template: src: certbot-init.sh.j2 dest: "{{ paperclip_base_path }}/certbot-init.sh" mode: '0755' owner: root group: root become: yes

  • name: Stop and remove old containers shell: | cd {{ paperclip_base_path }} /usr/local/bin/docker-compose down -v --remove-orphans 2>/dev/null || true become: yes ignore_errors: yes

  • name: Deploy docker compose stack shell: | cd {{ paperclip_base_path }} /usr/local/bin/docker-compose up -d become: yes register: compose_result

  • name: Wait for Paperclip to be ready uri: url: "http://localhost:{{ paperclip_port }}/health" status_code: 200 register: result until: result.status == 200 retries: 30 delay: 5 ignore_errors: yes

  • name: Wait for nginx to be ready uri: url: "https://{{ paperclip_domain }}/" validate_certs: no status_code: [200, 301, 302] register: result until: result.status in [200, 301, 302] retries: 30 delay: 5 ignore_errors: yes

  • name: Verify Paperclip is accessible via https debug: msg: "Paperclip is accessible at https://{{ paperclip_domain }}" when: result.status is defined and result.status in [200, 301, 302]