diff --git a/roles/services/tasks/main.yml b/roles/services/tasks/main.yml index b09df08..e109ce1 100644 --- a/roles/services/tasks/main.yml +++ b/roles/services/tasks/main.yml @@ -25,20 +25,24 @@ - "{{ promtail_image }}" - "{{ crowdsec_image }}" - "{{ uptime_kuma_image }}" - - "tecnativa/postfix-relay" + - "{{ outline_image }}" + - "{{ outline_db_image }}" + - "{{ outline_redis_image }}" + - "{{ n8n_image }}" register: pull_result changed_when: "'Status: Downloaded newer image' in pull_result.stdout" retries: 5 delay: 30 until: pull_result.rc == 0 -- name: Allow SMTP relay port from tools server +- name: Remove legacy SMTP relay UFW rule (port 1025) community.general.ufw: rule: allow port: "1025" proto: tcp src: "{{ ip_tools }}" - comment: "SMTP relay for tools-server Outline" + delete: true + failed_when: false - name: Deploy Docker Compose stack community.docker.docker_compose_v2: diff --git a/roles/services/templates/docker-compose.yml.j2 b/roles/services/templates/docker-compose.yml.j2 index 012a62b..9ef2a60 100644 --- a/roles/services/templates/docker-compose.yml.j2 +++ b/roles/services/templates/docker-compose.yml.j2 @@ -580,30 +580,6 @@ services: timeout: 5s retries: 3 - # ── SMTP Relay ───────────────────────────────────────────────────────────── - # Forwards mail from tools-server (85.193.83.9) to Resend SMTP. - # tools-server has outbound SMTP blocked by the VPS provider. - # Listens on 85.193.83.9:1025 (UFW allows only from ip_tools). - smtp-relay: - image: tecnativa/postfix-relay - container_name: smtp-relay - restart: unless-stopped - ports: - - "{{ ip_tools }}:1025:25" - networks: - - proxy - environment: - - MAILNAME={{ domain_base }} - - MAIL_RELAY_HOST=smtp.resend.com - - MAIL_RELAY_PORT=587 - - MAIL_RELAY_USER=resend - - MAIL_RELAY_PASS={{ resend_api_key }} - - MAIL_RELAY_MYHOSTNAME=mail.{{ domain_base }} - logging: - driver: json-file - options: - max-size: "5m" - max-file: "2" # ── Outline wiki ──────────────────────────────────────────────────────────── outline: diff --git a/roles/tools/defaults/main.yml b/roles/tools/defaults/main.yml index 4d929ac..36c0115 100644 --- a/roles/tools/defaults/main.yml +++ b/roles/tools/defaults/main.yml @@ -1,7 +1,2 @@ --- tools_root: /opt/tools -outline_image: "outlinewiki/outline:0.80.2" -outline_db_image: "postgres:15-alpine" -outline_redis_image: "redis:7-alpine" -n8n_image: "n8nio/n8n:1.89.2" # https://hub.docker.com/r/n8nio/n8n/tags -outline_mcp_image: "git.{{ domain_base }}/jack/outline-mcp:latest" diff --git a/roles/tools/tasks/main.yml b/roles/tools/tasks/main.yml index a8ce1eb..9467d03 100644 --- a/roles/tools/tasks/main.yml +++ b/roles/tools/tasks/main.yml @@ -7,7 +7,6 @@ group: "{{ deploy_group }}" mode: "0750" -# ── Deploy configs and start stack ──────────────────────────────────────────── - name: Deploy docker-compose.yml ansible.builtin.template: src: docker-compose.yml.j2 @@ -16,27 +15,8 @@ group: "{{ deploy_group }}" mode: "0640" -- name: Deploy .env - ansible.builtin.template: - src: env.j2 - dest: "{{ tools_root }}/.env" - owner: "{{ deploy_user }}" - group: "{{ deploy_group }}" - mode: "0600" - -- name: Pull images - community.docker.docker_image: - name: "{{ item }}" - source: pull - loop: - - "{{ outline_image }}" - - "{{ outline_db_image }}" - - "{{ outline_redis_image }}" - - "{{ n8n_image }}" - - name: Start tools stack community.docker.docker_compose_v2: project_src: "{{ tools_root }}" state: present - pull: missing remove_orphans: true diff --git a/roles/tools/templates/docker-compose.yml.j2 b/roles/tools/templates/docker-compose.yml.j2 index 6e0f778..e5d21af 100644 --- a/roles/tools/templates/docker-compose.yml.j2 +++ b/roles/tools/templates/docker-compose.yml.j2 @@ -1,150 +1,10 @@ # Tools stack — generated by Ansible # Do not edit manually; re-run ansible-playbook playbooks/tools.yml +# All app services (Outline, n8n) have been migrated to main server. +# Monitoring stack (Grafana, Prometheus, Loki, Alertmanager) will be added here. networks: - # front — non-internal: needed for Docker port binding to work (expose ports to host) - # Docker does not create DNAT rules for containers only on internal networks front: driver: bridge - outline-internal: - driver: bridge - internal: true - n8n-internal: - driver: bridge - internal: true -volumes: - outline_db_data: - outline_redis_data: - n8n_data: - -services: - - # ── Outline wiki ──────────────────────────────────────────────────────────── - outline: - image: {{ outline_image }} - container_name: outline - restart: unless-stopped - env_file: .env - networks: - - outline-internal - - front # needed for host port binding - ports: - # Exposed only to main Traefik (access controlled by UFW) - - "{{ ip_tools }}:3000:3000" - depends_on: - outline-db: - condition: service_healthy - outline-redis: - condition: service_healthy - healthcheck: - test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/_health"] - interval: 30s - timeout: 5s - retries: 3 - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - - outline-db: - image: {{ outline_db_image }} - container_name: outline-db - restart: unless-stopped - environment: - POSTGRES_DB: outline - POSTGRES_USER: outline - POSTGRES_PASSWORD: ${OUTLINE_DB_PASSWORD} - networks: - - outline-internal - volumes: - - outline_db_data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U outline"] - interval: 10s - timeout: 5s - retries: 5 - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - - outline-redis: - image: {{ outline_redis_image }} - container_name: outline-redis - restart: unless-stopped - networks: - - outline-internal - volumes: - - outline_redis_data:/data - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - - # ── Outline MCP server ─────────────────────────────────────────────────────── - # MCP server exposing Outline wiki to Claude/AI clients (port 8765, internal only) - outline-mcp: - image: {{ outline_mcp_image }} - container_name: outline-mcp - restart: unless-stopped - networks: - - front # needed for host port binding - ports: - - "127.0.0.1:8765:8765" - environment: - - OUTLINE_URL=https://{{ domain_wiki }} - - OUTLINE_API_KEY={{ outline_mcp_api_key }} - - PORT=8765 - - HOST=0.0.0.0 - - LOG_LEVEL=INFO - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" - - # ── n8n workflow automation ────────────────────────────────────────────────── - n8n: - image: {{ n8n_image }} - container_name: n8n - restart: unless-stopped - networks: - - n8n-internal - - front # needed for host port binding - ports: - # Exposed only to main Traefik (access controlled by UFW) - - "{{ ip_tools }}:5678:5678" - volumes: - - n8n_data:/home/node/.n8n - environment: - - N8N_HOST={{ domain_n8n }} - - N8N_PORT=5678 - - N8N_PROTOCOL=https - - WEBHOOK_URL=https://{{ domain_n8n }}/ - - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY} - - N8N_USER_MANAGEMENT_JWT_SECRET=${N8N_JWT_SECRET} - - GENERIC_TIMEZONE=Europe/Moscow - - TZ=Europe/Moscow - - N8N_METRICS=false - - N8N_LOG_LEVEL=warn - - EXECUTIONS_DATA_PRUNE=true - - EXECUTIONS_DATA_MAX_AGE=336 - healthcheck: - test: ["CMD", "wget", "-qO-", "http://127.0.0.1:5678/healthz"] - interval: 30s - timeout: 5s - retries: 3 - logging: - driver: json-file - options: - max-size: "10m" - max-file: "3" +services: {} diff --git a/roles/tools/templates/env.j2 b/roles/tools/templates/env.j2 deleted file mode 100644 index aaba16e..0000000 --- a/roles/tools/templates/env.j2 +++ /dev/null @@ -1,47 +0,0 @@ -# Outline env — generated by Ansible -NODE_ENV=production -SECRET_KEY={{ outline_secret_key }} -UTILS_SECRET={{ outline_utils_secret }} - -# Database -DATABASE_URL=postgres://outline:{{ outline_db_password }}@outline-db:5432/outline -PGSSLMODE=disable - -# Redis -REDIS_URL=redis://outline-redis:6379 - -# App URL -URL=https://{{ domain_wiki }} -PORT=3000 - -# S3 file storage (Timeweb Object Storage) -AWS_ACCESS_KEY_ID={{ s3_access_key }} -AWS_SECRET_ACCESS_KEY={{ s3_secret_key }} -AWS_REGION=ru-1 -AWS_S3_UPLOAD_BUCKET_NAME=visual-outline -AWS_S3_UPLOAD_BUCKET_URL=https://s3.timeweb.cloud -AWS_S3_FORCE_PATH_STYLE=true -AWS_S3_ACL=private -FILE_STORAGE=s3 - -# Auth -AUTH_PROVIDERS=email - -# SMTP via relay on main server (tools-server has outbound SMTP blocked) -SMTP_HOST={{ ip_main }} -SMTP_PORT=1025 -SMTP_FROM_EMAIL=noreply@{{ domain_base }} -SMTP_FROM_NAME=Visual Wiki -SMTP_SECURE=false - -# Outline DB password (used in docker-compose) -OUTLINE_DB_PASSWORD={{ outline_db_password }} - -# Optional -DEFAULT_LANGUAGE=en_US -RATE_LIMITER_ENABLED=true -ENABLE_UPDATES=false - -# n8n secrets -N8N_ENCRYPTION_KEY={{ n8n_encryption_key }} -N8N_JWT_SECRET={{ n8n_jwt_secret }}