Deploy Paperclip AI with PostgreSQL, nginx reverse proxy, and Cloudflare SSL/TLS on illuminations.wdw-labs.cloud. Configured for local_trusted mode (LAN-only, no auth) with host networking and auto-generated secrets. Stack: PostgreSQL 16 + Paperclip + nginx + certbot Hostname: muppet-vision.wdw-labs.cloud vLLM endpoint: localhost:8000 (DeepSeek-R1-32B Q4)
142 lines
3.5 KiB
YAML
142 lines
3.5 KiB
YAML
---
|
|
- 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: Fix directory ownership for container user (UID 1000)
|
|
shell: |
|
|
chown -R 1000:1000 {{ paperclip_data_dir }}
|
|
chown -R 1000:1000 {{ 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 --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]
|
|
|