wip: FrankenPHP container setup (Octane + Supervisor)

Dockerfile from hostuk (FrankenPHP 1-php8.5), stripped scorer binary.
Supervisor config simplified for lthn.io (no horizon/reverb).
Octane + Predis installed. docker-compose.yml with Traefik labels,
host.docker.internal for daemon/wallet/LNS access, file cache.

TODO: Fix view namespace resolution inside container (localhost
doesn't match Lethean $domains). Need to add localhost to Lethean
$domains or test with proper Host header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude 2026-04-04 10:54:20 +01:00
parent 9286f84020
commit 5d38d09c3a
No known key found for this signature in database
GPG key ID: AF404715446AEB41
5 changed files with 349 additions and 48 deletions

View file

@ -36,19 +36,17 @@ COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Copy pre-built application (vendor + node_modules/public built on host)
COPY --chown=www-data:www-data --chmod=755 . .
# Clear stale caches from build context
# Clear stale caches and fix permissions
RUN rm -rf bootstrap/cache/*.php \
storage/framework/cache/data/* \
storage/framework/sessions/* \
storage/framework/views/*
storage/framework/views/* \
&& chmod -R 777 storage bootstrap/cache
# Optimise autoloader + discover packages
RUN composer dump-autoload --optimize \
&& php artisan package:discover --ansi
# Scorer binary (EaaS content scoring — no HTTP server needed)
COPY --chmod=755 bin/scorer /usr/local/bin/scorer
# Runtime scripts
COPY --chmod=755 utils/scripts/redis-entrypoint.sh /usr/local/bin/redis-entrypoint.sh
COPY --chmod=755 utils/scripts/laravel-entrypoint.sh /usr/local/bin/laravel-entrypoint.sh

View file

@ -15,8 +15,10 @@
"php": "^8.4",
"guzzlehttp/guzzle": "^7.9",
"laravel/framework": "^12.0",
"laravel/octane": "^2.17",
"laravel/pennant": "^1.23",
"livewire/livewire": "^4.2"
"livewire/livewire": "^4.2",
"predis/predis": "^3.4"
},
"require-dev": {
"larastan/larastan": "^3.0",

329
composer.lock generated
View file

@ -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": "bba8f005feba947387d7719ec55fc7dc",
"content-hash": "0c4002658f386c7fcaf38cece94ea724",
"packages": [
{
"name": "brick/math",
@ -1053,6 +1053,94 @@
],
"time": "2025-08-22T14:27:06+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.56.0",
@ -1275,6 +1363,95 @@
},
"time": "2026-03-26T14:51:54+00:00"
},
{
"name": "laravel/octane",
"version": "v2.17.1",
"source": {
"type": "git",
"url": "https://github.com/laravel/octane.git",
"reference": "eb6150b9aa30956e3a2c04dfebf3a03c5d963a3a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/octane/zipball/eb6150b9aa30956e3a2c04dfebf3a03c5d963a3a",
"reference": "eb6150b9aa30956e3a2c04dfebf3a03c5d963a3a",
"shasum": ""
},
"require": {
"laminas/laminas-diactoros": "^3.0",
"laravel/framework": "^10.10.1|^11.0|^12.0|^13.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|^8.0",
"symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0|^8.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",
"nunomaduro/collision": "^6.4.0|^7.5.2|^8.0",
"orchestra/testbench": "^8.21|^9.0|^10.0|^11.0",
"phpstan/phpstan": "^2.1.7",
"phpunit/phpunit": "^10.4|^11.5|^12.0|^13.0",
"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-18T14:14:24+00:00"
},
{
"name": "laravel/pennant",
"version": "v1.23.0",
@ -2634,6 +2811,69 @@
],
"time": "2025-12-27T19:41:33+00:00"
},
{
"name": "predis/predis",
"version": "v3.4.2",
"source": {
"type": "git",
"url": "https://github.com/predis/predis.git",
"reference": "2033429520d8997a7815a2485f56abe6d2d0e075"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/predis/predis/zipball/2033429520d8997a7815a2485f56abe6d2d0e075",
"reference": "2033429520d8997a7815a2485f56abe6d2d0e075",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0",
"psr/http-message": "^1.0|^2.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.3",
"phpstan/phpstan": "^1.9",
"phpunit/phpcov": "^6.0 || ^8.0",
"phpunit/phpunit": "^8.0 || ~9.4.4"
},
"suggest": {
"ext-relay": "Faster connection with in-memory caching (>=0.6.2)"
},
"type": "library",
"autoload": {
"psr-4": {
"Predis\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Till Krüss",
"homepage": "https://till.im",
"role": "Maintainer"
}
],
"description": "A flexible and feature-complete Redis/Valkey client for PHP.",
"homepage": "http://github.com/predis/predis",
"keywords": [
"nosql",
"predis",
"redis"
],
"support": {
"issues": "https://github.com/predis/predis/issues",
"source": "https://github.com/predis/predis/tree/v3.4.2"
},
"funding": [
{
"url": "https://github.com/sponsors/tillkruss",
"type": "github"
}
],
"time": "2026-03-09T20:33:04+00:00"
},
{
"name": "psr/clock",
"version": "1.0.0",
@ -5134,6 +5374,93 @@
],
"time": "2026-03-24T13:12:05+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
"version": "v8.0.8",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
"reference": "94facc221260c1d5f20e31ee43cd6c6a824b4a19"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/94facc221260c1d5f20e31ee43cd6c6a824b4a19",
"reference": "94facc221260c1d5f20e31ee43cd6c6a824b4a19",
"shasum": ""
},
"require": {
"php": ">=8.4",
"psr/http-message": "^1.0|^2.0",
"symfony/http-foundation": "^7.4|^8.0"
},
"conflict": {
"php-http/discovery": "<1.15"
},
"require-dev": {
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3",
"symfony/browser-kit": "^7.4|^8.0",
"symfony/config": "^7.4|^8.0",
"symfony/event-dispatcher": "^7.4|^8.0",
"symfony/framework-bundle": "^7.4|^8.0",
"symfony/http-kernel": "^7.4|^8.0",
"symfony/runtime": "^7.4|^8.0"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\PsrHttpMessage\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "PSR HTTP message bridge",
"homepage": "https://symfony.com",
"keywords": [
"http",
"http-message",
"psr-17",
"psr-7"
],
"support": {
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.0.8"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2026-03-30T15:14:47+00:00"
},
{
"name": "symfony/routing",
"version": "v7.4.8",

View file

@ -16,11 +16,10 @@ services:
APP_ENV: production
APP_DEBUG: "false"
OCTANE_SERVER: frankenphp
QUEUE_CONNECTION: redis
CACHE_STORE: redis
SESSION_DRIVER: redis
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
CACHE_STORE: file
SESSION_DRIVER: file
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- ./.env:/app/.env:ro
labels:

View file

@ -1,6 +1,5 @@
# Production supervisord config for Host Hub
# Note: supervisord runs as root to manage processes and bind port 80.
# Child processes (horizon, scheduler) run as 'nobody' for security.
# lthn.io supervisord config
# FrankenPHP Octane + Redis (cache/session)
[supervisord]
nodaemon=true
@ -9,6 +8,12 @@ logfile=/dev/null
logfile_maxbytes=0
pidfile=/run/supervisord.pid
[unix_http_server]
file=/var/run/supervisor.sock
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock
[program:redis-setup]
command=/usr/local/bin/redis-entrypoint.sh
autostart=true
@ -32,50 +37,20 @@ stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:octane]
command=sh -c 'php artisan octane:start --server=frankenphp --host=0.0.0.0 --port=${OCTANE_PORT:-80} --admin-port=2019'
directory=/app
command=php /app/artisan octane:frankenphp --host=0.0.0.0 --port=%(ENV_OCTANE_PORT)s --workers=4 --max-requests=500
autostart=true
autorestart=true
startsecs=5
priority=10
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:horizon]
command=php artisan horizon
directory=/app
autostart=true
autorestart=true
startsecs=5
priority=15
user=nobody
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:scheduler]
command=sh -c "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done"
directory=/app
command=/bin/sh -c "while true; do php /app/artisan schedule:run --no-interaction >> /dev/null 2>&1; sleep 60; done"
autostart=true
autorestart=true
startsecs=0
priority=20
user=nobody
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:reverb]
command=php artisan reverb:start --host=0.0.0.0 --port=8080
directory=/app
autostart=true
autorestart=true
startsecs=5
priority=25
priority=15
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr