# Tools stack — generated by Ansible # Do not edit manually; re-run ansible-playbook playbooks/tools.yml 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 mail-internal: driver: bridge internal: true webmail-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 - mail-internal # send mail via mailserver - 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" # ── 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" # ── Mail server (Postfix + Dovecot — send & receive for @csrx.ru) ─────────── mailserver: image: {{ mailserver_image }} container_name: mailserver hostname: mx domainname: {{ domain_base }} restart: unless-stopped networks: - mail-internal # Outline → mailserver (internal, port 587 with auth) - front # inbound/outbound internet SMTP ports: - "{{ ip_tools }}:25:25" # SMTP inbound (MX delivery from internet) - "{{ ip_tools }}:587:587" # SMTP submission (mail clients, STARTTLS) - "{{ ip_tools }}:993:993" # IMAPS (mail clients, TLS) - "{{ ip_tools }}:465:465" # SMTPS (mail clients, implicit TLS) environment: - ENABLE_RSPAMD=1 # spam filter + DKIM signing - ENABLE_CLAMAV=0 # no antivirus (saves RAM) - ENABLE_FAIL2BAN=0 # host fail2ban already handles this - POSTFIX_INET_PROTOCOLS=ipv4 - SSL_TYPE=letsencrypt # TLS certs from /etc/letsencrypt/live/mx.csrx.ru/ - LOG_LEVEL=warn - OVERRIDE_HOSTNAME=mx.{{ domain_base }} - POSTMASTER_ADDRESS=admin@{{ domain_base }} - POSTFIX_MESSAGE_SIZE_LIMIT=26214400 # 25 MB max message size volumes: - {{ tools_root }}/mailserver/mail-data:/var/mail - {{ tools_root }}/mailserver/mail-state:/var/mail-state - {{ tools_root }}/mailserver/mail-logs:/var/log/mail - {{ tools_root }}/mailserver/config:/tmp/docker-mailserver - /etc/letsencrypt:/etc/letsencrypt:ro # TLS certs from certbot stop_grace_period: 1m cap_add: - NET_ADMIN logging: driver: json-file options: max-size: "10m" max-file: "3" # ── SnappyMail webmail ─────────────────────────────────────────────────────── snappymail: image: {{ snappymail_image }} container_name: snappymail restart: unless-stopped networks: - webmail-internal - front ports: - "{{ ip_tools }}:8888:8888" volumes: - {{ tools_root }}/snappymail/data:/var/lib/snappymail environment: - SNAPPYMAIL_ADMIN_PASSWORD={{ snappymail_admin_password }} healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8888"] interval: 30s timeout: 5s retries: 3 logging: driver: json-file options: max-size: "10m" max-file: "3"