diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..1a747a38b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +.git +.github/workflows +.idea +.vscode +node_modules +vendor +storage/logs/* +storage/framework/cache/* +storage/framework/sessions/* +storage/framework/views/* +bootstrap/cache/* +.phpunit.result.cache +.env +.env.* +!.env.example +*.md +docker-compose*.yml +tests +.php-cs-fixer.cache diff --git a/.github/docker/default.conf b/.github/docker/default.conf new file mode 100644 index 000000000..a622dc5d2 --- /dev/null +++ b/.github/docker/default.conf @@ -0,0 +1,34 @@ +server { + listen 80; + listen [::]:80; + server_name _; + root /app/public; + + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-Content-Type-Options "nosniff"; + + index index.php; + + charset utf-8; + + location / { + try_files $uri $uri/ /index.php?$query_string; + } + + location = /favicon.ico { access_log off; log_not_found off; } + location = /robots.txt { access_log off; log_not_found off; } + + error_page 404 /index.php; + + location ~ \.php$ { + fastcgi_pass 127.0.0.1:9000; + fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; + include fastcgi_params; + fastcgi_hide_header X-Powered-By; + fastcgi_read_timeout 300; + } + + location ~ /\.(?!well-known).* { + deny all; + } +} diff --git a/.github/docker/entrypoint.sh b/.github/docker/entrypoint.sh new file mode 100644 index 000000000..282a38b5c --- /dev/null +++ b/.github/docker/entrypoint.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e +cd /app + +# Writable paths for Laravel (esp. when bind-mounting storage from host) +chown -R nginx:nginx storage bootstrap/cache 2>/dev/null || true +chmod -R ug+rwx storage bootstrap/cache 2>/dev/null || true + +exec "$@" diff --git a/.github/docker/supervisord.conf b/.github/docker/supervisord.conf new file mode 100644 index 000000000..33756879e --- /dev/null +++ b/.github/docker/supervisord.conf @@ -0,0 +1,33 @@ +[supervisord] +nodaemon=true +user=root +logfile=/dev/null +logfile_maxbytes=0 +pidfile=/run/supervisord.pid + +[program:php-fpm] +command=php-fpm -F +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +priority=5 + +[program:nginx] +command=nginx -g 'daemon off;' +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +priority=10 + +[program:crond] +command=crond -f -l 2 +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 +autorestart=true +priority=15 diff --git a/.github/docker/www.conf b/.github/docker/www.conf new file mode 100644 index 000000000..9a61b9a56 --- /dev/null +++ b/.github/docker/www.conf @@ -0,0 +1,22 @@ +[global] +daemonize = no +error_log = /proc/self/fd/2 +log_limit = 8192 + +[www] +user = nginx +group = nginx +listen = 127.0.0.1:9000 +listen.owner = nginx +listen.group = nginx +pm = dynamic +pm.max_children = 20 +pm.start_servers = 2 +pm.min_spare_servers = 1 +pm.max_spare_servers = 3 +clear_env = no +catch_workers_output = yes +decorate_workers_output = no + +php_admin_value[error_log] = /proc/self/fd/2 +php_admin_flag[log_errors] = on diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..488efaa15 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,109 @@ +# Production-style stack: build the app image from ./Dockerfile, MariaDB, Redis. +# Copy .env.example to .env (or set env_file) and run: docker compose up -d +# First boot: docker compose exec app php artisan key:generate --force +# docker compose exec app php artisan migrate --force + +services: + app: + build: + context: . + dockerfile: Dockerfile + image: paymenter:local + restart: unless-stopped + ports: + - "${APP_PORT:-8080}:80" + env_file: + - path: .env + required: false + environment: + APP_ENV: production + APP_DEBUG: "false" + APP_URL: ${APP_URL:-http://localhost:8080} + DB_CONNECTION: mariadb + DB_HOST: db + DB_PORT: 3306 + DB_DATABASE: ${DB_DATABASE:-paymenter} + DB_USERNAME: ${DB_USERNAME:-paymenter} + DB_PASSWORD: ${DB_PASSWORD:-changeme} + CACHE_STORE: redis + SESSION_DRIVER: redis + QUEUE_CONNECTION: redis + REDIS_HOST: redis + REDIS_PORT: 6379 + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + volumes: + - paymenter_storage:/app/storage/app + - paymenter_logs:/app/storage/logs + networks: + - paymenter + + queue: + image: paymenter:local + restart: unless-stopped + command: ["php", "/app/artisan", "queue:work", "--sleep=3", "--tries=3"] + env_file: + - path: .env + required: false + environment: + APP_ENV: production + DB_CONNECTION: mariadb + DB_HOST: db + DB_PORT: 3306 + DB_DATABASE: ${DB_DATABASE:-paymenter} + DB_USERNAME: ${DB_USERNAME:-paymenter} + DB_PASSWORD: ${DB_PASSWORD:-changeme} + CACHE_STORE: redis + QUEUE_CONNECTION: redis + REDIS_HOST: redis + REDIS_PORT: 6379 + depends_on: + - app + - db + - redis + volumes: + - paymenter_storage:/app/storage/app + - paymenter_logs:/app/storage/logs + networks: + - paymenter + + db: + image: mariadb:11 + restart: unless-stopped + environment: + MYSQL_DATABASE: ${DB_DATABASE:-paymenter} + MYSQL_USER: ${DB_USERNAME:-paymenter} + MYSQL_PASSWORD: ${DB_PASSWORD:-changeme} + MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-rootchangeme} + volumes: + - paymenter_db_data:/var/lib/mysql + command: ["--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"] + healthcheck: + test: ["CMD", "mariadb-admin", "ping", "-h", "localhost", "--silent"] + interval: 5s + timeout: 5s + retries: 30 + start_period: 20s + networks: + - paymenter + + redis: + image: redis:alpine + restart: unless-stopped + volumes: + - paymenter_redis_data:/data + networks: + - paymenter + +networks: + paymenter: + driver: bridge + +volumes: + paymenter_db_data: + paymenter_redis_data: + paymenter_storage: + paymenter_logs: