# Copyright (c) Abstract Machines # SPDX-License-Identifier: Apache-2.0 name: "magistrala" networks: magistrala-base-net: driver: bridge name: magistrala-base-net ipam: config: - subnet: 172.30.0.0/24 volumes: magistrala-pat-db-volume: magistrala-ui-backend-db-volume: magistrala-re-db-volume: magistrala-alarms-db-volume: magistrala-reports-db-volume: magistrala-timescale-writer-volume: magistrala-fluxmq-node1-volume: magistrala-fluxmq-node2-volume: magistrala-fluxmq-node3-volume: magistrala-atom-db-volume: services: atom-db: image: postgres:16-alpine container_name: magistrala-atom-db restart: on-failure environment: POSTGRES_USER: ${ATOM_DB_USER} POSTGRES_PASSWORD: ${ATOM_DB_PASSWORD} POSTGRES_DB: ${ATOM_DB_NAME} ports: - ${ATOM_DB_PORT}:5432 networks: - magistrala-base-net volumes: - magistrala-atom-db-volume:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${ATOM_DB_USER} -d ${ATOM_DB_NAME}"] interval: 5s timeout: 5s retries: 5 atom: image: ${ATOM_IMAGE:-ghcr.io/absmach/atom:latest} container_name: magistrala-atom restart: on-failure depends_on: atom-db: condition: service_healthy environment: DATABASE_URL: postgres://${ATOM_DB_USER}:${ATOM_DB_PASSWORD}@atom-db:5432/${ATOM_DB_NAME} LISTEN_ADDR: 0.0.0.0:8080 GRPC_ADDR: ${ATOM_GRPC_ADDR:-0.0.0.0:8081} JWT_SECRET: ${ATOM_JWT_SECRET} JWT_EXPIRY_SECS: ${ATOM_JWT_EXPIRY_SECS} ATOM_PUBLIC_BASE_URL: ${ATOM_PUBLIC_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_SIGNUP_ENABLED: ${ATOM_SIGNUP_ENABLED} ATOM_ALLOW_UNVERIFIED_EMAIL_LOGIN: ${ATOM_ALLOW_UNVERIFIED_EMAIL_LOGIN} ATOM_DEV_ALLOW_UNVERIFIED_EMAIL_LOGIN: ${ATOM_DEV_ALLOW_UNVERIFIED_EMAIL_LOGIN} ATOM_CORS_ALLOWED_ORIGINS: ${ATOM_CORS_ALLOWED_ORIGINS} ATOM_INVITATION_REDIRECT: ${ATOM_INVITATION_REDIRECT} ATOM_INVITATION_EXPIRY_SECS: ${ATOM_INVITATION_EXPIRY_SECS} ATOM_SMTP_HOST: ${ATOM_SMTP_HOST} ATOM_SMTP_PORT: ${ATOM_SMTP_PORT} ATOM_SMTP_USERNAME: ${ATOM_SMTP_USERNAME} ATOM_SMTP_PASSWORD: ${ATOM_SMTP_PASSWORD} ATOM_SMTP_FROM: ${ATOM_SMTP_FROM} ATOM_SMTP_TLS: ${ATOM_SMTP_TLS} ADMIN_SECRET: ${ATOM_ADMIN_SECRET} ATOM_KEY_ENCRYPTION_KEY: ${ATOM_KEY_ENCRYPTION_KEY} ATOM_KEY_ENCRYPTION_KEY_ID: ${ATOM_KEY_ENCRYPTION_KEY_ID:-local:v1} ATOM_ALLOW_PLAINTEXT_SIGNING_KEYS: ${ATOM_ALLOW_PLAINTEXT_SIGNING_KEYS:-false} ATOM_SERVICE_SECRET: ${ATOM_SERVICE_SECRET} ATOM_CERTS_ENABLED: ${ATOM_CERTS_ENABLED:-true} ATOM_CERTS_CA_MODE: ${ATOM_CERTS_CA_MODE:-file_root_issuer} ATOM_CERTS_ROOT_CA_CERT_PATH: ${ATOM_CERTS_ROOT_CA_CERT_PATH:-/certs/ca.crt} ATOM_CERTS_ROOT_CA_KEY_PATH: ${ATOM_CERTS_ROOT_CA_KEY_PATH:-/certs/ca.key} ATOM_CERTS_LEAF_DEFAULT_TTL_SECS: ${ATOM_CERTS_LEAF_DEFAULT_TTL_SECS:-2592000} ATOM_CERTS_LEAF_MAX_TTL_SECS: ${ATOM_CERTS_LEAF_MAX_TTL_SECS:-2592000} ATOM_RATE_LIMIT_ENABLED: ${ATOM_RATE_LIMIT_ENABLED:-true} ATOM_TRUSTED_PROXY_CIDRS: ${ATOM_TRUSTED_PROXY_CIDRS:-} ATOM_MIN_PASSWORD_CHARS: ${ATOM_MIN_PASSWORD_CHARS} RUST_LOG: ${ATOM_RUST_LOG} ports: - ${ATOM_HTTP_PORT}:8080 volumes: - ${ATOM_CERTS_CA_DIR:-./ssl/certs}:/certs:ro networks: - magistrala-base-net atom-ui: image: ghcr.io/absmach/atom-ui:latest container_name: magistrala-atom-ui restart: on-failure depends_on: - atom environment: ATOM_GRAPHQL_URL: http://atom:8080/graphql ports: - ${ATOM_UI_HTTP_PORT:-3005}:3000 networks: - magistrala-base-net atom-bootstrap: image: ghcr.io/absmach/magistrala/atom-bootstrap:${MG_RELEASE_TAG} container_name: magistrala-atom-bootstrap restart: on-failure depends_on: - atom environment: ATOM_URL: ${ATOM_URL} ATOM_SERVICE_USERNAME: ${ATOM_SERVICE_USERNAME} ATOM_SERVICE_SECRET: ${ATOM_SERVICE_SECRET} ATOM_ADMIN_TOKEN: ${ATOM_ADMIN_TOKEN} ATOM_ADMIN_USERNAME: ${ATOM_ADMIN_USERNAME} ATOM_ADMIN_SECRET: ${ATOM_ADMIN_SECRET} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_ATOM_BOOTSTRAP_RETRIES: ${MG_ATOM_BOOTSTRAP_RETRIES:-30} MG_ATOM_BOOTSTRAP_RETRY_INTERVAL: ${MG_ATOM_BOOTSTRAP_RETRY_INTERVAL:-2s} MG_ATOM_BOOTSTRAP_TIMEOUT: ${MG_ATOM_BOOTSTRAP_TIMEOUT:-30s} networks: - magistrala-base-net nginx: image: docker.io/nginx:1.31.3-alpine3.24 container_name: magistrala-nginx restart: on-failure volumes: - ./nginx/nginx-${AUTH-key}.conf:/etc/nginx/nginx.conf.template - ./nginx/entrypoint.sh:/docker-entrypoint.d/entrypoint.sh - ./nginx/snippets:/etc/nginx/snippets - ./ssl/authorization.js:/etc/nginx/authorization.js - type: bind source: ${MG_NGINX_SERVER_CERT:-./ssl/certs/magistrala-server.crt} target: /etc/ssl/certs/magistrala-server.crt - type: bind source: ${MG_NGINX_SERVER_KEY:-./ssl/certs/magistrala-server.key} target: /etc/ssl/private/magistrala-server.key - type: bind source: ${MG_NGINX_SERVER_CLIENT_CA:-./ssl/certs/ca.crt} target: /etc/ssl/certs/ca.crt - type: bind source: ${MG_NGINX_SERVER_DHPARAM:-./ssl/dhparam.pem} target: /etc/ssl/certs/dhparam.pem - ./ssl/letsencrypt:/etc/letsencrypt:ro - ./ssl/certbot-www:/var/www/certbot:ro ports: - ${MG_NGINX_HTTP_PORT}:${MG_NGINX_HTTP_PORT} - ${MG_NGINX_SSL_PORT}:${MG_NGINX_SSL_PORT} - ${MG_NGINX_MQTT_PORT}:${MG_NGINX_MQTT_PORT} - ${MG_NGINX_MQTTS_PORT}:${MG_NGINX_MQTTS_PORT} - ${MG_NGINX_AMQP_PORT}:${MG_NGINX_AMQP_PORT} networks: - magistrala-base-net env_file: - .env depends_on: - fluxmq-node1 - fluxmq-node2 - fluxmq-node3 ulimits: nofile: soft: 65536 hard: 65536 certbot: image: docker.io/certbot/certbot:v5.7.0 container_name: magistrala-certbot profiles: - letsencrypt depends_on: - nginx pid: "service:nginx" restart: unless-stopped env_file: - .env volumes: - ./ssl/letsencrypt:/etc/letsencrypt - ./ssl/certbot-www:/var/www/certbot entrypoint: /bin/sh command: - -c - | if [ -z "$${MG_PUBLIC_HOST}" ] || [ "$${MG_PUBLIC_HOST}" = "localhost" ]; then echo "Set MG_PUBLIC_HOST to a public DNS name before requesting a Let's Encrypt certificate." >&2 exit 1 fi if [ -z "$${MG_LETSENCRYPT_EMAIL}" ]; then echo "Set MG_LETSENCRYPT_EMAIL before requesting a Let's Encrypt certificate." >&2 exit 1 fi staging_arg="" if [ "$${MG_LETSENCRYPT_STAGING}" = "true" ]; then staging_arg="--staging" fi renewal_arg="--keep-until-expiring" if [ "$${MG_LETSENCRYPT_FORCE_RENEWAL}" = "true" ]; then renewal_arg="--force-renewal" fi certbot certonly \ --webroot \ --webroot-path /var/www/certbot \ --domain "$${MG_PUBLIC_HOST}" \ --email "$${MG_LETSENCRYPT_EMAIL}" \ --agree-tos \ --no-eff-email \ --non-interactive \ $${renewal_arg} \ $${staging_arg} while :; do certbot renew \ --webroot \ --webroot-path /var/www/certbot \ --quiet \ --deploy-hook "kill -HUP 1" \ $${staging_arg} sleep 12h & wait $$! done jaeger: image: docker.io/jaegertracing/all-in-one:1.76.0 container_name: magistrala-jaeger environment: COLLECTOR_OTLP_ENABLED: ${MG_JAEGER_COLLECTOR_OTLP_ENABLED} command: --memory.max-traces ${MG_JAEGER_MEMORY_MAX_TRACES} ports: - ${MG_JAEGER_FRONTEND}:${MG_JAEGER_FRONTEND} - ${MG_JAEGER_OLTP_HTTP}:${MG_JAEGER_OLTP_HTTP} networks: - magistrala-base-net fluxmq-node1: image: ghcr.io/absmach/fluxmq:${MG_FLUXMQ_IMAGE_TAG} container_name: magistrala-fluxmq-node1 user: "0:0" command: ["-config", "/etc/fluxmq/config.yaml"] depends_on: fluxmq-auth: condition: service_started restart: on-failure ports: - ${MG_COAP_PORT}:5683/udp - ${MG_FLUXMQ_API_PORT_1}:8082 networks: magistrala-base-net: ipv4_address: 172.30.0.201 volumes: - ./fluxmq/node1.yaml:/etc/fluxmq/config.yaml:ro # Server certificate and CA for the mTLS service listener, plus each # local principal's SASL secret. - ./ssl/certs/fluxmq-service-server.crt:/etc/fluxmq/certs/fluxmq-service-server.crt:ro - ./ssl/certs/fluxmq-service-server.key:/etc/fluxmq/certs/fluxmq-service-server.key:ro - ./ssl/certs/ca.crt:/etc/fluxmq/certs/ca.crt:ro - ./fluxmq/secrets/re-current:/etc/fluxmq/secrets/re-current:ro - ./fluxmq/secrets/timescale-writer-current:/etc/fluxmq/secrets/timescale-writer-current:ro - ./fluxmq/secrets/postgres-writer-current:/etc/fluxmq/secrets/postgres-writer-current:ro - ./fluxmq/secrets/fluxmq-auth-current:/etc/fluxmq/secrets/fluxmq-auth-current:ro - magistrala-fluxmq-node1-volume:/tmp/fluxmq fluxmq-node2: image: ghcr.io/absmach/fluxmq:${MG_FLUXMQ_IMAGE_TAG} container_name: magistrala-fluxmq-node2 user: "0:0" command: ["-config", "/etc/fluxmq/config.yaml"] depends_on: fluxmq-node1: condition: service_started fluxmq-auth: condition: service_started restart: on-failure ports: - ${MG_FLUXMQ_API_PORT_2}:8082 networks: magistrala-base-net: ipv4_address: 172.30.0.202 volumes: - ./fluxmq/node2.yaml:/etc/fluxmq/config.yaml:ro # Server certificate and CA for the mTLS service listener, plus each # local principal's SASL secret. - ./ssl/certs/fluxmq-service-server.crt:/etc/fluxmq/certs/fluxmq-service-server.crt:ro - ./ssl/certs/fluxmq-service-server.key:/etc/fluxmq/certs/fluxmq-service-server.key:ro - ./ssl/certs/ca.crt:/etc/fluxmq/certs/ca.crt:ro - ./fluxmq/secrets/re-current:/etc/fluxmq/secrets/re-current:ro - ./fluxmq/secrets/timescale-writer-current:/etc/fluxmq/secrets/timescale-writer-current:ro - ./fluxmq/secrets/postgres-writer-current:/etc/fluxmq/secrets/postgres-writer-current:ro - ./fluxmq/secrets/fluxmq-auth-current:/etc/fluxmq/secrets/fluxmq-auth-current:ro - magistrala-fluxmq-node2-volume:/tmp/fluxmq fluxmq-node3: image: ghcr.io/absmach/fluxmq:${MG_FLUXMQ_IMAGE_TAG} container_name: magistrala-fluxmq-node3 user: "0:0" command: ["-config", "/etc/fluxmq/config.yaml"] depends_on: fluxmq-node1: condition: service_started fluxmq-auth: condition: service_started restart: on-failure ports: - ${MG_FLUXMQ_API_PORT_3}:8082 networks: magistrala-base-net: ipv4_address: 172.30.0.203 volumes: - ./fluxmq/node3.yaml:/etc/fluxmq/config.yaml:ro # Server certificate and CA for the mTLS service listener, plus each # local principal's SASL secret. - ./ssl/certs/fluxmq-service-server.crt:/etc/fluxmq/certs/fluxmq-service-server.crt:ro - ./ssl/certs/fluxmq-service-server.key:/etc/fluxmq/certs/fluxmq-service-server.key:ro - ./ssl/certs/ca.crt:/etc/fluxmq/certs/ca.crt:ro - ./fluxmq/secrets/re-current:/etc/fluxmq/secrets/re-current:ro - ./fluxmq/secrets/timescale-writer-current:/etc/fluxmq/secrets/timescale-writer-current:ro - ./fluxmq/secrets/postgres-writer-current:/etc/fluxmq/secrets/postgres-writer-current:ro - ./fluxmq/secrets/fluxmq-auth-current:/etc/fluxmq/secrets/fluxmq-auth-current:ro - magistrala-fluxmq-node3-volume:/tmp/fluxmq fluxmq-auth: image: ghcr.io/absmach/magistrala/fluxmq:${MG_RELEASE_TAG} container_name: magistrala-fluxmq-auth depends_on: atom-bootstrap: condition: service_completed_successfully restart: on-failure environment: MG_FLUXMQ_LOG_LEVEL: ${MG_FLUXMQ_LOG_LEVEL} MG_FLUXMQ_GRPC_HOST: ${MG_FLUXMQ_GRPC_HOST} MG_FLUXMQ_GRPC_PORT: ${MG_FLUXMQ_GRPC_PORT} MG_FLUXMQ_INSTANCE_ID: ${MG_FLUXMQ_INSTANCE_ID} MG_FLUXMQ_CACHE_NUM_COUNTERS: ${MG_FLUXMQ_CACHE_NUM_COUNTERS} MG_FLUXMQ_CACHE_MAX_COST: ${MG_FLUXMQ_CACHE_MAX_COST} MG_FLUXMQ_CACHE_BUFFER_ITEMS: ${MG_FLUXMQ_CACHE_BUFFER_ITEMS} MG_MESSAGE_BROKER_URL: ${MG_MESSAGE_BROKER_URL} MG_FLUXMQ_PUBLISH_HTTP_HOST: ${MG_FLUXMQ_PUBLISH_HTTP_HOST} MG_FLUXMQ_PUBLISH_HTTP_PORT: ${MG_FLUXMQ_PUBLISH_HTTP_PORT} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_TOKEN: ${MG_ATOM_TOKEN_FLUXMQ_AUTH} ATOM_SERVICE_USERNAME: ${ATOM_SERVICE_USERNAME} ATOM_SERVICE_SECRET: ${ATOM_SERVICE_SECRET} ATOM_ADMIN_TOKEN: ${ATOM_ADMIN_TOKEN} ATOM_ADMIN_USERNAME: ${ATOM_ADMIN_USERNAME} ATOM_ADMIN_SECRET: ${ATOM_ADMIN_SECRET} ATOM_JWKS_URL: ${ATOM_JWKS_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} MG_FLUXMQ_BROKER_URL: ${MG_FLUXMQ_BROKER_URL} MG_FLUXMQ_BROKER_CLIENT_CERT: ${MG_FLUXMQ_BROKER_CLIENT_CERT} MG_FLUXMQ_BROKER_CLIENT_KEY: ${MG_FLUXMQ_BROKER_CLIENT_KEY} MG_FLUXMQ_BROKER_CA_CERTS: ${MG_FLUXMQ_BROKER_CA_CERTS} volumes: # The URI SAN in this client certificate identifies the publish proxy to # the FluxMQ local listener; the broker ACL only permits publishing to the # message topic namespace. - ./ssl/certs/fluxmq-auth-fluxmq-client.crt:${MG_FLUXMQ_BROKER_CLIENT_CERT}:ro - ./ssl/certs/fluxmq-auth-fluxmq-client.key:${MG_FLUXMQ_BROKER_CLIENT_KEY}:ro - ./ssl/certs/ca.crt:${MG_FLUXMQ_BROKER_CA_CERTS}:ro networks: - magistrala-base-net ui: image: ghcr.io/absmach/magistrala/ui-mg:${MG_RELEASE_TAG} container_name: magistrala-ui restart: unless-stopped ports: - 3000:3000 networks: - magistrala-base-net environment: MG_AUTH_URL: ${MG_AUTH_URL} MG_ATOM_URL: ${MG_ATOM_URL} ATOM_URL: ${ATOM_PUBLIC_URL} MG_DOMAINS_URL: ${MG_DOMAINS_URL} MG_USERS_URL: ${MG_USERS_URL} MG_CLIENTS_URL: ${MG_CLIENTS_URL} MG_CHANNELS_URL: ${MG_CHANNELS_URL} MG_GROUPS_URL: ${MG_GROUPS_URL} MG_BOOTSTRAP_URL: ${MG_BOOTSTRAP_URL} MG_HTTP_ADAPTER_URL: ${MG_HTTP_ADAPTER_URL} MG_PUBLISH_PROXY_URL: ${MG_PUBLISH_PROXY_URL} MG_READER_URL: ${MG_READER_URL} MG_BACKEND_URL: ${MG_UI_BACKEND_URL} MG_ALARMS_URL: ${MG_ALARMS_URL} MG_RE_URL: ${MG_RE_URL} MG_REPORTS_URL: ${MG_REPORTS_URL} MG_GOOGLE_CLIENT_ID: ${MG_GOOGLE_CLIENT_ID} MG_GOOGLE_CLIENT_SECRET: ${MG_GOOGLE_CLIENT_SECRET} MG_GOOGLE_REDIRECT_URL: ${MG_GOOGLE_REDIRECT_URL} MG_GOOGLE_STATE: ${MG_GOOGLE_STATE} MG_UI_BASE_PATH: ${MG_UI_BASE_PATH} MG_NEXTAUTH_BASE_PATH: ${MG_NEXTAUTH_BASE_PATH} MG_UI_TYPE: ${MG_UI_TYPE} MG_UI_CLIENT_TYPE: ${MG_UI_CLIENT_TYPE} MG_UI_BASEURL: ${MG_UI_BASEURL} NEXTAUTH_URL: ${NEXTAUTH_URL} NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} NEXT_LOG_LEVEL: "debug" MG_HOST_URL: ${MG_HOST_URL} MG_UI_IMAGE_URL: ${MG_UI_IMAGE_URL} MG_SUPPORT_EMAIL: ${MG_SUPPORT_EMAIL} MG_SUPPORT_EMAIL_PASS: ${MG_SUPPORT_EMAIL_PASS} MG_UI_CLI_MQTT_HOST: ${MG_UI_CLI_MQTT_HOST} MG_UI_CLI_WS_URL: ${MG_UI_CLI_WS_URL} MG_UI_CLI_COAP_HOST: ${MG_UI_CLI_COAP_HOST} MG_UI_CLI_COAP_PORT: ${MG_UI_CLI_COAP_PORT} MG_UI_CLI_HTTP_URL: ${MG_UI_CLI_HTTP_URL} MG_UI_ALLOW_UNVERIFIED_USER: ${MG_ALLOW_UNVERIFIED_USER} MG_ACCESS_TOKEN_EXPIRY: ${MG_AUTH_ACCESS_TOKEN_DURATION} MG_REFRESH_TOKEN_EXPIRY: ${MG_AUTH_REFRESH_TOKEN_DURATION} MG_UI_SMTP_HOST: ${MG_UI_SMTP_HOST} MG_UI_SMTP_PORT: ${MG_UI_SMTP_PORT} MG_UI_SMTP_SECURE: ${MG_UI_SMTP_SECURE} MG_UI_SUPPORT_FROM: ${MG_UI_SUPPORT_FROM} OTEL_SERVICE_NAME: ${OTEL_SERVICE_NAME} OTEL_EXPORTER_OTLP_ENDPOINT: ${OTEL_EXPORTER_OTLP_ENDPOINT} ui-backend: image: ghcr.io/absmach/magistrala/ui-backend:${MG_RELEASE_TAG} container_name: magistrala-ui-backend ports: - ${MG_UI_BACKEND_HTTP_PORT}:${MG_UI_BACKEND_HTTP_PORT} networks: - magistrala-base-net restart: on-failure:3 environment: MG_BACKEND_LOG_LEVEL: ${MG_UI_BACKEND_LOG_LEVEL} MG_BACKEND_HTTP_HOST: ${MG_UI_BACKEND_HTTP_HOST} MG_BACKEND_HTTP_PORT: ${MG_UI_BACKEND_HTTP_PORT} MG_BACKEND_HTTP_SERVER_CERT: ${MG_UI_BACKEND_HTTP_SERVER_CERT} MG_BACKEND_HTTP_SERVER_KEY: ${MG_UI_BACKEND_HTTP_SERVER_KEY} MG_BACKEND_DB_HOST: ${MG_UI_BACKEND_DB_HOST} MG_BACKEND_DB_PORT: ${MG_UI_BACKEND_DB_PORT} MG_BACKEND_DB_USER: ${MG_UI_BACKEND_DB_USER} MG_BACKEND_DB_PASS: ${MG_UI_BACKEND_DB_PASS} MG_BACKEND_DB_NAME: ${MG_UI_BACKEND_DB_NAME} MG_BACKEND_DB_SSL_MODE: ${MG_UI_BACKEND_DB_SSL_MODE} MG_BACKEND_DB_SSL_CERT: ${MG_UI_BACKEND_DB_SSL_CERT} MG_BACKEND_DB_SSL_KEY: ${MG_UI_BACKEND_DB_SSL_KEY} MG_BACKEND_DB_SSL_ROOT_CERT: ${MG_UI_BACKEND_DB_SSL_ROOT_CERT} MG_BACKEND_INSTANCE_ID: ${MG_UI_BACKEND_INSTANCE_ID} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_USERNAME: ${ATOM_SERVICE_USERNAME} ATOM_SERVICE_SECRET: ${ATOM_SERVICE_SECRET} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_AUTH_GRPC_URL: ${MG_AUTH_GRPC_URL} MG_AUTH_GRPC_TIMEOUT: ${MG_AUTH_GRPC_TIMEOUT} MG_AUTH_GRPC_CLIENT_CERT: ${MG_AUTH_GRPC_CLIENT_CERT:+/auth-grpc-client.crt} MG_AUTH_GRPC_CLIENT_KEY: ${MG_AUTH_GRPC_CLIENT_KEY:+/auth-grpc-client.key} MG_AUTH_GRPC_SERVER_CA_CERTS: ${MG_AUTH_GRPC_SERVER_CA_CERTS:+/auth-grpc-server-ca.crt} MG_UI_VERIFICATION_TLS: ${MG_UI_VERIFICATION_TLS} MG_UI_CONTENT_TYPE: ${MG_UI_CONTENT_TYPE} MG_READER_URL: ${MG_READER_URL} MG_CHANNELS_GRPC_URL: ${MG_CHANNELS_GRPC_URL} MG_CHANNELS_GRPC_TIMEOUT: ${MG_CHANNELS_GRPC_TIMEOUT} MG_CHANNELS_GRPC_CLIENT_CERT: ${MG_CHANNELS_GRPC_CLIENT_CERT:+/channels-grpc-client.crt} MG_CHANNELS_GRPC_CLIENT_KEY: ${MG_CHANNELS_GRPC_CLIENT_KEY:+/channels-grpc-client.key} MG_CHANNELS_GRPC_SERVER_CA_CERTS: ${MG_CHANNELS_GRPC_SERVER_CA_CERTS:+/channels-grpc-server-ca.crt} MG_TIMESCALE_READER_GRPC_URL: ${MG_TIMESCALE_READER_GRPC_URL} MG_TIMESCALE_READER_GRPC_TIMEOUT: ${MG_TIMESCALE_READER_GRPC_TIMEOUT} MG_TIMESCALE_READER_GRPC_CLIENT_CERT: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT:+/readers-grpc-client.crt} MG_TIMESCALE_READER_GRPC_CLIENT_KEY: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY:+/readers-grpc-client.key} MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS: ${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS:+/readers-grpc-server-ca.crt} MG_BACKEND_OBJECT_STORAGE_REGION: ${MG_BACKEND_OBJECT_STORAGE_REGION} MG_BACKEND_OBJECT_STORAGE_BUCKET: ${MG_BACKEND_OBJECT_STORAGE_BUCKET} MG_BACKEND_OBJECT_STORAGE_ENDPOINT: ${MG_BACKEND_OBJECT_STORAGE_ENDPOINT} MG_BACKEND_OBJECT_STORAGE_USE_PATH_STYLE: ${MG_BACKEND_OBJECT_STORAGE_USE_PATH_STYLE} MG_BACKEND_OBJECT_STORAGE_PRESIGN_ENDPOINT: ${MG_BACKEND_OBJECT_STORAGE_PRESIGN_ENDPOINT} MG_BACKEND_OBJECT_STORAGE_ACCESS_KEY: ${MG_BACKEND_OBJECT_STORAGE_ACCESS_KEY} MG_BACKEND_OBJECT_STORAGE_SECRET_KEY: ${MG_BACKEND_OBJECT_STORAGE_SECRET_KEY} MG_BACKEND_OBJECT_STORAGE_TTL: ${MG_BACKEND_OBJECT_STORAGE_TTL} MG_BACKEND_OBJECT_STORAGE_READ_TTL: ${MG_BACKEND_OBJECT_STORAGE_READ_TTL} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} depends_on: atom-bootstrap: condition: service_completed_successfully ui-backend-db: condition: service_healthy seaweedfs-s3: condition: service_started volumes: # Auth gRPC client certificates - type: bind source: ${MG_AUTH_GRPC_CLIENT_CERT:-./ssl/placeholder} target: /auth-grpc-client.crt bind: create_host_path: true - type: bind source: ${MG_AUTH_GRPC_CLIENT_KEY:-./ssl/placeholder} target: /auth-grpc-client.key bind: create_host_path: true - type: bind source: ${MG_AUTH_GRPC_SERVER_CA_CERTS:-./ssl/placeholder} target: /auth-grpc-server-ca.crt bind: create_host_path: true # Channels gRPC client certificates - type: bind source: ${MG_CHANNELS_GRPC_CLIENT_CERT:-./ssl/placeholder} target: /channels-grpc-client.crt bind: create_host_path: true - type: bind source: ${MG_CHANNELS_GRPC_CLIENT_KEY:-./ssl/placeholder} target: /channels-grpc-client.key bind: create_host_path: true - type: bind source: ${MG_CHANNELS_GRPC_SERVER_CA_CERTS:-./ssl/placeholder} target: /channels-grpc-server-ca.crt bind: create_host_path: true # Reader gRPC client certificates - type: bind source: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT:-./ssl/placeholder} target: /readers-grpc-client.crt bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY:-./ssl/placeholder} target: /readers-grpc-client.key bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS:-./ssl/placeholder} target: /readers-grpc-server-ca.crt bind: create_host_path: true ui-backend-db: image: docker.io/postgres:18.4-alpine3.24 container_name: magistrala-ui-backend-db restart: on-failure command: postgres -c "max_connections=${MG_POSTGRES_MAX_CONNECTIONS}" environment: PGDATA: /var/lib/postgresql/data POSTGRES_USER: ${MG_UI_BACKEND_DB_USER} POSTGRES_PASSWORD: ${MG_UI_BACKEND_DB_PASS} POSTGRES_DB: ${MG_UI_BACKEND_DB_NAME} MG_POSTGRES_MAX_CONNECTIONS: ${MG_POSTGRES_MAX_CONNECTIONS} ports: - 6008:5432 networks: - magistrala-base-net volumes: - magistrala-ui-backend-db-volume:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 3s retries: 60 seaweedfs-s3: image: chrislusf/seaweedfs:4.40 container_name: magistrala-seaweedfs-s3 command: server -s3 -s3.config=/etc/seaweedfs/s3.json -dir=/data ports: - "8333:8333" - "9333:9333" - "19333:19333" - "8888:8888" volumes: - ./data/seaweedfs:/data - ./seaweedfs/s3.json:/etc/seaweedfs/s3.json:ro networks: - magistrala-base-net # Creates the image bucket with the broker's own image rather than pulling a # second one. An aws-cli here cost a 130 MB image for a single call, and it # was the only untagged reference in this file, so what it resolved to # depended on the day it was pulled. seaweedfs-init: image: chrislusf/seaweedfs:4.40 container_name: magistrala-seaweedfs-init entrypoint: /bin/sh depends_on: - seaweedfs-s3 command: - -c - | set -eu # weed shell blocks indefinitely against an unreachable master, so the # wait is a port check and every weed call is bounded; left to itself it # would hang this container rather than fail it. # # 60 ticks is ~2 minutes while the store is merely slow to boot, and # ~3 minutes to give up when it never appears, since a failing lookup # costs about a second on top of the sleep. tick=0; while ! nc -z seaweedfs-s3 9333 2>/dev/null; do tick=$$((tick + 1)); if [ $$tick -ge 60 ]; then echo "[INIT] SeaweedFS master did not come up" >&2; exit 1; fi; sleep 2; done; printf 's3.bucket.create -name %s\n' "$${BUCKET}" > /tmp/create.cmd; printf 's3.bucket.list\n' > /tmp/list.cmd; try=0; while [ $$try -lt 3 ]; do try=$$((try + 1)); timeout 20 weed shell -master seaweedfs-s3:9333 < /tmp/create.cmd > /tmp/create.out 2>&1 || true; timeout 20 weed shell -master seaweedfs-s3:9333 < /tmp/list.cmd > /tmp/list.out 2>/dev/null || true; # s3.bucket.create reports success even for an existing bucket, and # weed shell exits 0 whatever the command did, so the listing is the # only trustworthy signal that the bucket is really there. if awk -v b="$${BUCKET}" '{sub(/^[ \t]+/,""); split($$0,f,/[ \t]/); if (f[1]==b) found=1} END{exit !found}' /tmp/list.out; then echo "[INIT] Bucket $${BUCKET} present."; exit 0; fi; sleep 3; done; echo "[INIT] Bucket $${BUCKET} was not created after $$try attempts" >&2; cat /tmp/create.out >&2; exit 1 networks: - magistrala-base-net environment: BUCKET: ${MG_BACKEND_OBJECT_STORAGE_BUCKET} timescale: image: timescale/timescaledb:2.29.0-pg16-oss container_name: magistrala-timescale restart: on-failure environment: POSTGRES_PASSWORD: ${MG_TIMESCALE_PASS} POSTGRES_USER: ${MG_TIMESCALE_USER} POSTGRES_DB: ${MG_TIMESCALE_NAME} ports: - 5433:5432 networks: - magistrala-base-net volumes: - magistrala-timescale-writer-volume:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 3s retries: 60 timescale-reader: image: ghcr.io/absmach/magistrala/timescale-reader:${MG_RELEASE_TAG} container_name: magistrala-timescale-reader depends_on: timescale: condition: service_healthy atom-bootstrap: condition: service_completed_successfully restart: on-failure environment: MG_TIMESCALE_READER_LOG_LEVEL: ${MG_TIMESCALE_READER_LOG_LEVEL} MG_TIMESCALE_READER_HTTP_HOST: ${MG_TIMESCALE_READER_HTTP_HOST} MG_TIMESCALE_READER_HTTP_PORT: ${MG_TIMESCALE_READER_HTTP_PORT} MG_TIMESCALE_READER_HTTP_SERVER_CERT: ${MG_TIMESCALE_READER_HTTP_SERVER_CERT} MG_TIMESCALE_READER_HTTP_SERVER_KEY: ${MG_TIMESCALE_READER_HTTP_SERVER_KEY} MG_TIMESCALE_HOST: ${MG_TIMESCALE_HOST} MG_TIMESCALE_PORT: ${MG_TIMESCALE_PORT} MG_TIMESCALE_USER: ${MG_TIMESCALE_USER} MG_TIMESCALE_PASS: ${MG_TIMESCALE_PASS} MG_TIMESCALE_NAME: ${MG_TIMESCALE_NAME} MG_TIMESCALE_SSL_MODE: ${MG_TIMESCALE_SSL_MODE} MG_TIMESCALE_SSL_CERT: ${MG_TIMESCALE_SSL_CERT} MG_TIMESCALE_SSL_KEY: ${MG_TIMESCALE_SSL_KEY} MG_TIMESCALE_SSL_ROOT_CERT: ${MG_TIMESCALE_SSL_ROOT_CERT} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_TOKEN: ${MG_ATOM_TOKEN_TIMESCALE_READER} ATOM_JWKS_URL: ${ATOM_JWKS_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_TIMESCALE_READER_GRPC_URL: ${MG_TIMESCALE_READER_GRPC_URL} MG_TIMESCALE_READER_GRPC_PORT: ${MG_TIMESCALE_READER_GRPC_PORT} MG_TIMESCALE_READER_GRPC_HOST: ${MG_TIMESCALE_READER_GRPC_HOST} MG_TIMESCALE_READER_GRPC_TIMEOUT: ${MG_TIMESCALE_READER_GRPC_TIMEOUT} MG_TIMESCALE_READER_GRPC_CLIENT_CERT: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT:+/readers-grpc-client.crt} MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS: ${MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS:+/readers-grpc-client-ca.crt} MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS: ${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS:+/readers-grpc-server-ca.crt} MG_TIMESCALE_READER_GRPC_CLIENT_KEY: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY:+/readers-grpc-client.key} MG_TIMESCALE_READER_GRPC_SERVER_CERT: ${MG_TIMESCALE_READER_GRPC_SERVER_CERT:+/readers-grpc-server.crt} MG_TIMESCALE_READER_GRPC_SERVER_KEY: ${MG_TIMESCALE_READER_GRPC_SERVER_KEY:+/readers-grpc-server.key} MG_SEND_TELEMETRY: ${MG_SEND_TELEMETRY} MG_TIMESCALE_READER_INSTANCE_ID: ${MG_TIMESCALE_READER_INSTANCE_ID} ports: - ${MG_TIMESCALE_READER_HTTP_PORT}:${MG_TIMESCALE_READER_HTTP_PORT} - ${MG_TIMESCALE_READER_GRPC_PORT}:${MG_TIMESCALE_READER_GRPC_PORT} networks: - magistrala-base-net volumes: # Reader gRPC server and client certificates - type: bind source: ${MG_TIMESCALE_READER_GRPC_SERVER_CERT:-./ssl/placeholder} target: /readers-grpc-server${MG_TIMESCALE_READER_GRPC_SERVER_CERT:+.crt} bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_SERVER_KEY:-./ssl/placeholder} target: /readers-grpc-server${MG_TIMESCALE_READER_GRPC_SERVER_KEY:+.key} bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS:-./ssl/placeholder} target: /readers-grpc-server-ca${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS:+.crt} bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS:-./ssl/placeholder} target: /readers-grpc-client-ca${MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS:+.crt} bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT:-./ssl/placeholder} target: /readers-grpc-client${MG_TIMESCALE_READER_GRPC_CLIENT_CERT:+.crt} bind: create_host_path: true - type: bind source: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY:-./ssl/placeholder} target: /readers-grpc-client${MG_TIMESCALE_READER_GRPC_CLIENT_KEY:+.key} bind: create_host_path: true timescale-writer: image: ghcr.io/absmach/magistrala/timescale-writer:${MG_RELEASE_TAG} container_name: magistrala-timescale-writer depends_on: timescale: condition: service_healthy fluxmq-node1: condition: service_healthy restart: on-failure environment: MG_TIMESCALE_WRITER_LOG_LEVEL: ${MG_TIMESCALE_WRITER_LOG_LEVEL} MG_TIMESCALE_WRITER_CONFIG_PATH: ${MG_TIMESCALE_WRITER_CONFIG_PATH} MG_TIMESCALE_WRITER_HTTP_HOST: ${MG_TIMESCALE_WRITER_HTTP_HOST} MG_TIMESCALE_WRITER_HTTP_PORT: ${MG_TIMESCALE_WRITER_HTTP_PORT} MG_TIMESCALE_WRITER_HTTP_SERVER_CERT: ${MG_TIMESCALE_WRITER_HTTP_SERVER_CERT} MG_TIMESCALE_WRITER_HTTP_SERVER_KEY: ${MG_TIMESCALE_WRITER_HTTP_SERVER_KEY} MG_TIMESCALE_HOST: ${MG_TIMESCALE_HOST} MG_TIMESCALE_PORT: ${MG_TIMESCALE_PORT} MG_TIMESCALE_USER: ${MG_TIMESCALE_USER} MG_TIMESCALE_PASS: ${MG_TIMESCALE_PASS} MG_TIMESCALE_NAME: ${MG_TIMESCALE_NAME} MG_TIMESCALE_SSL_MODE: ${MG_TIMESCALE_SSL_MODE} MG_TIMESCALE_SSL_CERT: ${MG_TIMESCALE_SSL_CERT} MG_TIMESCALE_SSL_KEY: ${MG_TIMESCALE_SSL_KEY} MG_TIMESCALE_SSL_ROOT_CERT: ${MG_TIMESCALE_SSL_ROOT_CERT} MG_MESSAGE_BROKER_URL: ${MG_TIMESCALE_WRITER_BROKER_URL} MG_TIMESCALE_WRITER_BROKER_CLIENT_CERT: ${MG_TIMESCALE_WRITER_BROKER_CLIENT_CERT} MG_TIMESCALE_WRITER_BROKER_CLIENT_KEY: ${MG_TIMESCALE_WRITER_BROKER_CLIENT_KEY} MG_TIMESCALE_WRITER_BROKER_CA_CERTS: ${MG_TIMESCALE_WRITER_BROKER_CA_CERTS} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} MG_SEND_TELEMETRY: ${MG_SEND_TELEMETRY} MG_TIMESCALE_WRITER_INSTANCE_ID: ${MG_TIMESCALE_WRITER_INSTANCE_ID} ports: - ${MG_TIMESCALE_WRITER_HTTP_PORT}:${MG_TIMESCALE_WRITER_HTTP_PORT} networks: - magistrala-base-net volumes: - ./addons/timescale-writer/config.toml:${MG_TIMESCALE_WRITER_CONFIG_PATH} # The URI SAN in this client certificate identifies the Timescale writer # to the FluxMQ local listener; the broker ACL only permits `writers`. - ./ssl/certs/timescale-writer-fluxmq-client.crt:${MG_TIMESCALE_WRITER_BROKER_CLIENT_CERT}:ro - ./ssl/certs/timescale-writer-fluxmq-client.key:${MG_TIMESCALE_WRITER_BROKER_CLIENT_KEY}:ro - ./ssl/certs/ca.crt:${MG_TIMESCALE_WRITER_BROKER_CA_CERTS}:ro re-db: image: docker.io/postgres:18.4-alpine3.24 container_name: magistrala-re-db restart: on-failure command: postgres -c "max_connections=${MG_POSTGRES_MAX_CONNECTIONS}" environment: PGDATA: /var/lib/postgresql/data POSTGRES_USER: ${MG_RE_DB_USER} POSTGRES_PASSWORD: ${MG_RE_DB_PASS} POSTGRES_DB: ${MG_RE_DB_NAME} ports: - 6009:5432 networks: - magistrala-base-net volumes: - magistrala-re-db-volume:/var/lib/postgresql/data re: image: ghcr.io/absmach/magistrala/re:${MG_RELEASE_TAG} container_name: magistrala-re depends_on: re-db: condition: service_started atom-bootstrap: condition: service_completed_successfully nginx: condition: service_started restart: on-failure environment: MG_RE_LOG_LEVEL: ${MG_RE_LOG_LEVEL} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_TOKEN: ${MG_ATOM_TOKEN_RE} ATOM_JWKS_URL: ${ATOM_JWKS_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_RE_HTTP_PORT: ${MG_RE_HTTP_PORT} MG_RE_HTTP_HOST: ${MG_RE_HTTP_HOST} MG_RE_HTTP_SERVER_CERT: ${MG_RE_HTTP_SERVER_CERT} MG_RE_HTTP_SERVER_KEY: ${MG_RE_HTTP_SERVER_KEY} MG_RE_DB_HOST: ${MG_RE_DB_HOST} MG_RE_DB_PORT: ${MG_RE_DB_PORT} MG_RE_DB_USER: ${MG_RE_DB_USER} MG_RE_DB_PASS: ${MG_RE_DB_PASS} MG_RE_DB_NAME: ${MG_RE_DB_NAME} MG_RE_DB_SSL_MODE: ${MG_RE_DB_SSL_MODE} MG_RE_DB_SSL_CERT: ${MG_RE_DB_SSL_CERT} MG_RE_DB_SSL_KEY: ${MG_RE_DB_SSL_KEY} MG_RE_DB_SSL_ROOT_CERT: ${MG_RE_DB_SSL_ROOT_CERT} MG_RE_CALLOUT_URLS: ${MG_RE_CALLOUT_URLS} MG_RE_CALLOUT_METHOD: ${MG_RE_CALLOUT_METHOD} MG_RE_CALLOUT_TLS_VERIFICATION: ${MG_RE_CALLOUT_TLS_VERIFICATION} MG_RE_CALLOUT_TIMEOUT: ${MG_RE_CALLOUT_TIMEOUT} MG_RE_CALLOUT_CA_CERT: ${MG_RE_CALLOUT_CA_CERT} MG_RE_CALLOUT_CERT: ${MG_RE_CALLOUT_CERT} MG_RE_CALLOUT_KEY: ${MG_RE_CALLOUT_KEY} MG_RE_CALLOUT_OPERATIONS: ${MG_RE_CALLOUT_OPERATIONS} MG_MESSAGE_BROKER_URL: ${MG_MESSAGE_BROKER_URL} MG_ES_URL: ${MG_ES_URL} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} MG_SEND_TELEMETRY: ${MG_SEND_TELEMETRY} MG_PERMISSIONS_FILE: ${MG_PERMISSIONS_FILE} MG_RE_INSTANCE_ID: ${MG_RE_INSTANCE_ID} MG_RE_MAX_RULE_HOPS: ${MG_RE_MAX_RULE_HOPS} MG_RE_TRACE_KEY: ${MG_RE_TRACE_KEY} MG_RE_TRACE_KEY_FILE: ${MG_RE_TRACE_KEY_FILE} MG_RE_BROKER_URL: ${MG_RE_BROKER_URL} MG_RE_BROKER_CLIENT_CERT: ${MG_RE_BROKER_CLIENT_CERT} MG_RE_BROKER_CLIENT_KEY: ${MG_RE_BROKER_CLIENT_KEY} MG_RE_BROKER_CA_CERTS: ${MG_RE_BROKER_CA_CERTS} MG_EMAIL_HOST: ${MG_EMAIL_HOST} MG_EMAIL_PORT: ${MG_EMAIL_PORT} MG_EMAIL_USERNAME: ${MG_EMAIL_USERNAME} MG_EMAIL_PASSWORD: ${MG_EMAIL_PASSWORD} MG_EMAIL_FROM_ADDRESS: ${MG_EMAIL_FROM_ADDRESS} MG_EMAIL_FROM_NAME: ${MG_EMAIL_FROM_NAME} MG_EMAIL_TEMPLATE: ${MG_EMAIL_TEMPLATE} MG_TIMESCALE_READER_GRPC_URL: ${MG_TIMESCALE_READER_GRPC_URL} MG_TIMESCALE_READER_GRPC_TIMEOUT: ${MG_TIMESCALE_READER_GRPC_TIMEOUT} MG_TIMESCALE_READER_GRPC_CLIENT_CERT: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT} MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS: ${MG_TIMESCALE_READER_GRPC_CLIENT_CA_CERTS} MG_TIMESCALE_READER_GRPC_CLIENT_KEY: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY} MG_ALLOW_UNVERIFIED_USER: ${MG_ALLOW_UNVERIFIED_USER} ports: - ${MG_RE_HTTP_PORT}:${MG_RE_HTTP_PORT} networks: - magistrala-base-net volumes: - ./permission.yaml:${MG_PERMISSIONS_FILE} - ./templates/${MG_RE_EMAIL_TEMPLATE}:/email.tmpl # Client certificate for the FluxMQ service listener. Its URI SAN is what # the broker matches against the rules-engine local principal. - ./ssl/certs/re-fluxmq-client.crt:${MG_RE_BROKER_CLIENT_CERT}:ro - ./ssl/certs/re-fluxmq-client.key:${MG_RE_BROKER_CLIENT_KEY}:ro - ./ssl/certs/ca.crt:${MG_RE_BROKER_CA_CERTS}:ro - ./re/secrets/trace.key:/run/secrets/magistrala-re-trace-key:ro alarms-db: image: docker.io/postgres:18.4-alpine3.24 container_name: magistrala-alarms-db restart: on-failure command: postgres -c "max_connections=${MG_POSTGRES_MAX_CONNECTIONS}" environment: PGDATA: /var/lib/postgresql/data POSTGRES_USER: ${MG_ALARMS_DB_USER} POSTGRES_PASSWORD: ${MG_ALARMS_DB_PASS} POSTGRES_DB: ${MG_ALARMS_DB_NAME} ports: - 6019:5432 networks: - magistrala-base-net volumes: - magistrala-alarms-db-volume:/var/lib/postgresql/data alarms: image: ghcr.io/absmach/magistrala/alarms:${MG_RELEASE_TAG} container_name: magistrala-alarms depends_on: alarms-db: condition: service_started atom-bootstrap: condition: service_completed_successfully nginx: condition: service_started restart: on-failure environment: MG_ALARMS_LOG_LEVEL: ${MG_ALARMS_LOG_LEVEL} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_TOKEN: ${MG_ATOM_TOKEN_ALARMS} ATOM_JWKS_URL: ${ATOM_JWKS_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_ALARMS_HTTP_PORT: ${MG_ALARMS_HTTP_PORT} MG_ALARMS_HTTP_HOST: ${MG_ALARMS_HTTP_HOST} MG_ALARMS_HTTP_SERVER_CERT: ${MG_ALARMS_HTTP_SERVER_CERT} MG_ALARMS_HTTP_SERVER_KEY: ${MG_ALARMS_HTTP_SERVER_KEY} MG_ALARMS_DB_HOST: ${MG_ALARMS_DB_HOST} MG_ALARMS_DB_PORT: ${MG_ALARMS_DB_PORT} MG_ALARMS_DB_USER: ${MG_ALARMS_DB_USER} MG_ALARMS_DB_PASS: ${MG_ALARMS_DB_PASS} MG_ALARMS_DB_NAME: ${MG_ALARMS_DB_NAME} MG_ALARMS_DB_SSL_MODE: ${MG_ALARMS_DB_SSL_MODE} MG_ALARMS_DB_SSL_CERT: ${MG_ALARMS_DB_SSL_CERT} MG_ALARMS_DB_SSL_KEY: ${MG_ALARMS_DB_SSL_KEY} MG_ALARMS_DB_SSL_ROOT_CERT: ${MG_ALARMS_DB_SSL_ROOT_CERT} MG_MESSAGE_BROKER_URL: ${MG_MESSAGE_BROKER_URL} MG_ES_URL: ${MG_ES_URL} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} MG_PERMISSIONS_FILE: ${MG_PERMISSIONS_FILE} MG_ALARMS_INSTANCE_ID: ${MG_ALARMS_INSTANCE_ID} MG_ALARMS_EVENT_CONSUMER: ${MG_ALARMS_EVENT_CONSUMER} MG_ALLOW_UNVERIFIED_USER: ${MG_ALLOW_UNVERIFIED_USER} ports: - ${MG_ALARMS_HTTP_PORT}:${MG_ALARMS_HTTP_PORT} networks: - magistrala-base-net volumes: - ./permission.yaml:${MG_PERMISSIONS_FILE} reports-db: image: docker.io/postgres:18.4-alpine3.24 container_name: magistrala-reports-db restart: on-failure command: postgres -c "max_connections=${MG_POSTGRES_MAX_CONNECTIONS}" environment: PGDATA: /var/lib/postgresql/data POSTGRES_USER: ${MG_REPORTS_DB_USER} POSTGRES_PASSWORD: ${MG_REPORTS_DB_PASS} POSTGRES_DB: ${MG_REPORTS_DB_NAME} ports: - 6020:5432 networks: - magistrala-base-net volumes: - magistrala-reports-db-volume:/var/lib/postgresql/data reports: image: ghcr.io/absmach/magistrala/reports:${MG_RELEASE_TAG} container_name: magistrala-reports depends_on: reports-db: condition: service_started atom-bootstrap: condition: service_completed_successfully nginx: condition: service_started restart: on-failure environment: MG_REPORTS_LOG_LEVEL: ${MG_REPORTS_LOG_LEVEL} ATOM_URL: ${ATOM_URL} ATOM_SERVICE_TOKEN: ${MG_ATOM_TOKEN_REPORTS} ATOM_JWKS_URL: ${ATOM_JWKS_URL} ATOM_JWT_ISSUER: ${ATOM_JWT_ISSUER} ATOM_JWT_AUDIENCE: ${ATOM_JWT_AUDIENCE} ATOM_TIMEOUT: ${ATOM_TIMEOUT} MG_REPORTS_HTTP_PORT: ${MG_REPORTS_HTTP_PORT} MG_REPORTS_HTTP_HOST: ${MG_REPORTS_HTTP_HOST} MG_REPORTS_HTTP_SERVER_CERT: ${MG_REPORTS_HTTP_SERVER_CERT} MG_REPORTS_HTTP_SERVER_KEY: ${MG_REPORTS_HTTP_SERVER_KEY} MG_REPORTS_DB_HOST: ${MG_REPORTS_DB_HOST} MG_REPORTS_DB_PORT: ${MG_REPORTS_DB_PORT} MG_REPORTS_DB_USER: ${MG_REPORTS_DB_USER} MG_REPORTS_DB_PASS: ${MG_REPORTS_DB_PASS} MG_REPORTS_DB_NAME: ${MG_REPORTS_DB_NAME} MG_REPORTS_DB_SSL_MODE: ${MG_REPORTS_DB_SSL_MODE} MG_REPORTS_DB_SSL_CERT: ${MG_REPORTS_DB_SSL_CERT} MG_REPORTS_DB_SSL_KEY: ${MG_REPORTS_DB_SSL_KEY} MG_REPORTS_DB_SSL_ROOT_CERT: ${MG_REPORTS_DB_SSL_ROOT_CERT} MG_REPORTS_DEFAULT_TEMPLATE: ${MG_REPORTS_DEFAULT_TEMPLATE} MG_PDF_CONVERTER_URL: ${MG_PDF_CONVERTER_URL} MG_REPORTS_CALLOUT_URLS: ${MG_REPORTS_CALLOUT_URLS} MG_REPORTS_CALLOUT_METHOD: ${MG_REPORTS_CALLOUT_METHOD} MG_REPORTS_CALLOUT_TLS_VERIFICATION: ${MG_REPORTS_CALLOUT_TLS_VERIFICATION} MG_REPORTS_CALLOUT_TIMEOUT: ${MG_REPORTS_CALLOUT_TIMEOUT} MG_REPORTS_CALLOUT_CA_CERT: ${MG_REPORTS_CALLOUT_CA_CERT} MG_REPORTS_CALLOUT_CERT: ${MG_REPORTS_CALLOUT_CERT} MG_REPORTS_CALLOUT_KEY: ${MG_REPORTS_CALLOUT_KEY} MG_REPORTS_CALLOUT_OPERATIONS: ${MG_REPORTS_CALLOUT_OPERATIONS} MG_MESSAGE_BROKER_URL: ${MG_MESSAGE_BROKER_URL} MG_ES_URL: ${MG_ES_URL} MG_JAEGER_URL: ${MG_JAEGER_URL} MG_JAEGER_TRACE_RATIO: ${MG_JAEGER_TRACE_RATIO} MG_SEND_TELEMETRY: ${MG_SEND_TELEMETRY} MG_PERMISSIONS_FILE: ${MG_PERMISSIONS_FILE} MG_REPORTS_INSTANCE_ID: ${MG_RE_INSTANCE_ID} MG_EMAIL_HOST: ${MG_EMAIL_HOST} MG_EMAIL_PORT: ${MG_EMAIL_PORT} MG_EMAIL_USERNAME: ${MG_EMAIL_USERNAME} MG_EMAIL_PASSWORD: ${MG_EMAIL_PASSWORD} MG_EMAIL_FROM_ADDRESS: ${MG_EMAIL_FROM_ADDRESS} MG_EMAIL_FROM_NAME: ${MG_EMAIL_FROM_NAME} MG_EMAIL_TEMPLATE: ${MG_EMAIL_TEMPLATE} MG_TIMESCALE_READER_GRPC_URL: ${MG_TIMESCALE_READER_GRPC_URL} MG_TIMESCALE_READER_GRPC_TIMEOUT: ${MG_TIMESCALE_READER_GRPC_TIMEOUT} MG_TIMESCALE_READER_GRPC_CLIENT_CERT: ${MG_TIMESCALE_READER_GRPC_CLIENT_CERT} MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS: ${MG_TIMESCALE_READER_GRPC_SERVER_CA_CERTS} MG_TIMESCALE_READER_GRPC_CLIENT_KEY: ${MG_TIMESCALE_READER_GRPC_CLIENT_KEY} MG_ALLOW_UNVERIFIED_USER: ${MG_ALLOW_UNVERIFIED_USER} ports: - ${MG_REPORTS_HTTP_PORT}:${MG_REPORTS_HTTP_PORT} networks: - magistrala-base-net volumes: - ./permission.yaml:${MG_PERMISSIONS_FILE} - ./templates/${MG_REPORTS_EMAIL_TEMPLATE}:/email.tmpl pdf-generator: image: gotenberg/gotenberg:8.34.0 container_name: magistrala-pdf restart: on-failure # Gotenberg leaks memory over time (upstream issues #987, #1169); the cap # keeps the OOM kill inside this container instead of stalling the host. mem_limit: 512m ports: - "4000:3000" networks: - magistrala-base-net