[{"data":1,"prerenderedAt":234},["ShallowReactive",2],{"seo-verification":3,"blog-laravel-octane-vps-frankenphp-docker-traefik-es":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-laravel-octane-vps-frankenphp-docker-traefik-es",{"id":9,"slug":10,"slugs":11,"title":14,"excerpt":15,"readTime":16,"views":17,"isPinned":18,"publishedAt":19,"updatedAt":20,"category":21,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":29,"intro":32,"sections":33,"ctaTitle":29,"ctaBody":29,"ctaButton":141,"ctaUrl":142,"relatedPosts":143},436,"laravel-octane-vps-frankenphp-docker-traefik",{"fr":12,"en":10,"ar":13,"es":10},"deployer-laravel-vps-octane","laravel-octane-على-vps-frankenphp-docker-traefik","Laravel Octane en VPS: FrankenPHP, Docker y Traefik","Migrar de PHP-FPM a Laravel Octane con FrankenPHP en Docker Compose detrás de Traefik, entender los cambios del ciclo de vida.",11,0,false,"2026-10-12T00:00:00+00:00","2026-10-13T14:10:28+00:00",{"id":22,"name":23,"slug":24,"color":25,"icon":26},4,"Desarrollo","developpement","bg-warning\u002F10 text-warning","dev",[28],{"id":22,"name":23,"slug":24,"color":25,"icon":26},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-laravel-vps-octane-poster.svg","PHP-FPM lanza un proceso por petición: eficiente para apps pequeñas, pero costoso cuando el tráfico crece. Laravel Octane cambia el paradigma — la aplicación se carga una sola vez en memoria y responde a miles de peticiones sin reinicializarse. La ganancia es real: los benchmarks oficiales de Laravel muestran multiplicadores de 4× a 6× en peticiones\u002Fsegundo frente a PHP-FPM 8.3. FrankenPHP, el driver Octane recomendado desde Laravel 11, integra el servidor HTTP directamente en el binario PHP — sin necesidad de nginx por delante. En un VPS con acceso root, Docker Compose y Traefik, la migración es limpia y reproducible.",[34,38,49,52,83,86,97,131,135,138],{"type":35,"title":36,"body":37},"h2","PHP-FPM vs Laravel Octane — lo que realmente cambia","PHP-FPM sigue el modelo \"shared nothing\": cada petición carga el framework desde cero, ejecuta el código y libera toda la memoria. Es robusto por diseño — una fuga en una petición muere con ella. Octane rompe este contrato. La aplicación se inicializa una vez, luego las peticiones se encadenan en el mismo proceso. La ganancia de rendimiento es masiva, pero la responsabilidad del desarrollador aumenta.",{"type":39,"title":40,"items":41},"ul","Seis diferencias estructurales a conocer",[42,43,44,45,46,47,48],"**Ciclo de vida compartido** — el contenedor IoC de Laravel, los providers y los singletons se instancian una vez y persisten entre todas las peticiones de un worker. Un valor escrito en un singleton en la petición N sigue ahí en la petición N+1.","**Ganancia de rendimiento documentada** — los benchmarks de la documentación oficial de Laravel Octane muestran 4× a 6× más peticiones\u002Fsegundo frente a PHP-FPM 8.3 en endpoints típicos, al eliminar el bootstrap de PHP en cada petición.","**Variables estáticas = fugas garantizadas** — cualquier propiedad `static` escrita durante una petición contamina las siguientes. Las Facades de Laravel ocultan referencias estáticas; algunas las limpia Octane, otras no.","**Archivos estáticos servidos por FrankenPHP** — el binario incluye un servidor HTTP completo. En un VPS, no se necesita nginx delante de PHP: FrankenPHP maneja TLS, HTTP\u002F2 y HTTP\u002F3 de forma nativa.","**Memoria RSS estable ≠ memoria filtrada** — la memoria del proceso sube al arrancar y luego se estabiliza. Una fuga real se detecta por crecimiento continuo a lo largo de miles de peticiones, no por el nivel inicial.","**Workers y concurrencia** — Octane arranca `--workers=N` procesos. Cada worker mantiene su propio estado; no hay memoria compartida entre workers, pero un mismo worker procesa sus peticiones secuencialmente.","**Compatibilidad Laravel 10 y 11** — Octane 2.x soporta Laravel 10+. FrankenPHP como driver está disponible desde `laravel\u002Foctane` 2.3. PHP 8.2 mínimo, PHP 8.3 recomendado.",{"type":35,"title":50,"body":51},"Prerrequisitos antes de empezar","Un VPS con **2 GB de RAM mínimo** (4 GB recomendados para un stack completo con Redis y queue workers), acceso root, Docker 25+ y Docker Compose v2. La aplicación debe ejecutarse en **Laravel 10 o 11**, con `laravel\u002Foctane` 2.x instalado (`composer require laravel\u002Foctane`). Traefik 3.x gestionará los certificados Let's Encrypt y el enrutamiento HTTPS. No se necesita nginx adicional: FrankenPHP reemplaza completamente la capa HTTP.",{"type":53,"title":54,"steps":55},"steps","Desplegar Laravel Octane + FrankenPHP + Traefik en Docker Compose",[56,59,62,65,68,71,74,77,80],{"title":57,"body":58},"Instalar laravel\u002Foctane y publicar la configuración","En tu proyecto Laravel:\n\n```bash\ncomposer require laravel\u002Foctane\nphp artisan octane:install --server=frankenphp\n```\n\nEsto publica `config\u002Foctane.php` y añade las variables de entorno en `.env.example`. Verifica que `OCTANE_SERVER=frankenphp` esté definido.",{"title":60,"body":61},"Escribir el Dockerfile para FrankenPHP","```dockerfile\nFROM dunglas\u002Ffrankenphp:1-php8.3-alpine\n\nRUN install-php-extensions \\\n    pdo_mysql \\\n    redis \\\n    opcache \\\n    pcntl \\\n    zip \\\n    intl\n\nWORKDIR \u002Fapp\n\nCOPY --chown=www-data:www-data . .\n\nRUN composer install --no-dev --optimize-autoloader --no-interaction \\\n && php artisan config:cache \\\n && php artisan route:cache \\\n && php artisan view:cache\n\nEXPOSE 8000\n\nCMD [\"php\", \"artisan\", \"octane:frankenphp\", \"--host=0.0.0.0\", \"--port=8000\", \"--workers=4\", \"--max-requests=500\"]\n```\n\nLa opción `--max-requests=500` reinicia el worker después de 500 peticiones: una red de seguridad contra fugas de memoria residuales.",{"title":63,"body":64},"Escribir el docker-compose.yml completo","```yaml\nservices:\n  app:\n    build: .\n    restart: unless-stopped\n    environment:\n      APP_ENV: production\n      APP_KEY: ${APP_KEY}\n      DB_HOST: db\n      REDIS_HOST: redis\n      CACHE_DRIVER: redis\n      SESSION_DRIVER: redis\n      QUEUE_CONNECTION: redis\n      OCTANE_SERVER: frankenphp\n    networks:\n      - internal\n      - traefik\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.app.rule=Host(`${DOMAIN}`)\"\n      - \"traefik.http.routers.app.entrypoints=websecure\"\n      - \"traefik.http.routers.app.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.app.loadbalancer.server.port=8000\"\n    depends_on:\n      db:\n        condition: service_healthy\n      redis:\n        condition: service_healthy\n\n  worker:\n    build: .\n    restart: unless-stopped\n    command: [\"php\", \"artisan\", \"queue:work\", \"redis\", \"--sleep=3\", \"--tries=3\", \"--max-time=3600\"]\n    networks:\n      - internal\n    depends_on:\n      db:\n        condition: service_healthy\n      redis:\n        condition: service_healthy\n\n  scheduler:\n    build: .\n    restart: unless-stopped\n    command: [\"sh\", \"-c\", \"while true; do php artisan schedule:run >> \u002Fdev\u002Fnull 2>&1; sleep 60; done\"]\n    networks:\n      - internal\n\n  db:\n    image: mysql:8.0\n    restart: unless-stopped\n    volumes:\n      - db_data:\u002Fvar\u002Flib\u002Fmysql\n    networks:\n      - internal\n    healthcheck:\n      test: [\"CMD\", \"mysqladmin\", \"ping\", \"-h\", \"localhost\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\n  redis:\n    image: redis:7-alpine\n    restart: unless-stopped\n    volumes:\n      - redis_data:\u002Fdata\n    networks:\n      - internal\n    healthcheck:\n      test: [\"CMD\", \"redis-cli\", \"ping\"]\n      interval: 10s\n      timeout: 3s\n      retries: 5\n\nvolumes:\n  db_data:\n  redis_data:\n\nnetworks:\n  internal:\n  traefik:\n    external: true\n```",{"title":66,"body":67},"Desplegar Traefik con certificados automáticos","```bash\ndocker network create traefik\nmkdir -p \u002Fopt\u002Ftraefik\u002Fletsencrypt\ntouch \u002Fopt\u002Ftraefik\u002Fletsencrypt\u002Facme.json\nchmod 600 \u002Fopt\u002Ftraefik\u002Fletsencrypt\u002Facme.json\ndocker compose -f \u002Fopt\u002Ftraefik\u002Fdocker-compose.yml up -d\n```",{"title":69,"body":70},"Preparar el archivo .env de producción","Variables críticas a definir en el VPS:\n\n```bash\nAPP_ENV=production\nAPP_DEBUG=false\nAPP_KEY=base64:...  # generado con php artisan key:generate\nDOMAIN=tu-dominio.com\nDB_DATABASE=laravel\nDB_USERNAME=laravel\nDB_PASSWORD=contraseña_fuerte\nDB_ROOT_PASSWORD=root_contraseña\nOCTANE_SERVER=frankenphp\nCACHE_DRIVER=redis\nSESSION_DRIVER=redis\nQUEUE_CONNECTION=redis\n```\n\nNunca hagas commit de `.env` en git. En el VPS, gestiónalo con `scp` o un gestor de secretos.",{"title":72,"body":73},"Ejecutar las migraciones sin downtime","```bash\ndocker compose run --rm app php artisan migrate --force\n```\n\nPara un despliegue zero-downtime, usa el flag `--step` en migraciones que añaden columnas NOT NULL.",{"title":75,"body":76},"Arrancar el stack y verificar el healthcheck","```bash\ndocker compose up -d --build\ndocker compose ps\n```\n\nEspera a que `db` y `redis` alcancen el estado `healthy` antes de que `app` arranque.",{"title":78,"body":79},"Verificar el estado con octane:status","```bash\ndocker compose exec app php artisan octane:status\n```\n\nEste comando muestra el servidor activo (frankenphp), el número de workers en ejecución y el estado global. Una respuesta `running` confirma que los workers responden.",{"title":81,"body":82},"Configurar recarga en caliente para despliegues","```bash\ndocker compose build app worker scheduler\ndocker compose up -d --no-deps app worker scheduler\n```\n\nPara recargar workers sin cortar conexiones activas:\n\n```bash\ndocker compose exec app php artisan octane:reload\n```",{"type":35,"title":84,"body":85},"Lista de compatibilidad antes de pasar a producción","Migrar a Octane no requiere reescribir la aplicación, pero algunos patrones comunes fallan en silencio. Revisa esta lista en tu código antes del primer despliegue.",{"type":39,"title":87,"items":88},"8 puntos a verificar obligatoriamente",[89,90,91,92,93,94,95,96],"**Singletons con estado mutable** — cualquier servicio registrado con `$this->app->singleton()` que almacene datos específicos de una petición debe reiniciarse en un `OctaneServiceProvider`. Auditoría: `grep -r 'singleton' app\u002FProviders`.","**Sesiones** — con `SESSION_DRIVER=redis` las sesiones sobreviven correctamente. El driver `file` puede crear condiciones de carrera con múltiples workers. Migra a `redis` o `database` antes de cambiar a Octane.","**Conexiones de base de datos** — Octane mantiene conexiones DB persistentes por worker. Verifica que MySQL acepte `max_connections ≥ workers × replicas`.","**Variables estáticas en modelos o servicios** — `static $cache = []` en un modelo Eloquent persiste entre peticiones. Reemplaza con inyección de dependencia con alcance de petición.","**Event listeners no idempotentes** — un listener registrado en `boot()` se registra solo una vez, pero se ejecuta en cada petición que dispara el evento. Problema solo si acumula estado global.","**Jobs y colas** — los Jobs no corren en el proceso principal de Octane sino en el contenedor `worker` separado. No se requieren adaptaciones para el código de los Jobs.","**Archivos subidos y almacenamiento** — monta un volumen para `\u002Fapp\u002Fstorage` para que los archivos persistan entre reconstrucciones de imagen.","**Paquetes de terceros** — verifica la compatibilidad con Octane de cada paquete. Desactiva Debugbar y Telescope en producción.",{"type":98,"title":99,"headers":100,"rows":105},"comparison","FrankenPHP vs Swoole vs RoadRunner: elegir tu driver Octane",[101,102,103,104],"Criterio","FrankenPHP","Swoole","RoadRunner",[106,111,116,121,126],[107,108,109,110],"Instalación","Imagen Docker oficial `dunglas\u002Ffrankenphp` — sin extensiones PECL a compilar","Extensión PECL `swoole` — requiere `pecl install swoole` o imagen personalizada","Binario Go separado (`roadrunner`) — descargado vía Composer (`spiral\u002Froadrunner`)",[112,113,114,115],"HTTP\u002F2 y HTTP\u002F3","Nativo — FrankenPHP está construido sobre Caddy que soporta HTTP\u002F3 (QUIC) de serie","HTTP\u002F2 soportado, HTTP\u002F3 no nativo","HTTP\u002F2 vía plugin, HTTP\u002F3 no soportado nativamente",[117,118,119,120],"Compatibilidad con extensiones PHP","Muy amplia — basado en PHP-FPM oficial, la mayoría de extensiones se instalan normalmente","Incompatibilidades conocidas con algunas extensiones bloqueantes","Amplia, pero algunas extensiones PECL complejas pueden necesitar adaptaciones",[122,123,124,125],"Recomendación oficial Laravel","Driver recomendado desde Laravel 11 (2024), listado primero en la documentación de Octane","Primer driver histórico, aún soportado pero menos destacado","Soportado, alternativo a Swoole, común en ecosistemas Symfony\u002FSpiral",[127,128,129,130],"Complejidad operacional","Baja — un solo contenedor, Dockerfile mínimo, sin demonio separado","Media — la extensión swoole debe compilarse con la versión PHP correcta","Media — el binario RoadRunner debe sincronizarse con la versión del paquete Composer",{"type":132,"title":133,"body":134},"tip","Monitorizar Octane en producción con octane:status","El comando `php artisan octane:status` consulta el servidor FrankenPHP en tiempo real y muestra el número de workers activos y el estado global. Intégralo en tu monitorización:\n\n```bash\ndocker compose exec -T app php artisan octane:status | grep -q 'running' && echo OK || echo FAIL\n```\n\nPara recargar workers sin cortar el tráfico:\n\n```bash\ndocker compose exec app php artisan octane:reload\n```\n\nSigue la memoria RSS del proceso principal: un crecimiento continuo tras miles de peticiones indica una fuga. El comando `docker stats app` da la memoria en tiempo real.",{"type":35,"title":136,"body":137},"Resolución de problemas: errores frecuentes en producción","**Fuga de memoria progresiva**: la memoria del contenedor `app` crece sin bajar nunca. Causa probable: un singleton acumula datos por petición. Reduce `--max-requests` a 100 mientras identificas el origen.\n\n**502 Bad Gateway de Traefik**: verifica que el contenedor esté en la red `traefik`, que la etiqueta `traefik.http.services.app.loadbalancer.server.port=8000` corresponda al puerto expuesto, y que el contenedor esté `healthy`.\n\n**Worker que reinicia en bucle**: busca `FATAL` en `docker compose logs app`. Causa más común: una migración no ejecutada que lanza una `QueryException` al arrancar.\n\n**Sesiones perdidas entre peticiones**: cambia a `SESSION_DRIVER=redis`.\n\n**Zona horaria incorrecta**: añade `APP_TIMEZONE` en `.env` y `RUN apk add --no-cache tzdata` en el Dockerfile.",{"type":35,"title":139,"body":140},"Próximos pasos","Ya tienes un stack Laravel Octane funcional en VPS. Los siguientes artículos cubren los pasos naturales: [Desplegar Laravel en un VPS](\u002Fblog\u002Fdeployer-laravel-vps), [Desplegar con Traefik](\u002Fblog\u002Fdeployer-avec-traefik), [Docker Compose production checklist](\u002Fblog\u002Fdocker-compose-production-checklist), [Alojar Redis en VPS](\u002Fblog\u002Fheberger-redis-vps), [PHP 8.2 fin de vida — checklist de migración](\u002Fblog\u002Fphp-82-fin-de-vie-checklist-migration).","Ver los VPS ServOrbit","\u002Fvps-cloud",[144,161,180,196,220],{"id":145,"slug":146,"slugs":147,"title":151,"excerpt":152,"readTime":22,"views":17,"isPinned":18,"publishedAt":153,"updatedAt":154,"category":155,"categories":156,"featuredImage":29,"bgImage":30,"posterImage":158,"relatedSolution":159},5,"desplegar-laravel-en-un-vps",{"fr":148,"en":149,"ar":150,"es":146},"deployer-laravel-vps","deploying-laravel-on-a-vps-a-production-guide","نشر-laravel-على-خادم-vps-دليل-الإنتاج","Desplegar Laravel en un VPS: guía de producción","Ponga Laravel en producción en un VPS: PHP, workers, caché, base de datos, reverse proxy y HTTPS bien configurados.","2026-02-09T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":22,"name":23,"slug":24,"color":25,"icon":26},[157],{"id":22,"name":23,"slug":24,"color":25,"icon":26},"\u002Fblog\u002Fcovers\u002Fdeployer-laravel-vps-poster.svg",{"categorySlug":26,"appSlug":160},"laravel-stack",{"id":162,"slug":163,"slugs":164,"title":168,"excerpt":169,"readTime":170,"views":171,"isPinned":18,"publishedAt":172,"updatedAt":154,"category":173,"categories":177,"featuredImage":29,"bgImage":30,"posterImage":179,"relatedSolution":29},38,"desplegar-con-traefik",{"fr":165,"en":166,"ar":167,"es":163},"deployer-avec-traefik","deploy-your-applications-with-traefik-on-a-vps","انشر-تطبيقاتك-باستخدام-traefik-على-خادم-vps","Desplegar sus aplicaciones con Traefik en un VPS","Despliegue Traefik como reverse proxy en su VPS: enrutamiento automático de los contenedores Docker, certificados SSL Let's Encrypt y balanceo de carga.",3,2,"2026-05-13T00:00:00+00:00",{"id":170,"name":174,"slug":175,"color":176,"icon":175},"Despliegue","deploiement","bg-success\u002F10 text-success",[178],{"id":170,"name":174,"slug":175,"color":176,"icon":175},"\u002Fblog\u002Fcovers\u002Fdeployer-avec-traefik-poster.svg",{"id":181,"slug":182,"slugs":183,"title":187,"excerpt":188,"readTime":189,"views":17,"isPinned":18,"publishedAt":190,"updatedAt":191,"category":192,"categories":193,"featuredImage":29,"bgImage":30,"posterImage":195,"relatedSolution":29},229,"checklist-docker-compose-en-produccion",{"fr":184,"en":185,"ar":186,"es":182},"docker-compose-production-checklist","docker-compose-in-production-10-point-checklist","docker-compose-في-الإنتاج-قائمة-التحقق-من-10-نقاط","Docker Compose en producción: checklist de 10 puntos","Checklist de Docker Compose en producción: 10 ajustes esenciales, health checks, secretos sin downtime, estrategia de rollback, solución de errores comunes.",12,"2026-08-06T00:00:00+00:00","2026-09-29T14:40:45+00:00",{"id":170,"name":174,"slug":175,"color":176,"icon":175},[194],{"id":170,"name":174,"slug":175,"color":176,"icon":175},"\u002Fblog\u002Fcovers\u002Fdocker-compose-production-checklist-poster.svg",{"id":197,"slug":198,"slugs":199,"title":203,"excerpt":204,"readTime":205,"views":17,"isPinned":18,"publishedAt":206,"updatedAt":207,"category":208,"categories":214,"featuredImage":29,"bgImage":30,"posterImage":216,"relatedSolution":217},58,"alojar-redis-en-un-vps",{"fr":200,"en":201,"ar":202,"es":198},"heberger-redis-vps","hosting-redis-on-a-vps","استضافة-redis-على-خادم-vps","Alojar Redis en un VPS: la guía completa","Despliegue Redis en su VPS Cloud: requisitos de RAM\u002FCPU, seguridad (ACL, TLS), persistencia RDB\u002FAOF, resolución de errores y alta disponibilidad.",10,"2026-04-23T00:00:00+00:00","2026-09-08T21:59:59+00:00",{"id":209,"name":210,"slug":211,"color":212,"icon":213},6,"Bases de datos","bases-de-donnees","bg-teal-500\u002F10 text-teal-400","database",[215],{"id":209,"name":210,"slug":211,"color":212,"icon":213},"\u002Fblog\u002Fcovers\u002Fheberger-redis-vps-poster.svg",{"categorySlug":218,"appSlug":219},"bases-de-datos","redis-stack",{"id":221,"slug":222,"slugs":223,"title":227,"excerpt":228,"readTime":16,"views":171,"isPinned":18,"publishedAt":229,"updatedAt":154,"category":230,"categories":231,"featuredImage":29,"bgImage":30,"posterImage":233,"relatedSolution":29},206,"php-82-fin-de-vida-planificar-la-migracion",{"fr":224,"en":225,"ar":226,"es":222},"php-82-fin-de-vie-checklist-migration","php-82-end-of-life-planning-your-migration","نهاية-دعم-php-82-دليل-الترحيل","PHP 8.2 fin de vida: checklist de migración","PHP 8.2 llega al final de su ciclo de vida el 31 de diciembre de 2026. Inventaría tu stack, compara versiones y sigue una checklist detallada para migrar a PHP 8.3 o 8.4.","2026-08-01T00:00:00+00:00",{"id":22,"name":23,"slug":24,"color":25,"icon":26},[232],{"id":22,"name":23,"slug":24,"color":25,"icon":26},"\u002Fblog\u002Fcovers\u002Fphp-82-fin-de-vie-checklist-migration-poster.svg",1791901105707]