From d669b0cfe7186aa4ae8551e131f74a7d7159bb45 Mon Sep 17 00:00:00 2001 From: boxswapper Date: Sun, 22 Feb 2026 21:12:23 -0700 Subject: [PATCH] recommit with matrix synapse --- deploy/ansible-playbook.yml | 97 ----------------------- deploy/inentory.ini | 2 - deploy/requirements.yml | 2 - deploy/vars.yml | 23 ------ prowler/.env | 154 ------------------------------------ prowler/docker-compose.yml | 109 ------------------------- templates/health-check.yml | 29 +++++++ templates/homeserver.yaml | 17 ++++ templates/mautrix-voip.yaml | 22 ++++++ traefik/config/traefik.yml | 150 ----------------------------------- traefik/docker-compose.yml | 19 ----- 11 files changed, 68 insertions(+), 556 deletions(-) delete mode 100644 deploy/ansible-playbook.yml delete mode 100644 deploy/inentory.ini delete mode 100644 deploy/requirements.yml delete mode 100644 deploy/vars.yml delete mode 100644 prowler/.env delete mode 100644 prowler/docker-compose.yml create mode 100644 templates/health-check.yml create mode 100644 templates/homeserver.yaml create mode 100644 templates/mautrix-voip.yaml delete mode 100755 traefik/config/traefik.yml delete mode 100644 traefik/docker-compose.yml diff --git a/deploy/ansible-playbook.yml b/deploy/ansible-playbook.yml deleted file mode 100644 index 14bfe60..0000000 --- a/deploy/ansible-playbook.yml +++ /dev/null @@ -1,97 +0,0 @@ ---- -- hosts: internal-apps - become: true - vars_files: - - ./vars.yml - tasks: - - name: Update Packages - ansible.builtin.dnf: - update_cache: yes - - - name: Install Packages - ansible.builtin.dnf: - name: - - vim - - podman - - fail2ban - - python3-libdnf5 - state: present - - - name: Create directories - file: - path: "{{ item }}" - state: directory - mode: '0755' - loop: "{{ directories }}" - - - name: Create internal podman network - containers.podman.podman_network: - name: npm_internal - ip_range: 10.10.0.128/25 - subnet: 10.10.0.0/24 - gateway: 10.10.0.1 - state: present - - - name: pull images - containers.podman.podman_image: - name: "{{ item }}" - loop: "{{ images }}" - -### NGINX Proxy manager --------------------------## - - name: Deploy Nginx Proxy Manager - containers.podman.podman_container: - image: "docker.io/jc21/nginx-proxy-manager:latest" - name: npm - restart_policy: always - recreate: true - state: started - ports: - - "80:80" - - "81:81" - - "443:443" - volumes: - - "/opt/apps/npm:/data:z" - - "/opt/apps/letsencrypt:/etc/letsencrypt:z" - network: - - npm_internal - ip: '10.10.0.19' - -### Deploy Gitea ---------------------------------## - - name: Deploy Gitea - containers.podman.podman_container: - image: docker.gitea.com/gitea:nightly - name: gitea - env: - USER_UID: 1000 - USER_GID: 1000 - restart_policy: always - recreate: true - state: started - volumes: - - /opt/apps/gitea:/data:z - - /usr/share/zoneinfo/America/Denver:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - network: - - npm_internal - ip: '10.10.0.25' - ports: - # - "3000:3000" - - "222:22" - - -###---- Deploy Matrix Synapse ------------------# - - name: Deploy Matrix Synapse - containers.podman.podman_container: - image: docker.io/matrixdotorg/synapse:latest - name: synapse - volumes: - - /opt/apps/synapse/data:/data:z - command: run -m synapse.app.generic_worker --config-path=/data/homeserver.yaml --config-path=/data/generic_worker.yaml - network: - - npm_internal - ip: '10.10.0.35' - # ports: - # - 8008:8008 - - - diff --git a/deploy/inentory.ini b/deploy/inentory.ini deleted file mode 100644 index a0a0740..0000000 --- a/deploy/inentory.ini +++ /dev/null @@ -1,2 +0,0 @@ -[internal-apps] -internal-apps \ No newline at end of file diff --git a/deploy/requirements.yml b/deploy/requirements.yml deleted file mode 100644 index 5efe5ae..0000000 --- a/deploy/requirements.yml +++ /dev/null @@ -1,2 +0,0 @@ -collections: - - name: containers.podman diff --git a/deploy/vars.yml b/deploy/vars.yml deleted file mode 100644 index 3465455..0000000 --- a/deploy/vars.yml +++ /dev/null @@ -1,23 +0,0 @@ -## add generic 755 directory for application here -directories: - - /opt/apps/npm - - /opt/apps/letsencrypt - - /opt/apps/gitea - - /opt/apps/prowler/data - - /opt/apps/prowler/tmp/prowler_api_output - - /opt/apps/prowler/postgres/data - - /opt/apps/synapse/data -# - /opt/apps/n8n/files - - -images: - - docker.io/jc21/nginx-proxy-manager:latest - - docker.gitea.com/gitea:nightly - - docker.io/matrixdotorg/synapse:latest - -sudo_password: sdfwwww - -POSTGRES_ADMIN_USER: theuseriwant -POSTGRES_PASSWORD: theuserthatineedpaswoord -POSTGRES_DB: thatoneit - diff --git a/prowler/.env b/prowler/.env deleted file mode 100644 index 55f47e1..0000000 --- a/prowler/.env +++ /dev/null @@ -1,154 +0,0 @@ -#### Important Note #### -# This file is used to store environment variables for the Prowler App. -# For production, it is recommended to use a secure method to store these variables and change the default secret keys. - -#### Prowler UI Configuration #### -PROWLER_UI_VERSION="stable" -AUTH_URL=http://localhost:3000 -API_BASE_URL=http://prowler-api:8080/api/v1 -NEXT_PUBLIC_API_BASE_URL=${API_BASE_URL} -NEXT_PUBLIC_API_DOCS_URL=http://prowler-api:8080/api/v1/docs -AUTH_TRUST_HOST=true -UI_PORT=3000 -# Temp URL for feeds need to use actual -RSS_FEED_URL=https://prowler.com/blog/rss -# openssl rand -base64 32 -AUTH_SECRET="N/c6mnaS5+SWq81+819OrzQZlmx1Vxtp/orjttJSmw8=" -# Google Tag Manager ID -NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID="" - - -#### Prowler API Configuration #### -PROWLER_API_VERSION="stable" -# PostgreSQL settings -# If running Django and celery on host, use 'localhost', else use 'postgres-db' -POSTGRES_HOST=postgres-db -POSTGRES_PORT=5432 -POSTGRES_ADMIN_USER=prowler_admin -POSTGRES_ADMIN_PASSWORD=postgres -POSTGRES_USER=prowler -POSTGRES_PASSWORD=postgres -POSTGRES_DB=prowler_db - -# Celery-Prowler task settings -TASK_RETRY_DELAY_SECONDS=0.1 -TASK_RETRY_ATTEMPTS=5 - -# Valkey settings -# If running Valkey and celery on host, use localhost, else use 'valkey' -VALKEY_HOST=valkey -VALKEY_PORT=6379 -VALKEY_DB=0 - -# API scan settings - -# The path to the directory where scan output should be stored -DJANGO_TMP_OUTPUT_DIRECTORY="/tmp/prowler_api_output" - -# The maximum number of findings to process in a single batch -DJANGO_FINDINGS_BATCH_SIZE=1000 - -# The AWS access key to be used when uploading scan output to an S3 bucket -# If left empty, default AWS credentials resolution behavior will be used -DJANGO_OUTPUT_S3_AWS_ACCESS_KEY_ID="" - -# The AWS secret key to be used when uploading scan output to an S3 bucket -DJANGO_OUTPUT_S3_AWS_SECRET_ACCESS_KEY="" - -# An optional AWS session token -DJANGO_OUTPUT_S3_AWS_SESSION_TOKEN="" - -# The AWS region where your S3 bucket is located (e.g., "us-east-1") -DJANGO_OUTPUT_S3_AWS_DEFAULT_REGION="" - -# The name of the S3 bucket where scan output should be stored -DJANGO_OUTPUT_S3_AWS_OUTPUT_BUCKET="" - -# Django settings -DJANGO_ALLOWED_HOSTS=localhost,127.0.0.1,prowler-api -DJANGO_BIND_ADDRESS=0.0.0.0 -DJANGO_PORT=8080 -DJANGO_DEBUG=False -DJANGO_SETTINGS_MODULE=config.django.production -# Select one of [ndjson|human_readable] -DJANGO_LOGGING_FORMATTER=human_readable -# Select one of [DEBUG|INFO|WARNING|ERROR|CRITICAL] -# Applies to both Django and Celery Workers -DJANGO_LOGGING_LEVEL=INFO -# Defaults to the maximum available based on CPU cores if not set. -DJANGO_WORKERS=4 -# Token lifetime is in minutes -DJANGO_ACCESS_TOKEN_LIFETIME=30 -# Token lifetime is in minutes -DJANGO_REFRESH_TOKEN_LIFETIME=1440 -DJANGO_CACHE_MAX_AGE=3600 -DJANGO_STALE_WHILE_REVALIDATE=60 -DJANGO_MANAGE_DB_PARTITIONS=True -# openssl genrsa -out private.pem 2048 -DJANGO_TOKEN_SIGNING_KEY="-----BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDs4e+kt7SnUJek -6V5r9zMGzXCoU5qnChfPiqu+BgANyawz+MyVZPs6RCRfeo6tlCknPQtOziyXYM2I -7X+qckmuzsjqp8+u+o1mw3VvUuJew5k2SQLPYwsiTzuFNVJEOgRo3hywGiGwS2iv -/5nh2QAl7fq2qLqZEXQa5+/xJlQggS1CYxOJgggvLyra50QZlBvPve/AxKJ/EV/Q -irWTZU5lLNI8sH2iZR05vQeBsxZ0dCnGMT+vGl+cGkqrvzQzKsYbDmabMcfTYhYi -78fpv6A4uharJFHayypYBjE39PwhMyyeycrNXlpm1jpq+03HgmDuDMHydk1tNwuT -nEC7m7iNAgMBAAECggEAA2m48nJcJbn9SVi8bclMwKkWmbJErOnyEGEy2sTK3Of+ -NWx9BB0FmqAPNxn0ss8K7cANKOhDD7ZLF9E2MO4/HgfoMKtUzHRbM7MWvtEepldi -nnvcUMEgULD8Dk4HnqiIVjt3BdmGiTv46OpBnRWrkSBV56pUL+7msZmMZTjUZvh2 -ZWv0+I3gtDIjo2Zo/FiwDV7CfwRjJarRpYUj/0YyuSA4FuOUYl41WAX1I301FKMH -xo3jiAYi1s7IneJ16OtPpOA34Wg5F6ebm/UO0uNe+iD4kCXKaZmxYQPh5tfB0Qa3 -qj1T7GNpFNyvtG7VVdauhkb8iu8X/wl6PCwbg0RCKQKBgQD9HfpnpH0lDlHMRw9K -X7Vby/1fSYy1BQtlXFEIPTN/btJ/asGxLmAVwJ2HAPXWlrfSjVAH7CtVmzN7v8oj -HeIHfeSgoWEu1syvnv2AMaYSo03UjFFlfc/GUxF7DUScRIhcJUPCP8jkAROz9nFv -DByNjUL17Q9r43DmDiRsy0IFqQKBgQDvlJ9Uhl+Sp7gRgKYwa/IG0+I4AduAM+Gz -Dxbm52QrMGMTjaJFLmLHBUZ/ot+pge7tZZGws8YR8ufpyMJbMqPjxhIvRRa/p1Tf -E3TQPW93FMsHUvxAgY3MV5MzXFPhlNAKb+akP/RcXUhetGAuZKLubtDCWa55ZQuL -wj2OS+niRQKBgE7K8zUqNi6/22S8xhy/2GPgB1qPObbsABUofK0U6CAGLo6te+gc -6Jo84IyzFtQbDNQFW2Fr+j1m18rw9AqkdcUhQndiZS9AfG07D+zFB86LeWHt4DS4 -ymIRX8Kvaak/iDcu/n3Mf0vCrhB6aetImObTj4GgrwlFvtJOmrYnO8EpAoGAIXXP -Xt25gWD9OyyNiVu6HKwA/zN7NYeJcRmdaDhO7B1A6R0x2Zml4AfjlbXoqOLlvLAf -zd79vcoAC82nH1eOPiSOq51plPDI0LMF8IN0CtyTkn1Lj7LIXA6rF1RAvtOqzppc -SvpHpZK9pcRpXnFdtBE0BMDDtl6fYzCIqlP94UUCgYEAnhXbAQMF7LQifEm34Dx8 -BizRMOKcqJGPvbO2+Iyt50O5X6onU2ITzSV1QHtOvAazu+B1aG9pEuBFDQ+ASxEu -L9ruJElkOkb/o45TSF6KCsHd55ReTZ8AqnRjf5R+lyzPqTZCXXb8KTcRvWT4zQa3 -VxyT2PnaSqEcexWUy4+UXoQ= ------END PRIVATE KEY-----" -# openssl rsa -in private.pem -pubout -out public.pem -DJANGO_TOKEN_VERIFYING_KEY="-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7OHvpLe0p1CXpOlea/cz -Bs1wqFOapwoXz4qrvgYADcmsM/jMlWT7OkQkX3qOrZQpJz0LTs4sl2DNiO1/qnJJ -rs7I6qfPrvqNZsN1b1LiXsOZNkkCz2MLIk87hTVSRDoEaN4csBohsEtor/+Z4dkA -Je36tqi6mRF0Gufv8SZUIIEtQmMTiYIILy8q2udEGZQbz73vwMSifxFf0Iq1k2VO -ZSzSPLB9omUdOb0HgbMWdHQpxjE/rxpfnBpKq780MyrGGw5mmzHH02IWIu/H6b+g -OLoWqyRR2ssqWAYxN/T8ITMsnsnKzV5aZtY6avtNx4Jg7gzB8nZNbTcLk5xAu5u4 -jQIDAQAB ------END PUBLIC KEY-----" -# openssl rand -base64 32 -DJANGO_SECRETS_ENCRYPTION_KEY="oE/ltOhp/n1TdbHjVmzcjDPLcLA41CVI/4Rk+UB5ESc=" -DJANGO_BROKER_VISIBILITY_TIMEOUT=86400 -DJANGO_SENTRY_DSN= - -# Sentry settings -SENTRY_ENVIRONMENT=local -SENTRY_RELEASE=local - -#### Prowler release version #### -NEXT_PUBLIC_PROWLER_RELEASE_VERSION=v5.10.0 - -# Social login credentials -SOCIAL_GOOGLE_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/google" -SOCIAL_GOOGLE_OAUTH_CLIENT_ID="" -SOCIAL_GOOGLE_OAUTH_CLIENT_SECRET="" - -SOCIAL_GITHUB_OAUTH_CALLBACK_URL="${AUTH_URL}/api/auth/callback/github" -SOCIAL_GITHUB_OAUTH_CLIENT_ID="" -SOCIAL_GITHUB_OAUTH_CLIENT_SECRET="" - -# Single Sign-On (SSO) -SAML_SSO_CALLBACK_URL="${AUTH_URL}/api/auth/callback/saml" - -# Lighthouse tracing -LANGSMITH_TRACING=false -LANGSMITH_ENDPOINT="https://api.smith.langchain.com" -LANGSMITH_API_KEY="" -LANGCHAIN_PROJECT="" diff --git a/prowler/docker-compose.yml b/prowler/docker-compose.yml deleted file mode 100644 index f96ae80..0000000 --- a/prowler/docker-compose.yml +++ /dev/null @@ -1,109 +0,0 @@ -## this is not for production, - -## Run with compose commands -# podman compose up -d -# docker compose up -d -## Access http://localhost:3000 for web interface - -## shutdown -# podman compose down -v -# docker compose down -v - # -v removes volume drive no persistence - -services: - api: - hostname: "prowler-api" - image: prowlercloud/prowler-api:${PROWLER_API_VERSION:-stable} - env_file: - - path: .env - required: false - ports: - - "${DJANGO_PORT:-8080}:${DJANGO_PORT:-8080}" - volumes: - - "output:/tmp/prowler_api_output" - depends_on: - postgres: - condition: service_healthy - valkey: - condition: service_healthy - entrypoint: - - "/home/prowler/docker-entrypoint.sh" - - "prod" - - ui: - image: prowlercloud/prowler-ui:${PROWLER_UI_VERSION:-stable} - env_file: - - path: .env - required: false - ports: - - ${UI_PORT:-3000}:${UI_PORT:-3000} - - postgres: - image: postgres:16.3-alpine3.20 - hostname: "postgres-db" - volumes: - - ./_data/postgres:/var/lib/postgresql/data:z - environment: - - POSTGRES_USER=${POSTGRES_ADMIN_USER} - - POSTGRES_PASSWORD=${POSTGRES_ADMIN_PASSWORD} - - POSTGRES_DB=${POSTGRES_DB} - env_file: - - path: .env - required: false - ports: - - "${POSTGRES_PORT:-5432}:${POSTGRES_PORT:-5432}" - healthcheck: - test: ["CMD-SHELL", "sh -c 'pg_isready -U ${POSTGRES_ADMIN_USER} -d ${POSTGRES_DB}'"] - interval: 5s - timeout: 5s - retries: 5 - - valkey: - image: valkey/valkey:7-alpine3.19 - hostname: "valkey" - volumes: - - ./_data/valkey:/data:z - env_file: - - path: .env - required: false - ports: - - "${VALKEY_PORT:-6379}:6379" - healthcheck: - test: ["CMD-SHELL", "sh -c 'valkey-cli ping'"] - interval: 10s - timeout: 5s - retries: 3 - - worker: - image: prowlercloud/prowler-api:${PROWLER_API_VERSION:-stable} - env_file: - - path: .env - required: false - volumes: - - "output:/tmp/prowler_api_output" - depends_on: - valkey: - condition: service_healthy - postgres: - condition: service_healthy - entrypoint: - - "/home/prowler/docker-entrypoint.sh" - - "worker" - - worker-beat: - image: prowlercloud/prowler-api:${PROWLER_API_VERSION:-stable} - env_file: - - path: ./.env - required: false - depends_on: - valkey: - condition: service_healthy - postgres: - condition: service_healthy - entrypoint: - - "../docker-entrypoint.sh" - - "beat" - -volumes: - output: {} - diff --git a/templates/health-check.yml b/templates/health-check.yml new file mode 100644 index 0000000..59b5a39 --- /dev/null +++ b/templates/health-check.yml @@ -0,0 +1,29 @@ +- name: Verify NGINX Proxy Manager UI is up + ansible.builtin.uri: + url: http://10.10.0.19 + return_content: no + status_code: 200 + register: npm_check + failed_when: npm_check.status != 200 + +- name: Verify Synapse health endpoint + ansible.builtin.uri: + url: http://10.10.0.35:8008/_matrix/client/versions + return_content: yes + register: synapse_check + failed_when: "'versions' not in synapse_check.json" + +- name: Verify Coturn is listening (UDP) + ansible.builtin.command: "nc -zuv 10.10.0.30 3478" + register: turn_check + failed_when: turn_check.rc != 0 + +- name: Verify mautrix‑voip registration with Synapse + ansible.builtin.uri: + url: "http://10.10.0.35:8008/_matrix/app/v1/rooms" + method: GET + headers: + Authorization: "Bearer {{ synapse_registration_token }}" + status_code: 200 + register: voip_check + failed_when: voip_check.status != 200 diff --git a/templates/homeserver.yaml b/templates/homeserver.yaml new file mode 100644 index 0000000..48907ce --- /dev/null +++ b/templates/homeserver.yaml @@ -0,0 +1,17 @@ +# /opt/apps/synapse/data/homeserver.yaml +# ---------------------------------------------------- +# Existing content … (keep it!) +# ---------------------------------------------------- +# Enable the VoIP module (MSC2746) – it’s built‑in but must be turned on +enable_voip: true + +# Turn server configuration (required for media relay) +turn_uris: + - "turn:coturn:3478?transport=udp" + - "turn:coturn:5349?transport=tcp" +turn_shared_secret: "{{ lookup('file', '/opt/apps/coturn/turn_shared_secret') }}" +turn_user_lifetime: "12h" + +# Application Service registration for mautrix‑voip (add a block) +app_service_config_files: + - "/data/mautrix-voip.yaml" diff --git a/templates/mautrix-voip.yaml b/templates/mautrix-voip.yaml new file mode 100644 index 0000000..222f9cd --- /dev/null +++ b/templates/mautrix-voip.yaml @@ -0,0 +1,22 @@ +# /opt/apps/mautrix-voip/mautrix-voip.yaml +# ---------------------------------------------------- +as_token: "{{ lookup('file', '/opt/apps/synapse/data/registration_token') }}" +hs_token: "{{ lookup('file', '/opt/apps/synapse/data/registration_token') }}" + +# Where Synapse lives (the internal network name) +homeserver: + url: "http://synapse:8008" + domain: "{{ matrix_domain }}" + +# TURN server details – the bridge will use these for its media streams +turn: + uris: + - "turn:coturn:3478?transport=udp" + - "turn:coturn:5349?transport=tcp" + shared_secret: "{{ lookup('file', '/opt/apps/coturn/turn_shared_secret') }}" + +# SIP provider configuration (example – replace with your own) +sip: + uri: "sip:example.com" + username: "myuser" + password: "mypassword" diff --git a/traefik/config/traefik.yml b/traefik/config/traefik.yml deleted file mode 100755 index 22825f4..0000000 --- a/traefik/config/traefik.yml +++ /dev/null @@ -1,150 +0,0 @@ -################################################################ -# -# Configuration sample for Traefik v2. -# -# For Traefik v1: https://github.com/traefik/traefik/blob/v1.7/traefik.sample.toml -# -################################################################ - -################################################################ -# Global configuration -################################################################ -global: - checkNewVersion: false - sendAnonymousUsage: false - -################################################################ -# EntryPoints configuration -################################################################ - -# EntryPoints definition -# -# Optional -# -entryPoints: - web: - address: :80 - - websecure: - address: :443 - -################################################################ -# Traefik logs configuration -################################################################ - -# Traefik logs -# Enabled by default and log to stdout -# -# Optional -log: - # Log level - # - # Optional - # Default: "ERROR" - # - level: DEBUG - - # Sets the filepath for the traefik log. If not specified, stdout will be used. - # Intermediate directories are created if necessary. - # - # Optional - # Default: os.Stdout - # -# filePath: log/traefik.log - - # Format is either "json" or "common". - # - # Optional - # Default: "common" - # -# format: json - -################################################################ -# Access logs configuration -################################################################ - -# Enable access logs -# By default it will write to stdout and produce logs in the textual -# Common Log Format (CLF), extended with additional fields. -# -# Optional -# -#accessLog: - # Sets the file path for the access log. If not specified, stdout will be used. - # Intermediate directories are created if necessary. - # - # Optional - # Default: os.Stdout - # -# filePath: /path/to/log/log.txt - - # Format is either "json" or "common". - # - # Optional - # Default: "common" - # -# format: json - -################################################################ -# API and dashboard configuration -################################################################ - -# Enable API and dashboard -# -# Optional -# -api: - # Enable the API in insecure mode - # - # Optional - # Default: false - # - insecure: true - - # Enabled Dashboard - # - # Optional - # Default: true - # - dashboard: true - -################################################################ -# Ping configuration -################################################################ - -# Enable ping -#ping: - # Name of the related entry point - # - # Optional - # Default: "traefik" - # -# entryPoint: traefik - -################################################################ -# Docker configuration backend -################################################################ - -#providers: - # Enable Docker configuration backend -# docker: - # Docker server endpoint. Can be a tcp or a unix socket endpoint. - # - # Required - # Default: "unix:///var/run/docker.sock" - # -# endpoint: tcp://10.10.10.10:2375 - - # Default host rule. - # - # Optional - # Default: "Host(`{{ normalize .Name }}`)" - # -# defaultRule: Host(`{{ normalize .Name }}.docker.localhost`) - - # Expose containers by default in traefik - # - # Optional - # Default: true - # -# exposedByDefault: false diff --git a/traefik/docker-compose.yml b/traefik/docker-compose.yml deleted file mode 100644 index ea2d65e..0000000 --- a/traefik/docker-compose.yml +++ /dev/null @@ -1,19 +0,0 @@ -## Crate network first because it is external:true -#podman network create frontend - -services: - traefik: - container_name: traefik - ports: - - 8080:8080 - - 80:80 - volumes: - - ./config/traefik.yml:/etc/traefik/traefik.yml:ro - image: traefik:v3.5 - restart: unless-stopped - networks: - - frontend - -networks: - frontend: - external: true \ No newline at end of file