All checks were successful
CI / skip-ci-check (pull_request) Successful in 1m22s
CI / lint-and-test (pull_request) Successful in 1m27s
CI / ansible-validation (pull_request) Successful in 2m53s
CI / secret-scanning (pull_request) Successful in 1m24s
CI / dependency-scan (pull_request) Successful in 1m28s
CI / sast-scan (pull_request) Successful in 2m32s
CI / license-check (pull_request) Successful in 1m28s
CI / vault-check (pull_request) Successful in 2m30s
CI / playbook-test (pull_request) Successful in 2m32s
CI / container-scan (pull_request) Successful in 1m53s
CI / sonar-analysis (pull_request) Successful in 2m40s
CI / workflow-summary (pull_request) Successful in 1m22s
- Fix deploy script to handle non-git directories by cloning to temp location and moving contents, preserving .env files during clone - Remove comment lines from env.j2 template to prevent xargs errors - Add initial deploy task to app_setup role to ensure app is deployed before service starts - Fix migrate command precedence to check env-specific overrides first - Add sudo to systemctl restart commands in deploy script - Update documentation with project-specific configuration notes These changes improve deployment reliability for all app projects while adding support for mirrormatch-specific requirements (db:push, seeding). All changes are backward-compatible with existing projects (pote, punimTag).
388 lines
12 KiB
YAML
388 lines
12 KiB
YAML
---
|
|
# Common variables for all hosts
|
|
timezone: America/Toronto
|
|
locale: en_US.UTF-8
|
|
ansible_python_interpreter: /usr/bin/python3
|
|
|
|
# Debug settings
|
|
ansible_debug_output: false
|
|
|
|
# Security settings
|
|
fail2ban_bantime: 3600
|
|
fail2ban_findtime: 600
|
|
fail2ban_maxretry: 3
|
|
|
|
# Maintenance settings
|
|
maintenance_default_serial: "100%" # Default serial execution for maintenance
|
|
maintenance_reboot_timeout: 300 # Reboot timeout in seconds
|
|
maintenance_pre_reboot_delay: 5 # Delay before reboot in seconds
|
|
|
|
# Global variables for all hosts
|
|
|
|
# Tailscale configuration
|
|
# Store your actual auth key in vault_tailscale_auth_key using ansible-vault
|
|
# Example: ansible-vault create group_vars/all/vault.yml
|
|
# vault_tailscale_auth_key: "tskey-auth-your-actual-key-here"
|
|
|
|
# Default Tailscale settings - these tell the playbook to use your vault key
|
|
tailscale_auth_key: "{{ vault_tailscale_auth_key | default('') }}"
|
|
tailscale_accept_routes: true
|
|
tailscale_accept_dns: true
|
|
tailscale_ssh: false
|
|
tailscale_hostname: "{{ inventory_hostname }}"
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Proxmox + modular app projects (LXC-first)
|
|
#
|
|
# This repo can manage many independent apps ("projects"). Each project defines
|
|
# its own dev/qa/prod guests (IPs/VMIDs/branches) under `app_projects`.
|
|
#
|
|
# Usage examples:
|
|
# - Run one project: ansible-playbook -i inventories/production playbooks/app/site.yml -e app_project=projectA
|
|
# - Run all projects: ansible-playbook -i inventories/production playbooks/app/site.yml
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# Proxmox API connection (keep secrets in vault)
|
|
proxmox_host: "{{ vault_proxmox_host }}"
|
|
proxmox_user: "{{ vault_proxmox_user }}"
|
|
proxmox_node: "{{ vault_proxmox_node | default('pve') }}"
|
|
proxmox_api_port: "{{ vault_proxmox_api_port | default(8006) }}"
|
|
# Proxmox commonly uses a self-signed cert; keep validation off by default.
|
|
proxmox_validate_certs: false
|
|
|
|
# Prefer API token auth (store in vault):
|
|
# - proxmox_token_id: "ansible@pve!token-name"
|
|
# - vault_proxmox_token: "secret"
|
|
proxmox_token_id: "{{ vault_proxmox_token_id | default('') }}"
|
|
|
|
# Default guest type for new projects. (Later you can set to `kvm` per project/env.)
|
|
proxmox_guest_type: lxc
|
|
|
|
# Proxmox LXC defaults (override per project/env as needed)
|
|
lxc_ostemplate: "local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst"
|
|
lxc_storage: "local-lvm"
|
|
lxc_network_bridge: "vmbr0"
|
|
lxc_unprivileged: true
|
|
lxc_features_list:
|
|
- "keyctl=1"
|
|
- "nesting=1"
|
|
lxc_start_after_create: true
|
|
lxc_nameserver: "1.1.1.1 8.8.8.8"
|
|
|
|
# Base OS / access defaults
|
|
appuser_name: appuser
|
|
appuser_shell: /bin/bash
|
|
appuser_groups:
|
|
- sudo
|
|
# Store your workstation public key in vault_ssh_public_key
|
|
appuser_ssh_public_key: "{{ vault_ssh_public_key }}"
|
|
|
|
# App defaults (override per project)
|
|
app_backend_port: 3001
|
|
app_frontend_port: 3000
|
|
|
|
# Default Node workflow commands (override per project if your app differs)
|
|
app_backend_install_cmd: "npm ci"
|
|
app_backend_migrate_cmd: "npm run migrate"
|
|
app_backend_start_cmd: "npm start"
|
|
|
|
app_frontend_install_cmd: "npm ci"
|
|
app_frontend_build_cmd: "npm run build"
|
|
app_frontend_start_cmd: "npm start"
|
|
|
|
# Projects definition: add as many projects as you want here.
|
|
# Each project has envs (dev/qa/prod) defining name/vmid/ip/gateway/branch and
|
|
# optional env_vars (dummy placeholders by default).
|
|
#
|
|
# -----------------------------------------------------------------------------
|
|
# Proxmox VMID/CTID ranges (DEDICATED; avoid collisions)
|
|
#
|
|
# Proxmox IDs are global. Never reuse IDs across unrelated guests.
|
|
# Suggested reservation table (edit to your preference):
|
|
# - 9000-9099: pote
|
|
# - 9100-9199: punimTagFE
|
|
# - 9200-9299: punimTagBE
|
|
# - 9300-9399: projectA (example)
|
|
# -----------------------------------------------------------------------------
|
|
app_projects:
|
|
projectA:
|
|
description: "Example full-stack app (edit repo_url, IPs, secrets)."
|
|
repo_url: "git@github.com:example/projectA.git"
|
|
components:
|
|
backend: true
|
|
frontend: true
|
|
|
|
|
|
# Repo is assumed to contain `backend/` and `frontend/` directories.
|
|
repo_dest: "/srv/app"
|
|
|
|
# Optional overrides for this project
|
|
backend_port: "{{ app_backend_port }}"
|
|
frontend_port: "{{ app_frontend_port }}"
|
|
|
|
guest_defaults:
|
|
guest_type: "{{ proxmox_guest_type }}"
|
|
cores: 2
|
|
memory_mb: 2048
|
|
swap_mb: 512
|
|
rootfs_size_gb: 16
|
|
|
|
deploy:
|
|
backend_install_cmd: "{{ app_backend_install_cmd }}"
|
|
backend_migrate_cmd: "{{ app_backend_migrate_cmd }}"
|
|
backend_start_cmd: "{{ app_backend_start_cmd }}"
|
|
frontend_install_cmd: "{{ app_frontend_install_cmd }}"
|
|
frontend_build_cmd: "{{ app_frontend_build_cmd }}"
|
|
frontend_start_cmd: "{{ app_frontend_start_cmd }}"
|
|
|
|
envs:
|
|
dev:
|
|
name: "projectA-dev"
|
|
vmid: 9301
|
|
ip: "10.0.10.101/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "dev"
|
|
env_vars:
|
|
APP_ENV: "dev"
|
|
BACKEND_BASE_URL: "http://10.0.10.101:{{ app_backend_port }}"
|
|
FRONTEND_BASE_URL: "http://10.0.10.101:{{ app_frontend_port }}"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
qa:
|
|
name: "projectA-qa"
|
|
vmid: 9302
|
|
ip: "10.0.10.102/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "qa"
|
|
env_vars:
|
|
APP_ENV: "qa"
|
|
BACKEND_BASE_URL: "http://10.0.10.102:{{ app_backend_port }}"
|
|
FRONTEND_BASE_URL: "http://10.0.10.102:{{ app_frontend_port }}"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
prod:
|
|
name: "projectA-prod"
|
|
vmid: 9303
|
|
ip: "10.0.10.103/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "main"
|
|
pote:
|
|
description: "POTE (python/venv + cron) project (edit repo_url, IPs, secrets)."
|
|
repo_url: "gitea@10.0.30.169:ilia/POTE.git"
|
|
# POTE deploys as a user-owned python app (not /srv/app)
|
|
repo_dest: "/home/poteapp/pote"
|
|
os_user: "poteapp"
|
|
components:
|
|
backend: false
|
|
frontend: false
|
|
guest_defaults:
|
|
guest_type: "{{ proxmox_guest_type }}"
|
|
cores: 2
|
|
memory_mb: 2048
|
|
swap_mb: 512
|
|
rootfs_size_gb: 16
|
|
# POTE-specific optional defaults (override per env if needed)
|
|
pote_db_host: "localhost"
|
|
pote_db_user: "poteuser"
|
|
pote_db_name: "potedb"
|
|
pote_smtp_host: "mail.levkin.ca"
|
|
pote_smtp_port: 587
|
|
envs:
|
|
dev:
|
|
name: "pote-dev"
|
|
vmid: 9001
|
|
ip: "10.0.10.114/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "dev"
|
|
qa:
|
|
name: "pote-qa"
|
|
vmid: 9002
|
|
ip: "10.0.10.112/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "qa"
|
|
prod:
|
|
name: "pote-prod"
|
|
vmid: 9003
|
|
ip: "10.0.10.113/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "main"
|
|
|
|
punimTagFE:
|
|
description: "punimTag frontend-only project (edit repo_url, IPs, secrets)."
|
|
repo_url: "git@github.com:example/punimTagFE.git"
|
|
repo_dest: "/srv/app"
|
|
components:
|
|
backend: false
|
|
frontend: true
|
|
guest_defaults:
|
|
guest_type: "{{ proxmox_guest_type }}"
|
|
cores: 2
|
|
memory_mb: 2048
|
|
swap_mb: 512
|
|
rootfs_size_gb: 16
|
|
deploy:
|
|
frontend_install_cmd: "{{ app_frontend_install_cmd }}"
|
|
frontend_build_cmd: "{{ app_frontend_build_cmd }}"
|
|
frontend_start_cmd: "{{ app_frontend_start_cmd }}"
|
|
envs:
|
|
dev:
|
|
name: "punimTagFE-dev"
|
|
vmid: 9101
|
|
ip: "10.0.10.121/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "dev"
|
|
env_vars:
|
|
APP_ENV: "dev"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
qa:
|
|
name: "punimTagFE-qa"
|
|
vmid: 9102
|
|
ip: "10.0.10.122/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "qa"
|
|
env_vars:
|
|
APP_ENV: "qa"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
prod:
|
|
name: "punimTagFE-prod"
|
|
vmid: 9103
|
|
ip: "10.0.10.123/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "main"
|
|
env_vars:
|
|
APP_ENV: "prod"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
|
|
punimTagBE:
|
|
description: "punimTag backend-only project (edit repo_url, IPs, secrets)."
|
|
repo_url: "git@github.com:example/punimTagBE.git"
|
|
repo_dest: "/srv/app"
|
|
components:
|
|
backend: true
|
|
frontend: false
|
|
guest_defaults:
|
|
guest_type: "{{ proxmox_guest_type }}"
|
|
cores: 2
|
|
memory_mb: 2048
|
|
swap_mb: 512
|
|
rootfs_size_gb: 16
|
|
deploy:
|
|
backend_install_cmd: "{{ app_backend_install_cmd }}"
|
|
backend_migrate_cmd: "{{ app_backend_migrate_cmd }}"
|
|
backend_start_cmd: "{{ app_backend_start_cmd }}"
|
|
envs:
|
|
dev:
|
|
name: "punimTagBE-dev"
|
|
vmid: 9201
|
|
ip: "10.0.10.131/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "dev"
|
|
env_vars:
|
|
APP_ENV: "dev"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
qa:
|
|
name: "punimTagBE-qa"
|
|
vmid: 9202
|
|
ip: "10.0.10.132/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "qa"
|
|
env_vars:
|
|
APP_ENV: "qa"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
prod:
|
|
name: "punimTagBE-prod"
|
|
vmid: 9203
|
|
ip: "10.0.10.133/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "main"
|
|
env_vars:
|
|
APP_ENV: "prod"
|
|
SECRET_PLACEHOLDER: "change-me"
|
|
|
|
mirrormatch:
|
|
description: "Mirrormatch Prisma/Node backend (dev/qa/prod)."
|
|
repo_url: "gitea@10.0.30.169:ilia/mirror_match.git"
|
|
repo_dest: "/srv/app"
|
|
backend_dir: "/srv/app"
|
|
components:
|
|
backend: true
|
|
frontend: false
|
|
# Next.js app listens on 3000 by default
|
|
backend_port: 3000
|
|
guest_defaults:
|
|
guest_type: "{{ proxmox_guest_type }}"
|
|
cores: 2
|
|
memory_mb: 2048
|
|
swap_mb: 512
|
|
rootfs_size_gb: 16
|
|
deploy:
|
|
backend_install_cmd: "npm ci"
|
|
backend_build_cmd: "npm run build"
|
|
backend_migrate_cmd: "npm run db:migrate"
|
|
backend_start_cmd: "npm run start"
|
|
envs:
|
|
dev:
|
|
name: "mirrormatch-dev"
|
|
vmid: 9401
|
|
ip: "10.0.10.141/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "dev"
|
|
backend_migrate_cmd: "npm run db:push"
|
|
backend_seed_cmd: "npm run db:seed"
|
|
env_vars:
|
|
APP_ENV: "dev"
|
|
NODE_ENV: "production"
|
|
PORT: "3000"
|
|
DATABASE_URL: "{{ vault_mirrormatch_database_url_dev }}"
|
|
NEXTAUTH_URL: "https://mirrormatchdev.levkin.ca"
|
|
NEXTAUTH_SECRET: "{{ vault_mirrormatch_nextauth_secret_dev }}"
|
|
AUTH_TRUST_HOST: "true"
|
|
# Dev/QA often use Ethereal/console email; leave SMTP unset or fill if needed
|
|
# SMTP_HOST: ""
|
|
# SMTP_PORT: ""
|
|
# SMTP_USER: ""
|
|
# SMTP_PASSWORD: ""
|
|
# SMTP_FROM: ""
|
|
# Optional: provide if your Prisma workflow needs a shadow DB
|
|
# SHADOW_DATABASE_URL: "{{ vault_mirrormatch_shadow_database_url_dev }}"
|
|
qa:
|
|
name: "mirrormatch-qa"
|
|
vmid: 9402
|
|
ip: "10.0.10.144/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "qa"
|
|
backend_migrate_cmd: "npm run db:push"
|
|
backend_seed_cmd: "npm run db:seed"
|
|
env_vars:
|
|
APP_ENV: "qa"
|
|
NODE_ENV: "production"
|
|
PORT: "3000"
|
|
DATABASE_URL: "{{ vault_mirrormatch_database_url_qa }}"
|
|
NEXTAUTH_URL: "https://mirrormatchqa.levkin.ca"
|
|
NEXTAUTH_SECRET: "{{ vault_mirrormatch_nextauth_secret_qa }}"
|
|
AUTH_TRUST_HOST: "true"
|
|
# SMTP_HOST: ""
|
|
# SMTP_PORT: ""
|
|
# SMTP_USER: ""
|
|
# SMTP_PASSWORD: ""
|
|
# SMTP_FROM: ""
|
|
# SHADOW_DATABASE_URL: "{{ vault_mirrormatch_shadow_database_url_qa }}"
|
|
prod:
|
|
name: "mirrormatch-prod"
|
|
vmid: 9403
|
|
ip: "10.0.10.145/24"
|
|
gateway: "10.0.10.1"
|
|
branch: "main"
|
|
backend_migrate_cmd: "npx prisma migrate deploy"
|
|
env_vars:
|
|
APP_ENV: "prod"
|
|
NODE_ENV: "production"
|
|
PORT: "3000"
|
|
DATABASE_URL: "{{ vault_mirrormatch_database_url_prod }}"
|
|
NEXTAUTH_URL: "https://mirrormatch.example.com"
|
|
NEXTAUTH_SECRET: "{{ vault_mirrormatch_nextauth_secret_prod }}"
|
|
AUTH_TRUST_HOST: "true"
|
|
SMTP_HOST: "{{ vault_mirrormatch_smtp_host | default('') }}"
|
|
SMTP_PORT: "{{ vault_mirrormatch_smtp_port | default('587') }}"
|
|
SMTP_USER: "{{ vault_mirrormatch_smtp_user | default('') }}"
|
|
SMTP_PASSWORD: "{{ vault_mirrormatch_smtp_password | default('') }}"
|
|
SMTP_FROM: "{{ vault_mirrormatch_smtp_from | default('') }}"
|