# Portainer stack: registry-based images (no build). Use with CI/CD webhook redeploy. # Set in Portainer stack env (or .env): REGISTRY, IMAGE_TAG (defaults below). # Images: ${REGISTRY}/mifi-holdings/shorty-qr-api:${IMAGE_TAG}, shorty-qr-web:${IMAGE_TAG} services: kutt_db: image: postgres:16-alpine restart: unless-stopped networks: - backend volumes: - /mnt/config/docker/kutt/postgres:/var/lib/postgresql/data environment: POSTGRES_USER: ${DB_USER:-kutt} POSTGRES_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD} POSTGRES_DB: ${DB_NAME:-kutt} healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-kutt} -d ${DB_NAME:-kutt}"] interval: 10s timeout: 5s retries: 5 kutt_redis: image: redis:7-alpine restart: unless-stopped networks: - backend volumes: - /mnt/config/docker/kutt/redis:/data command: redis-server --appendonly yes kutt: image: kutt/kutt:latest restart: unless-stopped networks: - marina-net - backend depends_on: kutt_db: condition: service_healthy kutt_redis: condition: service_started environment: DB_CLIENT: pg DB_HOST: kutt_db DB_PORT: "5432" DB_USER: ${DB_USER:-kutt} DB_PASSWORD: ${DB_PASSWORD:?Set DB_PASSWORD} DB_NAME: ${DB_NAME:-kutt} REDIS_ENABLED: "true" REDIS_HOST: kutt_redis REDIS_PORT: "6379" DEFAULT_DOMAIN: mifi.me NODE_ENV: production JWT_SECRET: ${JWT_SECRET:?Set JWT_SECRET} labels: - "traefik.enable=true" - "docker.network=marina-net" - "traefik.http.routers.kutt-mifi.rule=Host(`mifi.me`)" - "traefik.http.routers.kutt-mifi.entrypoints=websecure" - "traefik.http.routers.kutt-mifi.tls.certresolver=letsencrypt" - "traefik.http.routers.kutt-mifi.service=kutt-short" - "traefik.http.services.kutt-short.loadbalancer.server.port=3000" - "traefik.http.routers.kutt-link.rule=Host(`link.mifi.me`)" - "traefik.http.routers.kutt-link.entrypoints=websecure" - "traefik.http.routers.kutt-link.tls.certresolver=letsencrypt" - "traefik.http.routers.kutt-link.service=kutt" - "traefik.http.services.kutt.loadbalancer.server.port=3000" qr_api: image: ${REGISTRY:-git.mifi.dev}/mifi-holdings/shorty-qr-api:${IMAGE_TAG:-latest} container_name: qr_api restart: unless-stopped networks: - backend volumes: - /mnt/config/docker/qr/db:/data - /mnt/config/docker/qr/uploads:/uploads environment: PORT: "8080" DB_PATH: /data/db.sqlite UPLOADS_PATH: /uploads KUTT_API_KEY: ${KUTT_API_KEY:-} KUTT_BASE_URL: http://kutt:3000 SHORT_DOMAIN: https://mifi.me qr_web: image: ${REGISTRY:-git.mifi.dev}/mifi-holdings/shorty-qr-web:${IMAGE_TAG:-latest} restart: unless-stopped networks: - marina-net - backend depends_on: - qr_api environment: QR_API_URL: http://qr_api:8080 labels: - "traefik.enable=true" - "docker.network=marina-net" - "traefik.http.routers.qr-web.rule=Host(`qr.mifi.dev`)" - "traefik.http.routers.qr-web.entrypoints=websecure" - "traefik.http.routers.qr-web.tls.certresolver=letsencrypt" - "traefik.http.routers.qr-web.service=qr-web" - "traefik.http.routers.qr-web.middlewares=qr-web-basicauth" - "traefik.http.middlewares.qr-web-basicauth.basicauth.users=mifi:$$2y$$05$$TS20fkfrmJ3MLc.cgfM6OcuowOstcy/2DTOq0YfirUDU3b0vtNz." - "traefik.http.services.qr-web.loadbalancer.server.port=3000" networks: marina-net: external: true backend: driver: bridge