diff --git a/.editorconfig b/.editorconfig index 7c159288..8fda640c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,5 +14,5 @@ trim_trailing_whitespace = false [*{.yml,.scss,.js,.json,.css}] indent_size = 2 -[docker-compose.yml] +[docker-compose*.yml] indent_size = 4 diff --git a/app-modules/database-migration/src/Services/SshTunnelService.php b/app-modules/database-migration/src/Services/SshTunnelService.php index 8be4d884..abfedba8 100644 --- a/app-modules/database-migration/src/Services/SshTunnelService.php +++ b/app-modules/database-migration/src/Services/SshTunnelService.php @@ -75,7 +75,6 @@ public function destroy(): bool $this->log('SSH tunnel destroyed successfully'); } - // Nettoyer le fichier temporaire de clé SSH s'il existe $this->cleanupTempKeyFile(); return $result; @@ -95,7 +94,6 @@ private function createTunnel(): void $this->runCommand($command); - // Wait for connection to establish usleep(config('ssh-tunnel.connection.wait_microseconds', 1000000)); $this->log('SSH tunnel creation command executed', ['command' => $command]); @@ -105,7 +103,6 @@ private function buildCommands(): void { $config = config('ssh-tunnel'); - // Build netcat verification command $this->ncCommand = sprintf( '%s -vz %s %d > /dev/null 2>&1', $config['executables']['nc'], @@ -113,7 +110,6 @@ private function buildCommands(): void $config['local']['port'] ); - // Build bash verification command $this->bashCommand = sprintf( 'timeout 1 %s -c \'cat < /dev/null > /dev/tcp/%s/%d\' > /dev/null 2>&1', $config['executables']['bash'], @@ -121,7 +117,6 @@ private function buildCommands(): void $config['local']['port'] ); - // Build SSH tunnel command with identity file handling $identityOption = $this->buildIdentityOption($config); $this->sshCommand = sprintf( @@ -149,27 +144,22 @@ private function runCommand(string $command): bool private function buildIdentityOption(array $config): string { - // Si une clé privée est fournie via variable d'environnement if (! empty($config['ssh']['private_key_content'])) { $tempKeyFile = $this->createTempKeyFile($config['ssh']['private_key_content']); return sprintf('-i %s', $tempKeyFile); } - // Sinon utiliser le fichier d'identité classique return sprintf('-i %s', $config['ssh']['identity_file']); } private function createTempKeyFile(string $keyContent): string { - // Nettoyer et normaliser le contenu de la clé SSH $cleanedKeyContent = $this->normalizeKeyContent($keyContent); - // Utiliser un nom de fichier plus persistant basé sur un hash du contenu $keyHash = hash('sha256', $cleanedKeyContent); $tempFile = sys_get_temp_dir().'/ssh_key_'.substr($keyHash, 0, 16); - // Si le fichier existe déjà avec le même contenu, le réutiliser if (file_exists($tempFile)) { $existingContent = file_get_contents($tempFile); if ($existingContent === $cleanedKeyContent) { @@ -180,19 +170,16 @@ private function createTempKeyFile(string $keyContent): string } } - // Écrire le contenu de la clé dans le fichier temporaire if (file_put_contents($tempFile, $cleanedKeyContent) === false) { throw new SshTunnelException('Unable to write SSH key to temporary file'); } - // Définir les permissions appropriées pour la clé SSH (600) if (chmod($tempFile, 0600) === false) { unlink($tempFile); throw new SshTunnelException('Unable to set proper permissions on SSH key file'); } - // Stocker la référence pour le nettoyage ultérieur $this->tempKeyFile = $tempFile; $this->log('Temporary SSH key file created', ['file' => $tempFile]); @@ -202,13 +189,16 @@ private function createTempKeyFile(string $keyContent): string private function normalizeKeyContent(string $keyContent): string { - // Remplacer les \n littéraux par de vrais retours à la ligne - $normalized = str_replace('\\n', "\n", $keyContent); + if ($this->isBase64Encoded($keyContent)) { + $decoded = base64_decode($keyContent, true); + if ($decoded !== false) { + $keyContent = $decoded; + } + } - // Nettoyer les espaces en début/fin + $normalized = str_replace('\\n', "\n", $keyContent); $normalized = trim($normalized); - // S'assurer que la clé se termine par un retour à la ligne if (! str_ends_with($normalized, "\n")) { $normalized .= "\n"; } @@ -216,6 +206,24 @@ private function normalizeKeyContent(string $keyContent): string return $normalized; } + private function isBase64Encoded(string $data): bool + { + if (in_array(preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $data), [0, false], true)) { + return false; + } + + if (str_contains($data, '-----BEGIN') || str_contains($data, '-----END')) { + return false; + } + + $decoded = base64_decode($data, true); + if ($decoded === false) { + return false; + } + + return str_contains($decoded, '-----BEGIN') && str_contains($decoded, '-----END'); + } + private function cleanupTempKeyFile(): void { if ($this->tempKeyFile !== null && file_exists($this->tempKeyFile)) { diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 89aa9343..e118d49a 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -51,6 +51,9 @@ services: CACHE_PREFIX: ${CACHE_PREFIX} MEMCACHED_HOST: ${MEMCACHED_HOST} REDIS_URL: ${REDIS_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_PORT: ${REDIS_PORT} MAIL_MAILER: ${MAIL_MAILER} MAIL_HOST: ${MAIL_HOST} MAIL_PORT: ${MAIL_PORT} @@ -67,7 +70,7 @@ services: AWS_ENDPOINT: ${AWS_ENDPOINT} AWS_URL: ${AWS_URL} AWS_USE_PATH_STYLE_ENDPOINT: ${AWS_USE_PATH_STYLE_ENDPOINT} - AWS_DIRECTORY: ${AWS_DIRECTORY} + AWS_ROOT: ${AWS_ROOT} VITE_APP_NAME: ${VITE_APP_NAME} OPENAI_API_KEY: ${OPENAI_API_KEY} OPENAI_ORGANIZATION: ${OPENAI_ORGANIZATION} @@ -98,16 +101,18 @@ services: GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} GITHUB_REDIRECT: ${GITHUB_REDIRECT} GITHUB_FINE_GRAINED_TOKEN: ${GITHUB_FINE_GRAINED_TOKEN} + UNSPLASH_ACCESS_KEY: ${UNSPLASH_ACCESS_KEY} NIGHTWATCH_TOKEN: ${NIGHTWATCH_TOKEN} NIGHTWATCH_REQUEST_SAMPLE_RATE: ${NIGHTWATCH_REQUEST_SAMPLE_RATE} SSH_TUNNEL_USER: '${SSH_TUNNEL_USER:-}' SSH_TUNNEL_HOSTNAME: '${SSH_TUNNEL_HOSTNAME:-}' SSH_TUNNEL_PORT: '${SSH_TUNNEL_PORT:-22}' - SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' SSH_TUNNEL_LOCAL_PORT: '${SSH_TUNNEL_LOCAL_PORT:-3307}' SSH_TUNNEL_BIND_ADDRESS: '${SSH_TUNNEL_BIND_ADDRESS:-127.0.0.1}' SSH_TUNNEL_BIND_PORT: '${SSH_TUNNEL_BIND_PORT:-3306}' SSH_TUNNEL_VERIFY_PROCESS: '${SSH_TUNNEL_VERIFY_PROCESS:-bash}' + SSH_TUNNEL_IDENTITY_FILE: '${SSH_TUNNEL_IDENTITY_FILE:-}' + SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' DB_CONNECTION_SECOND: '${DB_CONNECTION_SECOND:-mysql}' DB_HOST_SECOND: '${DB_HOST_SECOND:-127.0.0.1}' DB_PORT_SECOND: '${DB_PORT_SECOND:-3307}' @@ -134,272 +139,282 @@ services: networks: - dokploy-network schedule: - image: laravelcm/php - restart: unless-stopped - command: ['artisan', 'schedule:run'] - stop_signal: SIGTERM - healthcheck: - test: ['CMD', 'healthcheck-schedule'] - start_period: 10s - environment: - APP_NAME: ${APP_NAME} - APP_ENV: ${APP_ENV} - APP_KEY: ${APP_KEY} - APP_DEBUG: ${APP_DEBUG} - APP_DOMAIN: ${APP_DOMAIN} - APP_URL: ${APP_URL} - ASSET_URL: ${ASSET_URL} - APP_TIMEZONE: ${APP_TIMEZONE} - APP_LOCALE: ${APP_LOCALE} - APP_FALLBACK_LOCALE: ${APP_FALLBACK_LOCALE} - APP_MAINTENANCE_DRIVER: ${APP_MAINTENANCE_DRIVER} - BCRYPT_ROUNDS: ${BCRYPT_ROUNDS} - DB_CONNECTION: ${DB_CONNECTION} - DB_HOST: ${DB_HOST} - DB_PORT: ${DB_PORT} - DB_DATABASE: ${DB_DATABASE} - DB_USERNAME: ${DB_USERNAME} - DB_PASSWORD: ${DB_PASSWORD} - LOG_CHANNEL: ${LOG_CHANNEL} - LOG_STACK: ${LOG_STACK} - LOG_DEPRECATIONS_CHANNEL: ${LOG_DEPRECATIONS_CHANNEL} - LOG_LEVEL: ${LOG_LEVEL} - SESSION_DRIVER: ${SESSION_DRIVER} - SESSION_LIFETIME: ${SESSION_LIFETIME} - SESSION_ENCRYPT: ${SESSION_ENCRYPT} - SESSION_PATH: ${SESSION_PATH} - SESSION_DOMAIN: ${SESSION_DOMAIN} - BROADCAST_CONNECTION: ${BROADCAST_CONNECTION} - FILESYSTEM_DISK: ${FILESYSTEM_DISK} - MEDIA_DISK: ${MEDIA_DISK} - FILAMENT_FILESYSTEM_DISK: ${MEDIA_DISK} - FILAMENT_PATH: ${FILAMENT_PATH} - QUEUE_CONNECTION: ${QUEUE_CONNECTION} - CACHE_STORE: ${CACHE_STORE} - CACHE_PREFIX: ${CACHE_PREFIX} - MEMCACHED_HOST: ${MEMCACHED_HOST} - REDIS_URL: ${REDIS_URL} - MAIL_MAILER: ${MAIL_MAILER} - MAIL_HOST: ${MAIL_HOST} - MAIL_PORT: ${MAIL_PORT} - MAIL_USERNAME: ${MAIL_USERNAME} - MAIL_PASSWORD: ${MAIL_PASSWORD} - MAIL_ENCRYPTION: ${MAIL_ENCRYPTION} - MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS} - MAIL_FROM_NAME: ${MAIL_FROM_NAME} - MAIL_SUPPORT: ${MAIL_SUPPORT} - AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} - AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION} - AWS_BUCKET: ${AWS_BUCKET} - AWS_ENDPOINT: ${AWS_ENDPOINT} - AWS_URL: ${AWS_URL} - AWS_USE_PATH_STYLE_ENDPOINT: ${AWS_USE_PATH_STYLE_ENDPOINT} - AWS_DIRECTORY: ${AWS_DIRECTORY} - VITE_APP_NAME: ${VITE_APP_NAME} - OPENAI_API_KEY: ${OPENAI_API_KEY} - OPENAI_ORGANIZATION: ${OPENAI_ORGANIZATION} - OPENAI_PROJECT: ${OPENAI_PROJECT} - ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} - ANTHROPIC_API_VERSION: ${ANTHROPIC_API_VERSION} - OLLAMA_URL: ${OLLAMA_URL} - DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY} - SCOUT_DRIVER: ${SCOUT_DRIVER} - TYPESENSE_HOST: ${TYPESENSE_HOST} - TYPESENSE_PORT: ${TYPESENSE_PORT} - TYPESENSE_PROTOCOL: ${TYPESENSE_PROTOCOL} - TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} - STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} - STRIPE_VERSION: ${STRIPE_VERSION} - NOTCHPAY_PUBLIC_KEY: ${NOTCHPAY_PUBLIC_KEY} - NOTCHPAY_SECRET_KEY: ${NOTCHPAY_SECRET_KEY} - MARKDOWNX_GIPHY_API_KEY: ${MARKDOWNX_GIPHY_API_KEY} - TORCHLIGHT_TOKEN: ${TORCHLIGHT_TOKEN} - TORCHLIGHT_THEME: ${TORCHLIGHT_THEME} - TWITTER_CONSUMER_KEY: ${TWITTER_CONSUMER_KEY} - TWITTER_CONSUMER_SECRET: ${TWITTER_CONSUMER_SECRET} - TWITTER_ACCESS_TOKEN: ${TWITTER_ACCESS_TOKEN} - TWITTER_ACCESS_SECRET: ${TWITTER_ACCESS_SECRET} - TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} - TELEGRAM_CHANNEL: ${TELEGRAM_CHANNEL} - GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} - GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} - GITHUB_REDIRECT: ${GITHUB_REDIRECT} - GITHUB_FINE_GRAINED_TOKEN: ${GITHUB_FINE_GRAINED_TOKEN} - NIGHTWATCH_TOKEN: ${NIGHTWATCH_TOKEN} - NIGHTWATCH_REQUEST_SAMPLE_RATE: ${NIGHTWATCH_REQUEST_SAMPLE_RATE} - SSH_TUNNEL_USER: '${SSH_TUNNEL_USER:-}' - SSH_TUNNEL_HOSTNAME: '${SSH_TUNNEL_HOSTNAME:-}' - SSH_TUNNEL_PORT: '${SSH_TUNNEL_PORT:-22}' - SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' - SSH_TUNNEL_LOCAL_PORT: '${SSH_TUNNEL_LOCAL_PORT:-3307}' - SSH_TUNNEL_BIND_ADDRESS: '${SSH_TUNNEL_BIND_ADDRESS:-127.0.0.1}' - SSH_TUNNEL_BIND_PORT: '${SSH_TUNNEL_BIND_PORT:-3306}' - SSH_TUNNEL_VERIFY_PROCESS: '${SSH_TUNNEL_VERIFY_PROCESS:-bash}' - DB_CONNECTION_SECOND: '${DB_CONNECTION_SECOND:-mysql}' - DB_HOST_SECOND: '${DB_HOST_SECOND:-127.0.0.1}' - DB_PORT_SECOND: '${DB_PORT_SECOND:-3307}' - DB_DATABASE_SECOND: '${DB_DATABASE_SECOND:-}' - DB_USERNAME_SECOND: '${DB_USERNAME_SECOND:-}' - DB_PASSWORD_SECOND: '${DB_PASSWORD_SECOND:-}' - OCTANE_SERVER: 'frankenphp' - CADDY_GLOBAL_OPTIONS: | - servers { - trusted_proxies static private_ranges - } - CADDY_SERVER_EXTRA_DIRECTIVES: | - @static { - file - path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 - } - header @static Cache-Control "public, max-age=31536000, s-maxage=31536000" - FRANKENPHP_CONFIG: | - worker { - file ./public/frankenphp-worker.php - } - volumes: - - storage:/var/www/html/storage - networks: - - dokploy-network - depends_on: - - laravelcm + image: laravelcm/php + restart: unless-stopped + command: ['artisan', 'schedule:run'] + stop_signal: SIGTERM + healthcheck: + test: ['CMD', 'healthcheck-schedule'] + start_period: 10s + environment: + APP_NAME: ${APP_NAME} + APP_ENV: ${APP_ENV} + APP_KEY: ${APP_KEY} + APP_DEBUG: ${APP_DEBUG} + APP_DOMAIN: ${APP_DOMAIN} + APP_URL: ${APP_URL} + ASSET_URL: ${ASSET_URL} + APP_TIMEZONE: ${APP_TIMEZONE} + APP_LOCALE: ${APP_LOCALE} + APP_FALLBACK_LOCALE: ${APP_FALLBACK_LOCALE} + APP_MAINTENANCE_DRIVER: ${APP_MAINTENANCE_DRIVER} + BCRYPT_ROUNDS: ${BCRYPT_ROUNDS} + DB_CONNECTION: ${DB_CONNECTION} + DB_HOST: ${DB_HOST} + DB_PORT: ${DB_PORT} + DB_DATABASE: ${DB_DATABASE} + DB_USERNAME: ${DB_USERNAME} + DB_PASSWORD: ${DB_PASSWORD} + LOG_CHANNEL: ${LOG_CHANNEL} + LOG_STACK: ${LOG_STACK} + LOG_DEPRECATIONS_CHANNEL: ${LOG_DEPRECATIONS_CHANNEL} + LOG_LEVEL: ${LOG_LEVEL} + SESSION_DRIVER: ${SESSION_DRIVER} + SESSION_LIFETIME: ${SESSION_LIFETIME} + SESSION_ENCRYPT: ${SESSION_ENCRYPT} + SESSION_PATH: ${SESSION_PATH} + SESSION_DOMAIN: ${SESSION_DOMAIN} + BROADCAST_CONNECTION: ${BROADCAST_CONNECTION} + FILESYSTEM_DISK: ${FILESYSTEM_DISK} + MEDIA_DISK: ${MEDIA_DISK} + FILAMENT_FILESYSTEM_DISK: ${MEDIA_DISK} + FILAMENT_PATH: ${FILAMENT_PATH} + QUEUE_CONNECTION: ${QUEUE_CONNECTION} + CACHE_STORE: ${CACHE_STORE} + CACHE_PREFIX: ${CACHE_PREFIX} + MEMCACHED_HOST: ${MEMCACHED_HOST} + REDIS_URL: ${REDIS_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_PORT: ${REDIS_PORT} + MAIL_MAILER: ${MAIL_MAILER} + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + MAIL_USERNAME: ${MAIL_USERNAME} + MAIL_PASSWORD: ${MAIL_PASSWORD} + MAIL_ENCRYPTION: ${MAIL_ENCRYPTION} + MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS} + MAIL_FROM_NAME: ${MAIL_FROM_NAME} + MAIL_SUPPORT: ${MAIL_SUPPORT} + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} + AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION} + AWS_BUCKET: ${AWS_BUCKET} + AWS_ENDPOINT: ${AWS_ENDPOINT} + AWS_URL: ${AWS_URL} + AWS_USE_PATH_STYLE_ENDPOINT: ${AWS_USE_PATH_STYLE_ENDPOINT} + AWS_ROOT: ${AWS_ROOT} + VITE_APP_NAME: ${VITE_APP_NAME} + OPENAI_API_KEY: ${OPENAI_API_KEY} + OPENAI_ORGANIZATION: ${OPENAI_ORGANIZATION} + OPENAI_PROJECT: ${OPENAI_PROJECT} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} + ANTHROPIC_API_VERSION: ${ANTHROPIC_API_VERSION} + OLLAMA_URL: ${OLLAMA_URL} + DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY} + SCOUT_DRIVER: ${SCOUT_DRIVER} + TYPESENSE_HOST: ${TYPESENSE_HOST} + TYPESENSE_PORT: ${TYPESENSE_PORT} + TYPESENSE_PROTOCOL: ${TYPESENSE_PROTOCOL} + TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} + STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} + STRIPE_VERSION: ${STRIPE_VERSION} + NOTCHPAY_PUBLIC_KEY: ${NOTCHPAY_PUBLIC_KEY} + NOTCHPAY_SECRET_KEY: ${NOTCHPAY_SECRET_KEY} + MARKDOWNX_GIPHY_API_KEY: ${MARKDOWNX_GIPHY_API_KEY} + TORCHLIGHT_TOKEN: ${TORCHLIGHT_TOKEN} + TORCHLIGHT_THEME: ${TORCHLIGHT_THEME} + TWITTER_CONSUMER_KEY: ${TWITTER_CONSUMER_KEY} + TWITTER_CONSUMER_SECRET: ${TWITTER_CONSUMER_SECRET} + TWITTER_ACCESS_TOKEN: ${TWITTER_ACCESS_TOKEN} + TWITTER_ACCESS_SECRET: ${TWITTER_ACCESS_SECRET} + TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} + TELEGRAM_CHANNEL: ${TELEGRAM_CHANNEL} + GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} + GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} + GITHUB_REDIRECT: ${GITHUB_REDIRECT} + GITHUB_FINE_GRAINED_TOKEN: ${GITHUB_FINE_GRAINED_TOKEN} + UNSPLASH_ACCESS_KEY: ${UNSPLASH_ACCESS_KEY} + NIGHTWATCH_TOKEN: ${NIGHTWATCH_TOKEN} + NIGHTWATCH_REQUEST_SAMPLE_RATE: ${NIGHTWATCH_REQUEST_SAMPLE_RATE} + SSH_TUNNEL_USER: '${SSH_TUNNEL_USER:-}' + SSH_TUNNEL_HOSTNAME: '${SSH_TUNNEL_HOSTNAME:-}' + SSH_TUNNEL_PORT: '${SSH_TUNNEL_PORT:-22}' + SSH_TUNNEL_LOCAL_PORT: '${SSH_TUNNEL_LOCAL_PORT:-3307}' + SSH_TUNNEL_BIND_ADDRESS: '${SSH_TUNNEL_BIND_ADDRESS:-127.0.0.1}' + SSH_TUNNEL_BIND_PORT: '${SSH_TUNNEL_BIND_PORT:-3306}' + SSH_TUNNEL_VERIFY_PROCESS: '${SSH_TUNNEL_VERIFY_PROCESS:-bash}' + SSH_TUNNEL_IDENTITY_FILE: '${SSH_TUNNEL_IDENTITY_FILE:-}' + SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' + DB_CONNECTION_SECOND: '${DB_CONNECTION_SECOND:-mysql}' + DB_HOST_SECOND: '${DB_HOST_SECOND:-127.0.0.1}' + DB_PORT_SECOND: '${DB_PORT_SECOND:-3307}' + DB_DATABASE_SECOND: '${DB_DATABASE_SECOND:-}' + DB_USERNAME_SECOND: '${DB_USERNAME_SECOND:-}' + DB_PASSWORD_SECOND: '${DB_PASSWORD_SECOND:-}' + OCTANE_SERVER: 'frankenphp' + CADDY_GLOBAL_OPTIONS: | + servers { + trusted_proxies static private_ranges + } + CADDY_SERVER_EXTRA_DIRECTIVES: | + @static { + file + path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 + } + header @static Cache-Control "public, max-age=31536000, s-maxage=31536000" + FRANKENPHP_CONFIG: | + worker { + file ./public/frankenphp-worker.php + } + volumes: + - storage:/var/www/html/storage + networks: + - dokploy-network + depends_on: + - laravelcm queue: - image: laravelcm/php - restart: unless-stopped - command: - - 'artisan' - - 'queue:listen' - - 'database' - - '--sleep=10' - - '--quiet' - - '--force' - - '--queue=default,media' - stop_signal: SIGTERM - healthcheck: - test: ['CMD', 'healthcheck-queue'] - start_period: 10s - environment: - APP_NAME: ${APP_NAME} - APP_ENV: ${APP_ENV} - APP_KEY: ${APP_KEY} - APP_DEBUG: ${APP_DEBUG} - APP_DOMAIN: ${APP_DOMAIN} - APP_URL: ${APP_URL} - ASSET_URL: ${ASSET_URL} - APP_TIMEZONE: ${APP_TIMEZONE} - APP_LOCALE: ${APP_LOCALE} - APP_FALLBACK_LOCALE: ${APP_FALLBACK_LOCALE} - APP_MAINTENANCE_DRIVER: ${APP_MAINTENANCE_DRIVER} - BCRYPT_ROUNDS: ${BCRYPT_ROUNDS} - DB_CONNECTION: ${DB_CONNECTION} - DB_HOST: ${DB_HOST} - DB_PORT: ${DB_PORT} - DB_DATABASE: ${DB_DATABASE} - DB_USERNAME: ${DB_USERNAME} - DB_PASSWORD: ${DB_PASSWORD} - LOG_CHANNEL: ${LOG_CHANNEL} - LOG_STACK: ${LOG_STACK} - LOG_DEPRECATIONS_CHANNEL: ${LOG_DEPRECATIONS_CHANNEL} - LOG_LEVEL: ${LOG_LEVEL} - SESSION_DRIVER: ${SESSION_DRIVER} - SESSION_LIFETIME: ${SESSION_LIFETIME} - SESSION_ENCRYPT: ${SESSION_ENCRYPT} - SESSION_PATH: ${SESSION_PATH} - SESSION_DOMAIN: ${SESSION_DOMAIN} - BROADCAST_CONNECTION: ${BROADCAST_CONNECTION} - FILESYSTEM_DISK: ${FILESYSTEM_DISK} - MEDIA_DISK: ${MEDIA_DISK} - FILAMENT_FILESYSTEM_DISK: ${MEDIA_DISK} - FILAMENT_PATH: ${FILAMENT_PATH} - QUEUE_CONNECTION: ${QUEUE_CONNECTION} - CACHE_STORE: ${CACHE_STORE} - CACHE_PREFIX: ${CACHE_PREFIX} - MEMCACHED_HOST: ${MEMCACHED_HOST} - REDIS_URL: ${REDIS_URL} - MAIL_MAILER: ${MAIL_MAILER} - MAIL_HOST: ${MAIL_HOST} - MAIL_PORT: ${MAIL_PORT} - MAIL_USERNAME: ${MAIL_USERNAME} - MAIL_PASSWORD: ${MAIL_PASSWORD} - MAIL_ENCRYPTION: ${MAIL_ENCRYPTION} - MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS} - MAIL_FROM_NAME: ${MAIL_FROM_NAME} - MAIL_SUPPORT: ${MAIL_SUPPORT} - AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} - AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION} - AWS_BUCKET: ${AWS_BUCKET} - AWS_ENDPOINT: ${AWS_ENDPOINT} - AWS_URL: ${AWS_URL} - AWS_USE_PATH_STYLE_ENDPOINT: ${AWS_USE_PATH_STYLE_ENDPOINT} - AWS_DIRECTORY: ${AWS_DIRECTORY} - VITE_APP_NAME: ${VITE_APP_NAME} - OPENAI_API_KEY: ${OPENAI_API_KEY} - OPENAI_ORGANIZATION: ${OPENAI_ORGANIZATION} - OPENAI_PROJECT: ${OPENAI_PROJECT} - ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} - ANTHROPIC_API_VERSION: ${ANTHROPIC_API_VERSION} - OLLAMA_URL: ${OLLAMA_URL} - DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY} - SCOUT_DRIVER: ${SCOUT_DRIVER} - TYPESENSE_HOST: ${TYPESENSE_HOST} - TYPESENSE_PORT: ${TYPESENSE_PORT} - TYPESENSE_PROTOCOL: ${TYPESENSE_PROTOCOL} - TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} - STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} - STRIPE_VERSION: ${STRIPE_VERSION} - NOTCHPAY_PUBLIC_KEY: ${NOTCHPAY_PUBLIC_KEY} - NOTCHPAY_SECRET_KEY: ${NOTCHPAY_SECRET_KEY} - MARKDOWNX_GIPHY_API_KEY: ${MARKDOWNX_GIPHY_API_KEY} - TORCHLIGHT_TOKEN: ${TORCHLIGHT_TOKEN} - TORCHLIGHT_THEME: ${TORCHLIGHT_THEME} - TWITTER_CONSUMER_KEY: ${TWITTER_CONSUMER_KEY} - TWITTER_CONSUMER_SECRET: ${TWITTER_CONSUMER_SECRET} - TWITTER_ACCESS_TOKEN: ${TWITTER_ACCESS_TOKEN} - TWITTER_ACCESS_SECRET: ${TWITTER_ACCESS_SECRET} - TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} - TELEGRAM_CHANNEL: ${TELEGRAM_CHANNEL} - GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} - GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} - GITHUB_REDIRECT: ${GITHUB_REDIRECT} - GITHUB_FINE_GRAINED_TOKEN: ${GITHUB_FINE_GRAINED_TOKEN} - NIGHTWATCH_TOKEN: ${NIGHTWATCH_TOKEN} - NIGHTWATCH_REQUEST_SAMPLE_RATE: ${NIGHTWATCH_REQUEST_SAMPLE_RATE} - SSH_TUNNEL_USER: '${SSH_TUNNEL_USER:-}' - SSH_TUNNEL_HOSTNAME: '${SSH_TUNNEL_HOSTNAME:-}' - SSH_TUNNEL_PORT: '${SSH_TUNNEL_PORT:-22}' - SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' - SSH_TUNNEL_LOCAL_PORT: '${SSH_TUNNEL_LOCAL_PORT:-3307}' - SSH_TUNNEL_BIND_ADDRESS: '${SSH_TUNNEL_BIND_ADDRESS:-127.0.0.1}' - SSH_TUNNEL_BIND_PORT: '${SSH_TUNNEL_BIND_PORT:-3306}' - SSH_TUNNEL_VERIFY_PROCESS: '${SSH_TUNNEL_VERIFY_PROCESS:-bash}' - DB_CONNECTION_SECOND: '${DB_CONNECTION_SECOND:-mysql}' - DB_HOST_SECOND: '${DB_HOST_SECOND:-127.0.0.1}' - DB_PORT_SECOND: '${DB_PORT_SECOND:-3307}' - DB_DATABASE_SECOND: '${DB_DATABASE_SECOND:-}' - DB_USERNAME_SECOND: '${DB_USERNAME_SECOND:-}' - DB_PASSWORD_SECOND: '${DB_PASSWORD_SECOND:-}' - OCTANE_SERVER: 'frankenphp' - CADDY_GLOBAL_OPTIONS: | - servers { - trusted_proxies static private_ranges - } - CADDY_SERVER_EXTRA_DIRECTIVES: | - @static { - file - path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 - } - header @static Cache-Control "public, max-age=31536000, s-maxage=31536000" - FRANKENPHP_CONFIG: | - worker { - file ./public/frankenphp-worker.php - } - volumes: - - storage:/var/www/html/storage - networks: - - dokploy-network - depends_on: - - laravelcm + image: laravelcm/php + restart: unless-stopped + command: + - 'artisan' + - 'queue:listen' + - 'database' + - '--sleep=10' + - '--quiet' + - '--force' + - '--queue=default,media' + stop_signal: SIGTERM + healthcheck: + test: ['CMD', 'healthcheck-queue'] + start_period: 10s + environment: + APP_NAME: ${APP_NAME} + APP_ENV: ${APP_ENV} + APP_KEY: ${APP_KEY} + APP_DEBUG: ${APP_DEBUG} + APP_DOMAIN: ${APP_DOMAIN} + APP_URL: ${APP_URL} + ASSET_URL: ${ASSET_URL} + APP_TIMEZONE: ${APP_TIMEZONE} + APP_LOCALE: ${APP_LOCALE} + APP_FALLBACK_LOCALE: ${APP_FALLBACK_LOCALE} + APP_MAINTENANCE_DRIVER: ${APP_MAINTENANCE_DRIVER} + BCRYPT_ROUNDS: ${BCRYPT_ROUNDS} + DB_CONNECTION: ${DB_CONNECTION} + DB_HOST: ${DB_HOST} + DB_PORT: ${DB_PORT} + DB_DATABASE: ${DB_DATABASE} + DB_USERNAME: ${DB_USERNAME} + DB_PASSWORD: ${DB_PASSWORD} + LOG_CHANNEL: ${LOG_CHANNEL} + LOG_STACK: ${LOG_STACK} + LOG_DEPRECATIONS_CHANNEL: ${LOG_DEPRECATIONS_CHANNEL} + LOG_LEVEL: ${LOG_LEVEL} + SESSION_DRIVER: ${SESSION_DRIVER} + SESSION_LIFETIME: ${SESSION_LIFETIME} + SESSION_ENCRYPT: ${SESSION_ENCRYPT} + SESSION_PATH: ${SESSION_PATH} + SESSION_DOMAIN: ${SESSION_DOMAIN} + BROADCAST_CONNECTION: ${BROADCAST_CONNECTION} + FILESYSTEM_DISK: ${FILESYSTEM_DISK} + MEDIA_DISK: ${MEDIA_DISK} + FILAMENT_FILESYSTEM_DISK: ${MEDIA_DISK} + FILAMENT_PATH: ${FILAMENT_PATH} + QUEUE_CONNECTION: ${QUEUE_CONNECTION} + CACHE_STORE: ${CACHE_STORE} + CACHE_PREFIX: ${CACHE_PREFIX} + MEMCACHED_HOST: ${MEMCACHED_HOST} + REDIS_URL: ${REDIS_URL} + REDIS_HOST: ${REDIS_HOST} + REDIS_PASSWORD: ${REDIS_PASSWORD} + REDIS_PORT: ${REDIS_PORT} + MAIL_MAILER: ${MAIL_MAILER} + MAIL_HOST: ${MAIL_HOST} + MAIL_PORT: ${MAIL_PORT} + MAIL_USERNAME: ${MAIL_USERNAME} + MAIL_PASSWORD: ${MAIL_PASSWORD} + MAIL_ENCRYPTION: ${MAIL_ENCRYPTION} + MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS} + MAIL_FROM_NAME: ${MAIL_FROM_NAME} + MAIL_SUPPORT: ${MAIL_SUPPORT} + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} + AWS_DEFAULT_REGION: ${AWS_DEFAULT_REGION} + AWS_BUCKET: ${AWS_BUCKET} + AWS_ENDPOINT: ${AWS_ENDPOINT} + AWS_URL: ${AWS_URL} + AWS_USE_PATH_STYLE_ENDPOINT: ${AWS_USE_PATH_STYLE_ENDPOINT} + AWS_ROOT: ${AWS_ROOT} + VITE_APP_NAME: ${VITE_APP_NAME} + OPENAI_API_KEY: ${OPENAI_API_KEY} + OPENAI_ORGANIZATION: ${OPENAI_ORGANIZATION} + OPENAI_PROJECT: ${OPENAI_PROJECT} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY} + ANTHROPIC_API_VERSION: ${ANTHROPIC_API_VERSION} + OLLAMA_URL: ${OLLAMA_URL} + DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY} + SCOUT_DRIVER: ${SCOUT_DRIVER} + TYPESENSE_HOST: ${TYPESENSE_HOST} + TYPESENSE_PORT: ${TYPESENSE_PORT} + TYPESENSE_PROTOCOL: ${TYPESENSE_PROTOCOL} + TYPESENSE_API_KEY: ${TYPESENSE_API_KEY} + STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY} + STRIPE_VERSION: ${STRIPE_VERSION} + NOTCHPAY_PUBLIC_KEY: ${NOTCHPAY_PUBLIC_KEY} + NOTCHPAY_SECRET_KEY: ${NOTCHPAY_SECRET_KEY} + MARKDOWNX_GIPHY_API_KEY: ${MARKDOWNX_GIPHY_API_KEY} + TORCHLIGHT_TOKEN: ${TORCHLIGHT_TOKEN} + TORCHLIGHT_THEME: ${TORCHLIGHT_THEME} + TWITTER_CONSUMER_KEY: ${TWITTER_CONSUMER_KEY} + TWITTER_CONSUMER_SECRET: ${TWITTER_CONSUMER_SECRET} + TWITTER_ACCESS_TOKEN: ${TWITTER_ACCESS_TOKEN} + TWITTER_ACCESS_SECRET: ${TWITTER_ACCESS_SECRET} + TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} + TELEGRAM_CHANNEL: ${TELEGRAM_CHANNEL} + GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID} + GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET} + GITHUB_REDIRECT: ${GITHUB_REDIRECT} + GITHUB_FINE_GRAINED_TOKEN: ${GITHUB_FINE_GRAINED_TOKEN} + UNSPLASH_ACCESS_KEY: ${UNSPLASH_ACCESS_KEY} + NIGHTWATCH_TOKEN: ${NIGHTWATCH_TOKEN} + NIGHTWATCH_REQUEST_SAMPLE_RATE: ${NIGHTWATCH_REQUEST_SAMPLE_RATE} + SSH_TUNNEL_USER: '${SSH_TUNNEL_USER:-}' + SSH_TUNNEL_HOSTNAME: '${SSH_TUNNEL_HOSTNAME:-}' + SSH_TUNNEL_PORT: '${SSH_TUNNEL_PORT:-22}' + SSH_TUNNEL_LOCAL_PORT: '${SSH_TUNNEL_LOCAL_PORT:-3307}' + SSH_TUNNEL_BIND_ADDRESS: '${SSH_TUNNEL_BIND_ADDRESS:-127.0.0.1}' + SSH_TUNNEL_BIND_PORT: '${SSH_TUNNEL_BIND_PORT:-3306}' + SSH_TUNNEL_VERIFY_PROCESS: '${SSH_TUNNEL_VERIFY_PROCESS:-bash}' + SSH_TUNNEL_IDENTITY_FILE: '${SSH_TUNNEL_IDENTITY_FILE:-}' + SSH_TUNNEL_PRIVATE_KEY: '${SSH_TUNNEL_PRIVATE_KEY:-}' + DB_CONNECTION_SECOND: '${DB_CONNECTION_SECOND:-mysql}' + DB_HOST_SECOND: '${DB_HOST_SECOND:-127.0.0.1}' + DB_PORT_SECOND: '${DB_PORT_SECOND:-3307}' + DB_DATABASE_SECOND: '${DB_DATABASE_SECOND:-}' + DB_USERNAME_SECOND: '${DB_USERNAME_SECOND:-}' + DB_PASSWORD_SECOND: '${DB_PASSWORD_SECOND:-}' + OCTANE_SERVER: 'frankenphp' + CADDY_GLOBAL_OPTIONS: | + servers { + trusted_proxies static private_ranges + } + CADDY_SERVER_EXTRA_DIRECTIVES: | + @static { + file + path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 + } + header @static Cache-Control "public, max-age=31536000, s-maxage=31536000" + FRANKENPHP_CONFIG: | + worker { + file ./public/frankenphp-worker.php + } + volumes: + - storage:/var/www/html/storage + networks: + - dokploy-network + depends_on: + - laravelcm networks: dokploy-network: external: true