diff --git a/Dockerfile.all-in-one b/Dockerfile.all-in-one index 45b18a531b..880e31f126 100644 --- a/Dockerfile.all-in-one +++ b/Dockerfile.all-in-one @@ -1,57 +1,77 @@ +# --- Stage 1: Build the Frontend --- FROM node:22-alpine AS node-frontend - WORKDIR /app/frontend - RUN apk add --no-cache yarn # Increase network timeout for slow ARM emulation builds RUN yarn config set network-timeout 600000 -COPY ./frontend/package.json ./frontend/yarn.lock ./ +# Build-time args for Vite (baked into the JS bundle — not runtime secrets) +# VITE_STRIPE_PUBLISHABLE_KEY is the client-side Stripe key; it is intentionally public +ARG VITE_FRONTEND_URL="http://localhost:5678" +ARG VITE_API_URL_CLIENT="http://localhost:8080/api" +ARG VITE_API_URL_SERVER="http://localhost:8000/api" +ARG VITE_STRIPE_PUBLISHABLE_KEY="" +ARG VITE_APP_NAME="Hi.Events" + +# hadolint ignore=DL3044 +ENV VITE_FRONTEND_URL=$VITE_FRONTEND_URL \ + VITE_API_URL_CLIENT=$VITE_API_URL_CLIENT \ + VITE_API_URL_SERVER=$VITE_API_URL_SERVER \ + VITE_STRIPE_PUBLISHABLE_KEY=$VITE_STRIPE_PUBLISHABLE_KEY \ + VITE_APP_NAME=$VITE_APP_NAME +COPY ./frontend/package.json ./frontend/yarn.lock ./ COPY ./frontend . COPY ./VERSION /app/VERSION - RUN yarn install --network-timeout 600000 --frozen-lockfile && yarn build -# Use stable multi-arch serversideup/php image -FROM serversideup/php:8.3-fpm-alpine - -ENV PHP_OPCACHE_ENABLE=1 +# --- Stage 2: Build the Backend with FrankenPHP --- +FROM dunglas/frankenphp:php8.3-alpine -# Switch to root for installing extensions and packages -USER root +ENV SERVER_NAME=":8000" +ENV LARAVEL_OCTANE=1 +ENV APP_ENV="production" -RUN install-php-extensions intl - -RUN apk add --no-cache nodejs yarn nginx supervisor dos2unix +WORKDIR /app -COPY --from=node-frontend /app/frontend /app/frontend +# Install PHP extensions +RUN set -ex \ + && apk add --no-cache php83-pdo_pgsql php83-pgsql php83-redis php83-pcntl php83-bcmath php83-zip php83-intl php83-opcache curl supervisor \ + && install-php-extensions gd redis pdo_pgsql sodium curl intl mbstring xml zip bcmath pcntl imagick opcache +# Copy Backend COPY ./backend /app/backend COPY ./VERSION /app/backend/VERSION -RUN mkdir -p /app/backend/bootstrap/cache \ - && mkdir -p /app/backend/storage \ - && chown -R www-data:www-data /app/backend \ - && find /app/backend -type d -exec chmod 755 {} \; \ - && find /app/backend -type f -exec chmod 644 {} \; \ - && chmod -R 755 /app/backend/storage /app/backend/bootstrap/cache \ - && composer install --working-dir=/app/backend \ - --ignore-platform-reqs \ - --no-interaction \ - --no-dev \ - --optimize-autoloader \ - --prefer-dist \ - && chmod -R 755 /app/backend/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer - -COPY ./docker/all-in-one/nginx/nginx.conf /etc/nginx/nginx.conf -COPY ./docker/all-in-one/supervisor/supervisord.conf /etc/supervisord.conf - -COPY ./docker/all-in-one/scripts/startup.sh /startup.sh -RUN dos2unix /startup.sh && chmod +x /startup.sh - -EXPOSE 80 -WORKDIR /app +# Setup Directories and Permissions +RUN chmod -R 775 /app/backend/storage \ + && mkdir -p /app/backend/bootstrap/cache \ + && chmod -R 775 /app/backend/bootstrap/cache \ + && chown -R root:root /app/backend/storage /app/backend/bootstrap/cache + +# Install Composer Dependencies +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer +RUN cd /app/backend \ + && composer install --no-interaction --no-dev --optimize-autoloader --prefer-dist + +RUN mkdir -p /app/backend/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ + && chmod -R 775 /app/backend/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ + && chown -R root:root /app/backend/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer + +# --- Stage 3: Combine Frontend, Supervisor, and Caddyfile --- +COPY --from=node-frontend /app/frontend/dist /app/frontend/dist + +# Publish the FrankenPHP worker file (APP_KEY is only needed to bootstrap the app during install) +RUN cd /app/backend && APP_KEY="base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" php artisan octane:install --server=frankenphp --no-interaction + +# Setup Supervisor and Startup Scripts +COPY ./docker/all-in-one/supervisord.conf /etc/supervisord.conf +COPY ./docker/all-in-one/Caddyfile /etc/caddy/Caddyfile +COPY ./docker/all-in-one/startup.sh /startup.sh + +RUN sed -i 's/\r$//' /startup.sh && chmod +x /startup.sh + +EXPOSE 8000 CMD ["/startup.sh"] diff --git a/backend/Dockerfile b/backend/Dockerfile index 609a307da2..10ef4a0714 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,34 +1,27 @@ -FROM serversideup/php:8.4-fpm-nginx-alpine +FROM dunglas/frankenphp:php8.3-alpine -ENV PHP_OPCACHE_ENABLE=1 +ENV SERVER_NAME=":8000" +ENV LARAVEL_OCTANE=1 -USER root +WORKDIR /app -# Set `www-data` as the user to start FPM -RUN echo "" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf && \ - echo "user = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf && \ - echo "group = www-data" >> /usr/local/etc/php-fpm.d/docker-php-serversideup-pool.conf +# Install PHP extensions via FrankenPHP's extension installer (not apk php83-* packages, +# which target the system PHP rather than FrankenPHP's embedded PHP). +RUN apk add --no-cache curl \ + && install-php-extensions gd redis pdo_pgsql sodium intl mbstring xml zip bcmath pcntl imagick opcache -RUN install-php-extensions intl imagick +COPY --from=composer:2 /usr/bin/composer /usr/local/bin/composer -COPY --chown=www-data:www-data . . +COPY . /app -RUN chmod -R 755 storage \ - && mkdir -p bootstrap/cache \ - && chmod -R 775 bootstrap/cache \ - && mkdir -p /var/lib/nginx/tmp \ - && chown -R www-data:www-data /var/lib/nginx \ - && chmod -R 755 /var/lib/nginx +RUN mkdir -p storage bootstrap/cache \ + && chmod -R 775 storage bootstrap/cache \ + && chown -R root:root storage bootstrap/cache -RUN composer install \ - --ignore-platform-reqs \ - --no-interaction \ - --no-dev \ - --optimize-autoloader \ - --prefer-dist +RUN composer install --no-interaction --no-dev --optimize-autoloader --prefer-dist \ + && mkdir -p /app/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ + && chmod -R 775 /app/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ + && chown -R root:root /app/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer -RUN mkdir -p /var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ - && chmod -R 775 /var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer \ - && chown -R www-data:www-data /var/www/html/vendor/ezyang/htmlpurifier/library/HTMLPurifier/DefinitionCache/Serializer - -EXPOSE 8080 +EXPOSE 8000 +CMD ["php", "artisan", "octane:start", "--server=frankenphp", "--host=0.0.0.0", "--port=8000"] diff --git a/backend/Dockerfile.dev b/backend/Dockerfile.dev index e4f9153f54..b51eb8bcb9 100644 --- a/backend/Dockerfile.dev +++ b/backend/Dockerfile.dev @@ -1,19 +1,14 @@ -FROM serversideup/php:8.4-fpm-nginx-alpine +FROM dunglas/frankenphp:php8.3-alpine -ENV PHP_OPCACHE_ENABLE=1 -ENV NGINX_WEBROOT=/var/www/html/public +ENV SERVER_NAME=":8000" +ENV LARAVEL_OCTANE=1 -WORKDIR /var/www/html +WORKDIR /app -RUN mkdir -p /var/www/html/storage /var/www/html/bootstrap/cache \ - && chown -R www-data:www-data /var/www/html +# Install PHP extensions via FrankenPHP's extension installer (not apk php83-* packages, +# which target the system PHP rather than FrankenPHP's embedded PHP). +RUN apk add --no-cache curl \ + && install-php-extensions gd redis pdo_pgsql sodium intl mbstring xml zip bcmath pcntl imagick opcache -COPY --chown=www-data:www-data . /var/www/html - -# Switch to root user to install PHP extensions -USER root -RUN install-php-extensions intl imagick -USER www-data - -RUN chmod -R 755 /var/www/html/storage \ - && chmod -R 775 /var/www/html/bootstrap/cache +EXPOSE 8000 +CMD ["php", "artisan", "octane:start", "--server=frankenphp", "--host=0.0.0.0", "--port=8000", "--watch"] diff --git a/backend/app/Providers/RouteServiceProvider.php b/backend/app/Providers/RouteServiceProvider.php index 2133f283b7..3c45e03755 100644 --- a/backend/app/Providers/RouteServiceProvider.php +++ b/backend/app/Providers/RouteServiceProvider.php @@ -39,6 +39,7 @@ public function boot(): void $this->routes(function () { Route::middleware('api') + ->prefix('api') ->group(base_path('routes/api.php')); Route::middleware('web') diff --git a/backend/composer.json b/backend/composer.json index e9768d531c..d49a8d0c95 100644 --- a/backend/composer.json +++ b/backend/composer.json @@ -4,7 +4,7 @@ "description": "hi.events - Ticket selling and event management.", "keywords": ["ticketing", "events"], "license": "AGPL-3.0", - "version": "1.8.0-beta", + "version": "v1.7.1-beta", "require": { "php": "^8.2", "ext-intl": "*", @@ -16,6 +16,7 @@ "guzzlehttp/guzzle": "^7.2", "lab404/laravel-impersonate": "^1.7", "laravel/framework": "^12.0", + "laravel/octane": "^2.15", "laravel/sanctum": "^4.0", "laravel/tinker": "^2.8", "laravel/vapor-core": "^2.37", diff --git a/backend/composer.lock b/backend/composer.lock index 7e0b6a083d..964b7caa48 100644 --- a/backend/composer.lock +++ b/backend/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7649da1e3e0f8fad888953eb259e42b7", + "content-hash": "f3342cc20c70407dad152758d127199d", "packages": [ { "name": "amphp/amp", @@ -3140,6 +3140,94 @@ }, "time": "2025-02-24T16:18:38+00:00" }, + { + "name": "laminas/laminas-diactoros", + "version": "3.8.0", + "source": { + "type": "git", + "url": "https://github.com/laminas/laminas-diactoros.git", + "reference": "60c182916b2749480895601649563970f3f12ec4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/60c182916b2749480895601649563970f3f12ec4", + "reference": "60c182916b2749480895601649563970f3f12ec4", + "shasum": "" + }, + "require": { + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0" + }, + "conflict": { + "amphp/amp": "<2.6.4" + }, + "provide": { + "psr/http-factory-implementation": "^1.0", + "psr/http-message-implementation": "^1.1 || ^2.0" + }, + "require-dev": { + "ext-curl": "*", + "ext-dom": "*", + "ext-gd": "*", + "ext-libxml": "*", + "http-interop/http-factory-tests": "^2.2.0", + "laminas/laminas-coding-standard": "~3.1.0", + "php-http/psr7-integration-tests": "^1.4.0", + "phpunit/phpunit": "^10.5.36", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.13" + }, + "type": "library", + "extra": { + "laminas": { + "module": "Laminas\\Diactoros", + "config-provider": "Laminas\\Diactoros\\ConfigProvider" + } + }, + "autoload": { + "files": [ + "src/functions/create_uploaded_file.php", + "src/functions/marshal_headers_from_sapi.php", + "src/functions/marshal_method_from_sapi.php", + "src/functions/marshal_protocol_version_from_sapi.php", + "src/functions/normalize_server.php", + "src/functions/normalize_uploaded_files.php", + "src/functions/parse_cookie_header.php" + ], + "psr-4": { + "Laminas\\Diactoros\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "PSR HTTP Message implementations", + "homepage": "https://laminas.dev", + "keywords": [ + "http", + "laminas", + "psr", + "psr-17", + "psr-7" + ], + "support": { + "chat": "https://laminas.dev/chat", + "docs": "https://docs.laminas.dev/laminas-diactoros/", + "forum": "https://discourse.laminas.dev", + "issues": "https://github.com/laminas/laminas-diactoros/issues", + "rss": "https://github.com/laminas/laminas-diactoros/releases.atom", + "source": "https://github.com/laminas/laminas-diactoros" + }, + "funding": [ + { + "url": "https://funding.communitybridge.org/projects/laminas-project", + "type": "community_bridge" + } + ], + "time": "2025-10-12T15:31:36+00:00" + }, { "name": "laravel/framework", "version": "v12.34.0", @@ -3359,6 +3447,96 @@ }, "time": "2025-10-14T13:58:31+00:00" }, + { + "name": "laravel/octane", + "version": "v2.15.0", + "source": { + "type": "git", + "url": "https://github.com/laravel/octane.git", + "reference": "37b6175920bde50584ee4e2fa30ce4ae0f11ae36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/octane/zipball/37b6175920bde50584ee4e2fa30ce4ae0f11ae36", + "reference": "37b6175920bde50584ee4e2fa30ce4ae0f11ae36", + "shasum": "" + }, + "require": { + "laminas/laminas-diactoros": "^3.0", + "laravel/framework": "^10.10.1|^11.0|^12.0", + "laravel/prompts": "^0.1.24|^0.2.0|^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "nesbot/carbon": "^2.66.0|^3.0", + "php": "^8.1.0", + "symfony/console": "^6.0|^7.0", + "symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0" + }, + "conflict": { + "spiral/roadrunner": "<2023.1.0", + "spiral/roadrunner-cli": "<2.6.0", + "spiral/roadrunner-http": "<3.3.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.6.1", + "inertiajs/inertia-laravel": "^1.3.2|^2.0", + "laravel/scout": "^10.2.1", + "laravel/socialite": "^5.6.1", + "livewire/livewire": "^2.12.3|^3.0", + "mockery/mockery": "^1.5.1", + "nunomaduro/collision": "^6.4.0|^7.5.2|^8.0", + "orchestra/testbench": "^8.21|^9.0|^10.0", + "phpstan/phpstan": "^2.1.7", + "phpunit/phpunit": "^10.4|^11.5", + "spiral/roadrunner-cli": "^2.6.0", + "spiral/roadrunner-http": "^3.3.0" + }, + "bin": [ + "bin/roadrunner-worker", + "bin/swoole-server" + ], + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Octane": "Laravel\\Octane\\Facades\\Octane" + }, + "providers": [ + "Laravel\\Octane\\OctaneServiceProvider" + ] + }, + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Octane\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Supercharge your Laravel application's performance.", + "keywords": [ + "frankenphp", + "laravel", + "octane", + "roadrunner", + "swoole" + ], + "support": { + "issues": "https://github.com/laravel/octane/issues", + "source": "https://github.com/laravel/octane" + }, + "time": "2026-03-10T14:27:22+00:00" + }, { "name": "laravel/prompts", "version": "v0.3.7", @@ -13702,5 +13880,5 @@ "ext-xmlwriter": "*" }, "platform-dev": {}, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/backend/config/octane.php b/backend/config/octane.php new file mode 100644 index 0000000000..f5d7547651 --- /dev/null +++ b/backend/config/octane.php @@ -0,0 +1,228 @@ + env('OCTANE_SERVER', 'frankenphp'), + + /* + |-------------------------------------------------------------------------- + | Force HTTPS + |-------------------------------------------------------------------------- + | + | When this configuration value is set to "true", Octane will inform the + | framework that all absolute links must be generated using the HTTPS + | protocol. Otherwise your links may be generated using plain HTTP. + | + */ + + 'https' => env('OCTANE_HTTPS', false), + + /* + |-------------------------------------------------------------------------- + | Octane Listeners + |-------------------------------------------------------------------------- + | + | All of the event listeners for Octane's events are defined below. These + | listeners are responsible for resetting your application's state for + | the next request. You may even add your own listeners to the list. + | + */ + + 'listeners' => [ + WorkerStarting::class => [ + EnsureUploadedFilesAreValid::class, + EnsureUploadedFilesCanBeMoved::class, + ], + + RequestReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + ...Octane::prepareApplicationForNextRequest(), + // + ], + + RequestHandled::class => [ + // + ], + + RequestTerminated::class => [ + // FlushUploadedFiles::class, + ], + + TaskReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + // + ], + + TaskTerminated::class => [ + // + ], + + TickReceived::class => [ + ...Octane::prepareApplicationForNextOperation(), + // + ], + + TickTerminated::class => [ + // + ], + + OperationTerminated::class => [ + FlushOnce::class, + FlushTemporaryContainerInstances::class, + // DisconnectFromDatabases::class, + // CollectGarbage::class, + ], + + WorkerErrorOccurred::class => [ + ReportException::class, + StopWorkerIfNecessary::class, + ], + + WorkerStopping::class => [ + CloseMonologHandlers::class, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Warm / Flush Bindings + |-------------------------------------------------------------------------- + | + | The bindings listed below will either be pre-warmed when a worker boots + | or they will be flushed before every new request. Flushing a binding + | will force the container to resolve that binding again when asked. + | + */ + + 'warm' => [ + ...Octane::defaultServicesToWarm(), + ], + + 'flush' => [ + \HiEvents\Services\Infrastructure\Stripe\StripeConfigurationService::class, + \HiEvents\Services\Infrastructure\Stripe\StripeClientFactory::class, + 'tymon.jwt.auth', + 'tymon.jwt.provider.auth', + // + ], + + /* + |-------------------------------------------------------------------------- + | Octane Swoole Tables + |-------------------------------------------------------------------------- + | + | While using Swoole, you may define additional tables as required by the + | application. These tables can be used to store data that needs to be + | quickly accessed by other workers on the particular Swoole server. + | + */ + + 'tables' => [ + 'example:1000' => [ + 'name' => 'string:1000', + 'votes' => 'int', + ], + ], + + /* + |-------------------------------------------------------------------------- + | Octane Swoole Cache Table + |-------------------------------------------------------------------------- + | + | While using Swoole, you may leverage the Octane cache, which is powered + | by a Swoole table. You may set the maximum number of rows as well as + | the number of bytes per row using the configuration options below. + | + */ + + 'cache' => [ + 'rows' => 1000, + 'bytes' => 10000, + ], + + /* + |-------------------------------------------------------------------------- + | File Watching + |-------------------------------------------------------------------------- + | + | The following list of files and directories will be watched when using + | the --watch option offered by Octane. If any of the directories and + | files are changed, Octane will automatically reload your workers. + | + */ + + 'watch' => [ + 'app', + 'bootstrap', + 'config/**/*.php', + 'database/**/*.php', + 'public/**/*.php', + 'resources/**/*.php', + 'routes', + 'composer.lock', + '.env', + ], + + /* + |-------------------------------------------------------------------------- + | Garbage Collection Threshold + |-------------------------------------------------------------------------- + | + | When executing long-lived PHP scripts such as Octane, memory can build + | up before being cleared by PHP. You can force Octane to run garbage + | collection if your application consumes this amount of megabytes. + | + */ + + 'garbage' => 50, + + /* + |-------------------------------------------------------------------------- + | Maximum Execution Time + |-------------------------------------------------------------------------- + | + | The following setting configures the maximum execution time for requests + | being handled by Octane. You may set this value to 0 to indicate that + | there isn't a specific time limit on Octane request execution time. + | + */ + + 'max_execution_time' => 30, + +]; diff --git a/docker/all-in-one/Caddyfile b/docker/all-in-one/Caddyfile new file mode 100644 index 0000000000..265ecb38e4 --- /dev/null +++ b/docker/all-in-one/Caddyfile @@ -0,0 +1,43 @@ +{ + # We load the Octane worker inside the global block + frankenphp { + worker /app/backend/public/frankenphp-worker.php + } +} + +:8000 { + log + + encode zstd br gzip + + # Set root to backend public directory by default + root * /app/backend/public + + # Serve the backend API for API routes or backend-specific requests + @api { + path /api/* /oauth/* /sanctum/* /broadcasting/* + } + php_server @api { + index frankenphp-worker.php + try_files {path} /frankenphp-worker.php + resolve_root_symlink + } + + # Serve uploaded storage files + @storage { + path /storage/* + } + route @storage { + file_server + } + + # Serve the frontend static assets for all other routes + @frontend { + not path /api/* /storage/* /oauth/* /sanctum/* /broadcasting/* + } + route @frontend { + root * /app/frontend/dist/client + try_files {path} /index.html + file_server + } +} diff --git a/docker/all-in-one/README.md b/docker/all-in-one/README.md index cab5878ac9..00fe4e3cd8 100644 --- a/docker/all-in-one/README.md +++ b/docker/all-in-one/README.md @@ -61,7 +61,7 @@ docker compose up -d ### Step 6: Create an Account -Visit [http://localhost:8123/auth/register](http://localhost:8123/auth/register) to create an account. +Visit [http://localhost:8000/auth/register](http://localhost:8000/auth/register) to create an account. --- diff --git a/docker/all-in-one/docker-compose.yml b/docker/all-in-one/docker-compose.yml index 28f912c617..d38ae7b397 100644 --- a/docker/all-in-one/docker-compose.yml +++ b/docker/all-in-one/docker-compose.yml @@ -5,15 +5,18 @@ services: dockerfile: Dockerfile.all-in-one restart: unless-stopped ports: - - "8123:80" + - "8000:8000" environment: + - APP_ENV=${APP_ENV:-production} + - APP_DEBUG=${APP_DEBUG:-false} + - OCTANE_SERVER=frankenphp - VITE_FRONTEND_URL=${VITE_FRONTEND_URL} - VITE_API_URL_CLIENT=${VITE_API_URL_CLIENT} - VITE_API_URL_SERVER=${VITE_API_URL_SERVER} - VITE_STRIPE_PUBLISHABLE_KEY=${VITE_STRIPE_PUBLISHABLE_KEY} - VITE_APP_NAME=${VITE_APP_NAME} - LOG_CHANNEL=${LOG_CHANNEL} - - QUEUE_CONNECTION=${QUEUE_CONNECTION} + - QUEUE_CONNECTION=${QUEUE_CONNECTION:-redis} - APP_KEY=${APP_KEY} - APP_CDN_URL=${APP_CDN_URL} - APP_FRONTEND_URL=${APP_FRONTEND_URL} @@ -43,7 +46,6 @@ services: - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY} - STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET} - WEBHOOK_QUEUE_NAME=webhook-queue - depends_on: postgres: condition: service_healthy diff --git a/docker/all-in-one/nginx/nginx.conf b/docker/all-in-one/nginx/nginx.conf deleted file mode 100644 index 054003df52..0000000000 --- a/docker/all-in-one/nginx/nginx.conf +++ /dev/null @@ -1,62 +0,0 @@ -events {} - -http { - server { - listen 80; - listen [::]:80; - server_name _; - - root /app/backend/public; - - add_header X-XSS-Protection "1; mode=block"; - - index index.html index.htm index.php; - charset utf-8; - - access_log /dev/stdout; - error_log /dev/stderr; - - location /storage { - alias /app/backend/storage/app/public; - access_log off; - expires max; - add_header Cache-Control "public"; - } - - location ^~ /api/ { - rewrite ^/api(/.*)$ /index.php$1 break; - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_param REQUEST_URI $1; - fastcgi_pass localhost:9000; - client_max_body_size 20M; - } - - location ~ \.php$ { - include fastcgi_params; - fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass localhost:9000; - fastcgi_index index.php; - fastcgi_param PHP_VALUE "error_log=/dev/stderr"; - } - - location / { - proxy_pass http://localhost:5678; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - - 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 ~ /\.(?!well-known).* { - deny all; - } - } -} diff --git a/docker/all-in-one/scripts/startup.sh b/docker/all-in-one/startup.sh similarity index 77% rename from docker/all-in-one/scripts/startup.sh rename to docker/all-in-one/startup.sh index 3ab2caadf8..5ea0d0c50c 100644 --- a/docker/all-in-one/scripts/startup.sh +++ b/docker/all-in-one/startup.sh @@ -15,7 +15,8 @@ php artisan route:clear php artisan view:clear php artisan storage:link -chown -R www-data:www-data /app/backend +# Only fix permissions on writable directories (not all of /app/backend which is huge) +chown -R root:root /app/backend/storage /app/backend/bootstrap/cache chmod -R 775 /app/backend/storage /app/backend/bootstrap/cache exec /usr/bin/supervisord -c /etc/supervisord.conf diff --git a/docker/all-in-one/supervisor/supervisord.conf b/docker/all-in-one/supervisor/supervisord.conf deleted file mode 100644 index 0ae6c167c9..0000000000 --- a/docker/all-in-one/supervisor/supervisord.conf +++ /dev/null @@ -1,59 +0,0 @@ -[supervisord] -nodaemon=true -logfile=/dev/stdout -logfile_maxbytes=0 -loglevel=info - -[program:nginx] -command=/usr/sbin/nginx -g "daemon off;" -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -redirect_stderr=true -stdout_logfile_maxbytes = 0 -stderr_logfile_maxbytes = 0 - -[program:php-fpm] -command=/usr/local/sbin/php-fpm -F -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -redirect_stderr=true -stdout_logfile_maxbytes = 0 -stderr_logfile_maxbytes = 0 - -[program:nodejs] -command=yarn start -directory=/app/frontend -autostart=true -autorestart=true -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -redirect_stderr=true -stdout_logfile_maxbytes = 0 -stderr_logfile_maxbytes = 0 -environment=NODE_ENV="production",VITE_API_URL_CLIENT="%(ENV_VITE_API_URL_CLIENT)s",VITE_API_URL_SERVER="http://localhost:80/api",VITE_FRONTEND_URL="%(ENV_VITE_FRONTEND_URL)s",VITE_STRIPE_PUBLISHABLE_KEY="%(ENV_VITE_STRIPE_PUBLISHABLE_KEY)s" - -[program:laravel-queue-worker] -command=php /app/backend/artisan queue:work --queue=default,webhook-queue --sleep=3 --tries=3 --timeout=60 -autostart=true -autorestart=true -user=www-data -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -redirect_stderr=true -stdout_logfile_maxbytes=0 -stderr_logfile_maxbytes=0 - -[program:laravel-scheduler] -command=/bin/sh -c "while true; do php /app/backend/artisan schedule:run --no-interaction; sleep 60; done" -autostart=true -autorestart=true -user=www-data -stdout_logfile=/dev/stdout -stderr_logfile=/dev/stderr -redirect_stderr=true -stdout_logfile_maxbytes=0 -stderr_logfile_maxbytes=0 diff --git a/docker/all-in-one/supervisord.conf b/docker/all-in-one/supervisord.conf new file mode 100644 index 0000000000..5067fb4bc9 --- /dev/null +++ b/docker/all-in-one/supervisord.conf @@ -0,0 +1,26 @@ +[supervisord] +nodaemon=true +logfile=/dev/stdout +logfile_maxbytes=0 +loglevel=info + +[program:frankenphp] +command=php artisan octane:start --server=frankenphp --host=0.0.0.0 --port=8000 --workers=auto --caddyfile=/etc/caddy/Caddyfile +autostart=true +autorestart=true +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +redirect_stderr=true +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 + +[program:laravel-queue-worker] +command=php artisan queue:work --queue=default,webhook-queue --sleep=3 --tries=3 --timeout=60 +autostart=true +autorestart=true +user=root +stdout_logfile=/dev/stdout +stderr_logfile=/dev/stderr +redirect_stderr=true +stdout_logfile_maxbytes=0 +stderr_logfile_maxbytes=0 diff --git a/docker/development/docker-compose.dev.yml b/docker/development/docker-compose.dev.yml index 1c605156cd..f841e31f13 100644 --- a/docker/development/docker-compose.dev.yml +++ b/docker/development/docker-compose.dev.yml @@ -5,12 +5,13 @@ services: dockerfile: Dockerfile.dev container_name: backend ports: - - "1234:80" + - "80:8000" + - "443:443" volumes: - - ./../../backend:/var/www/html - - ./../../backend/storage:/var/www/html/storage - - ./../../backend/bootstrap/cache:/var/www/html/bootstrap/cache - - ./../../VERSION:/var/www/html/VERSION:ro + - ./../../backend:/app + - ./../../backend/storage:/app/storage + - ./../../backend/bootstrap/cache:/app/bootstrap/cache + - ./../../VERSION:/app/VERSION:ro environment: APP_ENV: '${APP_ENV:-local}' APP_KEY: '${APP_KEY}' @@ -37,7 +38,7 @@ services: command: yarn dev:csr environment: - VITE_API_URL_CLIENT: 'http://localhost:${API_PORT:-1234}' + VITE_API_URL_CLIENT: 'http://localhost:${API_PORT:-80}' networks: - app frontend: @@ -63,21 +64,6 @@ services: networks: - app - nginx: - image: nginx:alpine - container_name: nginx - ports: - - "8080:80" - - "8443:443" - volumes: - - ./nginx/nginx.conf:/etc/nginx/nginx.conf - - ./certs:/etc/nginx/certs:ro - depends_on: - - backend - - frontend - networks: - - app - redis: image: 'redis:alpine' ports: @@ -171,7 +157,6 @@ services: /usr/bin/mc anonymous set public myminio/hievents-public; echo 'Buckets created and policies set.'; - exit 0; " networks: - app