services: db: image: mariadb:11.8.8-noble restart: unless-stopped init: true environment: MARIADB_DATABASE: ${MARIADB_DATABASE:-azionelab} MARIADB_USER: ${MARIADB_USER:-azionelab} MARIADB_PASSWORD: ${MARIADB_PASSWORD:-replace-with-a-local-password} MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-replace-with-a-local-root-password} WP_ENVIRONMENT_TYPE: ${WP_ENVIRONMENT_TYPE:-local} entrypoint: ["/bin/sh", "/usr/local/bin/check-environment.sh"] command: ["mariadbd"] volumes: - type: bind source: ${DB_DATA_PATH:-./runtime/db} target: /var/lib/mysql bind: create_host_path: true - ./db/check-environment.sh:/usr/local/bin/check-environment.sh:ro networks: - data healthcheck: test: ["CMD-SHELL", "healthcheck.sh --connect --innodb_initialized"] interval: 5s timeout: 5s retries: 20 start_period: 10s security_opt: - no-new-privileges:true pids_limit: 300 wordpress: build: context: ./wordpress restart: unless-stopped init: true environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: ${MARIADB_DATABASE:-azionelab} WORDPRESS_DB_USER: ${MARIADB_USER:-azionelab} WORDPRESS_DB_PASSWORD: ${MARIADB_PASSWORD:-replace-with-a-local-password} WORDPRESS_TABLE_PREFIX: ${WORDPRESS_TABLE_PREFIX:-azl_} WORDPRESS_DEBUG: ${WORDPRESS_DEBUG:-0} WP_ENVIRONMENT_TYPE: ${WP_ENVIRONMENT_TYPE:-local} WP_URL: ${WP_URL:-http://azionelab.org:8080} WORDPRESS_CONFIG_EXTRA: | if (!isset($$_SERVER['HTTP_HOST'])) { $$_SERVER['HTTP_HOST'] = parse_url(getenv('WP_URL') ?: 'http://localhost', PHP_URL_HOST); } if (isset($$_SERVER['HTTP_X_FORWARDED_PROTO']) && $$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { $$_SERVER['HTTPS'] = 'on'; } define('DISALLOW_FILE_EDIT', true); define('WP_AUTO_UPDATE_CORE', 'minor'); define('WP_POST_REVISIONS', 10); if (getenv('WP_ENVIRONMENT_TYPE') === 'production') { define('FORCE_SSL_ADMIN', true); define('DISALLOW_FILE_MODS', true); } volumes: - type: bind source: ${WORDPRESS_DATA_PATH:-./runtime/wordpress} target: /var/www/html bind: create_host_path: true networks: - web - data ports: - 8000:80 depends_on: db: condition: service_healthy healthcheck: test: ["CMD", "php", "/usr/local/bin/azionelab-healthcheck.php"] interval: 10s timeout: 5s retries: 20 start_period: 60s security_opt: - no-new-privileges:true pids_limit: 300 proxy: build: context: ./nginx restart: unless-stopped init: true environment: LETSENCRYPT_ENABLED: ${LETSENCRYPT_ENABLED:-0} LETSENCRYPT_DOMAIN: ${LETSENCRYPT_DOMAIN:-azionelab.org} TLS_RELOAD_INTERVAL_SECONDS: ${TLS_RELOAD_INTERVAL_SECONDS:-30} TRUST_PROXY_HEADERS: ${TRUST_PROXY_HEADERS:-0} volumes: - type: bind source: ${LETSENCRYPT_DATA_PATH:-./runtime/letsencrypt} target: /etc/letsencrypt read_only: true bind: create_host_path: true - type: bind source: ${CERTBOT_CHALLENGES_PATH:-./runtime/certbot/www} target: /var/www/certbot read_only: true bind: create_host_path: true networks: - web ports: - "${NGINX_BIND_ADDRESS:-127.0.0.1}:${NGINX_HTTP_PORT:-8080}:80" - "${NGINX_BIND_ADDRESS:-127.0.0.1}:${NGINX_HTTPS_PORT:-8443}:443" depends_on: wordpress: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1/nginx-health && wget -q -O /dev/null http://127.0.0.1/wordpress-health || exit 1"] interval: 10s timeout: 5s retries: 20 start_period: 15s security_opt: - no-new-privileges:true pids_limit: 200 certbot: image: certbot/certbot:v5.6.0 restart: unless-stopped init: true read_only: true environment: LETSENCRYPT_DOMAIN: ${LETSENCRYPT_DOMAIN:-azionelab.org} LETSENCRYPT_EMAIL: ${LETSENCRYPT_EMAIL:-} LETSENCRYPT_STAGING: ${LETSENCRYPT_STAGING:-1} LETSENCRYPT_RENEW_INTERVAL_SECONDS: ${LETSENCRYPT_RENEW_INTERVAL_SECONDS:-43200} LETSENCRYPT_RETRY_SECONDS: ${LETSENCRYPT_RETRY_SECONDS:-300} entrypoint: ["/bin/sh", "/opt/certbot/renew.sh"] volumes: - ./certbot/renew.sh:/opt/certbot/renew.sh:ro - type: bind source: ${LETSENCRYPT_DATA_PATH:-./runtime/letsencrypt} target: /etc/letsencrypt bind: create_host_path: true - type: bind source: ${CERTBOT_CHALLENGES_PATH:-./runtime/certbot/www} target: /var/www/certbot bind: create_host_path: true tmpfs: - /tmp - /var/lib/letsencrypt - /var/log/letsencrypt depends_on: proxy: condition: service_healthy deploy: replicas: ${LETSENCRYPT_ENABLED:-0} networks: - acme security_opt: - no-new-privileges:true cap_drop: - ALL pids_limit: 100 wp-cli: image: wordpress:cli-2.12.0-php8.3 init: true user: "33:33" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: ${MARIADB_DATABASE:-azionelab} WORDPRESS_DB_USER: ${MARIADB_USER:-azionelab} WORDPRESS_DB_PASSWORD: ${MARIADB_PASSWORD:-replace-with-a-local-password} WORDPRESS_TABLE_PREFIX: ${WORDPRESS_TABLE_PREFIX:-azl_} WP_URL: ${WP_URL:-http://azionelab.org:8080} WP_TITLE: ${WP_TITLE:-Azione!Lab} WP_ADMIN_USER: ${WP_ADMIN_USER:-azionelab-admin} WP_ADMIN_PASSWORD: ${WP_ADMIN_PASSWORD:-replace-with-a-local-admin-password} WP_ADMIN_EMAIL: ${WP_ADMIN_EMAIL:-admin@example.org} WP_ENVIRONMENT_TYPE: ${WP_ENVIRONMENT_TYPE:-local} HOME: /tmp HTTP_HOST: ${LETSENCRYPT_DOMAIN:-azionelab.org} entrypoint: ["/bin/sh"] command: ["/scripts/bootstrap.sh"] volumes: - type: bind source: ${WORDPRESS_DATA_PATH:-./runtime/wordpress} target: /var/www/html bind: create_host_path: true - ./wp-cli/bootstrap.sh:/scripts/bootstrap.sh:ro networks: - data depends_on: db: condition: service_healthy wordpress: condition: service_healthy profiles: ["tools"] security_opt: - no-new-privileges:true cap_drop: - ALL pids_limit: 100 networks: web: data: internal: true acme: