#---------------------------------------------------------------------# # OpnForm — Beautiful open-source form builder # #---------------------------------------------------------------------# services: api: &api-service image: {{ opnform_api_image }} container_name: opnform-api restart: unless-stopped volumes: - {{ opnform_storage_dir }}:/usr/share/nginx/html/storage:rw environment: &api-env APP_ENV: production APP_KEY: "{{ opnform_app_key }}" APP_URL: "{{ opnform_base_url }}" APP_DEBUG: "false" SELF_HOSTED: "true" LOG_CHANNEL: errorlog LOG_LEVEL: info DB_CONNECTION: pgsql DB_HOST: db DB_PORT: "5432" DB_DATABASE: "{{ opnform_db_name }}" DB_USERNAME: "{{ opnform_db_user }}" DB_PASSWORD: "{{ opnform_db_password }}" REDIS_HOST: redis REDIS_PORT: "6379" CACHE_STORE: redis CACHE_DRIVER: redis QUEUE_CONNECTION: redis SESSION_DRIVER: redis SESSION_LIFETIME: "120" BROADCAST_CONNECTION: log FILESYSTEM_DISK: local FILESYSTEM_DRIVER: local LOCAL_FILESYSTEM_VISIBILITY: public MAIL_MAILER: "{{ opnform_mail_mailer }}" MAIL_HOST: "{{ opnform_mail_host }}" MAIL_PORT: "{{ opnform_mail_port }}" MAIL_USERNAME: "{{ opnform_mail_username }}" MAIL_PASSWORD: "{{ opnform_mail_password }}" MAIL_ENCRYPTION: "{{ opnform_mail_encryption }}" MAIL_FROM_ADDRESS: "{{ opnform_mail_from_address }}" MAIL_FROM_NAME: "{{ opnform_mail_from_name }}" JWT_TTL: "1440" JWT_SECRET: "{{ opnform_jwt_secret }}" PHP_MEMORY_LIMIT: "{{ opnform_php_memory_limit }}" PHP_MAX_EXECUTION_TIME: "{{ opnform_php_max_execution_time }}" PHP_UPLOAD_MAX_FILESIZE: "{{ opnform_php_upload_max_filesize }}" PHP_POST_MAX_SIZE: "{{ opnform_php_post_max_size }}" depends_on: db: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD-SHELL", "php /usr/share/nginx/html/artisan about || exit 1"] interval: 30s timeout: 15s retries: 3 start_period: 60s networks: - opnform-internal api-worker: <<: *api-service container_name: opnform-api-worker command: ["php", "artisan", "queue:work"] environment: <<: *api-env IS_API_WORKER: "true" healthcheck: test: ["CMD-SHELL", "pgrep -f 'php artisan queue:work' > /dev/null || exit 1"] interval: 60s timeout: 10s retries: 3 start_period: 30s api-scheduler: <<: *api-service container_name: opnform-api-scheduler command: ["php", "artisan", "schedule:work"] healthcheck: test: - "CMD-SHELL" - "php /usr/share/nginx/html/artisan app:scheduler-status --mode=check --max-minutes=3 || exit 1" interval: 60s timeout: 30s retries: 3 start_period: 70s ui: image: {{ opnform_client_image }} container_name: opnform-ui restart: unless-stopped environment: NUXT_PUBLIC_APP_URL: "{{ opnform_base_url }}" NUXT_PUBLIC_API_BASE: "/api" NUXT_PRIVATE_API_BASE: "http://ingress/api" NUXT_PUBLIC_ENV: production FRONT_API_SECRET: "{{ opnform_front_api_secret }}" depends_on: api: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget --spider -q http://localhost:3000/login || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 45s networks: - opnform-internal redis: image: {{ opnform_redis_image }} container_name: opnform-redis restart: unless-stopped volumes: - {{ opnform_redis_data_dir }}:/data healthcheck: test: ["CMD-SHELL", "redis-cli ping | grep PONG"] interval: 30s timeout: 5s networks: - opnform-internal db: image: {{ opnform_db_image }} container_name: opnform-db restart: unless-stopped environment: POSTGRES_DB: "{{ opnform_db_name }}" POSTGRES_USER: "{{ opnform_db_user }}" POSTGRES_PASSWORD: "{{ opnform_db_password }}" volumes: - {{ opnform_db_data_dir }}:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U {{ opnform_db_user }}"] interval: 30s timeout: 5s networks: - opnform-internal ingress: image: {{ opnform_ingress_image }} container_name: opnform-ingress restart: unless-stopped volumes: - ./nginx.conf:/etc/nginx/templates/default.conf.template:ro environment: NGINX_MAX_BODY_SIZE: "{{ opnform_nginx_max_body_size }}" depends_on: api: condition: service_started ui: condition: service_started healthcheck: test: ["CMD-SHELL", "nginx -t && curl -f http://localhost/ || exit 1"] interval: 30s timeout: 5s retries: 3 start_period: 10s networks: - opnform-internal - {{ opnform_traefik_network }} labels: - traefik.enable=true - traefik.docker.network={{ opnform_traefik_network }} - traefik.http.routers.{{ opnform_service_name }}.rule=Host(`{{ opnform_domain }}`) {% if opnform_use_ssl %} - traefik.http.routers.{{ opnform_service_name }}.entrypoints=websecure - traefik.http.routers.{{ opnform_service_name }}.tls=true {% else %} - traefik.http.routers.{{ opnform_service_name }}.entrypoints=web {% endif %} - traefik.http.services.{{ opnform_service_name }}.loadbalancer.server.port=80 networks: opnform-internal: driver: bridge {{ opnform_traefik_network }}: external: true