2025 PHP konferansında Frankenphp ve Caddy web server ile tanıştım, Frankenphp standartta kullandığımız php alınarak üzerine bir takım eklemeler yapılan bir php servisi, Caddy web server ile birlikte 103 Early Hints web response desteğine sahip oluyor. Bu 103 kodu standartta kullandığımız Nginx ya da Apache sunucularda mevcut değil. 103 Early Hints Nedir? Bu response kodu tarayıcımıza web sitesi daha yüklenmeden bizim daha önceden belirlediğimiz css, javascript ya da bazı görselleri direkt olarak indirmeye başlıyor, yani biz siteye girmek için bir istekte bulunduğumuzda sitenin kendi html yanıtı gelmeden bu dosyalar indirilmeye başlıyor ve sitenin önyükleme hızını artırmış oluyor. headers_send(103); PHP koduyla bunu yapıyoruz ancak standart kullandığımız PHP içinde bu yoktur, bu fonksiyonu çağırmak istediğinizde PHP Fatal error: Uncaught Error: Call to undefined function headers_send() hatasıyla karşılaşırsınız. Bu fonksiyon Frankenphp içerisinde geliyor.Laravel web sitemde aşağıdaki gibi bir middleware hazırladım test etmek için, kısa bir süre sonra burayı dinamik bir hale getirerek sitede aktif tema ne ise dosyaları oradan alacağı şekilde düzenleme yapacağım buraya. namespace App\\Http\\Middleware; use Closure; use Illuminate\\Http\\Request; use Symfony\\Component\\HttpFoundation\\Response; class EarlyHintsMiddleware { /** * Handle an incoming request. * * @param \\Closure(\\Illuminate\\Http\\Request): (\\Symfony\\Component\\HttpFoundation\\Response) $next */ public function handle(Request $request, Closure $next): Response { $this->frankenphp_send_early_hints([ \'; rel=preload; as=style\', \'; rel=preload; as=style\', \'<\'.asset(\'themes/fontawesome/css/all.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/animate.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/bootstrap.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/slick.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/default.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/style.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/responsive.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/css/custom.min.css\').\'>; rel=preload; as=style\', \'<\'.asset(\'theme/Cryptograph/js/vendor/jquery-3.6.0.min.js\').\'>; rel=preload; as=script\', \'<\'.asset(\'theme/Cryptograph/js/bootstrap.min.js\').\'>; rel=preload; as=script\', \'<\'.asset(\'theme/Cryptograph/js/main.min.js\').\'>; rel=preload; as=script\', \'; rel=preload; as=style\', \'; rel=preload; as=script\', \'<\'.asset(\'themes/fontawesome/webfonts/fa-solid-900.woff2\').\'>; rel=preload; as=font; type=font/woff2; crossorigin\', \'<\'.asset(\'themes/fontawesome/webfonts/fa-brands-400.woff2\').\'>; rel=preload; as=font; type=font/woff2; crossorigin\', \'<\'.asset(\'themes/fontawesome/webfonts/fa-duotone-900.woff2\').\'>; rel=preload; as=font; type=font/woff2; crossorigin\', \'<\'.asset(\'themes/fontawesome/webfonts/fa-regular-400.woff2\').\'>; rel=preload; as=font; type=font/woff2; crossorigin\', ]); return $next($request); } private function frankenphp_send_early_hints(array $links): void { foreach ($links as $link) { header(\'Link: \'.$link); if(function_exists(\'headers_send\')){ headers_send(103); } } } } Asıl gelmek istediğim konu ise şu, sunucu yapımı tamamen docker-compose ile çalıştıracağım bir yapıya taşımayı düşünüyordum zaten, Frankenphp ile de tanıştığımda bu yapıyı oluşturmaya başladım. Yani standart Nginx, Apache, PHP Fpm dışına çıkarak böyle bir yapı oluşturmaya başladım, bu yapıyı oluştururken de karşılaştığım bazı problemler oldu, sunucumda bazı web sitelerinin yazılımı güncel değil .htaccess kuralları ile çalışıyor bazıları bu da Caddy tarafında desteklenmediği için sitenin anasayfası haricinde diğer sayfalar 404e düşüyordu mecbur docker compose içerisine bir de Apache eklemek zorunda kaldım.docker-compose.yaml dosyası aşağıdaki gibi services: alpha_panel_web: build: context: ./alpha-panel/web dockerfile: Dockerfile container_name: alpha_panel_web hostname: alpha_panel_web restart: always volumes: - ./alpha-panel/web/httpdocs:/var/www/AlphaPanel/httpdocs - ./alpha-panel/web/logs:/var/log/caddy - ./alpha-panel/web/ssl:/var/www/ssl - ./alpha-panel/web/Caddyfile:/etc/frankenphp/Caddyfile - ./alpha-panel/web/caddy_data:/data - ./vhosts:/var/www/vhosts environment: PANEL_DOMAIN: ${PANEL_DOMAIN} CF_API_TOKEN: ${CF_API_TOKEN} ADMIN_EMAIL: ${ADMIN_EMAIL} ports: - \"${PRIVATE_NETWORK_IP}:7443:443\" networks: - vhost_network alpha_panel_webhook: build: context: ./alpha-panel/webhook dockerfile: Dockerfile container_name: alpha_panel_webhook hostname: alpha_panel_webhook restart: always volumes: - ./alpha-panel/webhook:/app - ./vhosts:/var/www/vhosts - ./alpha-panel/webhook/ssh_key:/root/.ssh networks: - vhost_network frankenphp: build: context: ./frankenphp dockerfile: Dockerfile container_name: frankenphp hostname: frankenphp restart: always environment: CF_API_TOKEN: ${CF_API_TOKEN} ADMIN_EMAIL: ${ADMIN_EMAIL} PUBLIC_NETWORK_IP: ${PUBLIC_NETWORK_IP} PRIVATE_NETWORK_IP: ${PRIVATE_NETWORK_IP} volumes: - ./frankenphp/Caddyfile:/etc/frankenphp/Caddyfile - ./frankenphp/sites-enabled:/etc/frankenphp/sites-enabled - ./frankenphp/caddy_data:/data - ./vhosts:/var/www/vhosts - ./php-code-server/run/:/run/php/ - ./frankenphp/logs:/var/log/caddy/ networks: - vhost_network depends_on: - mysql - redis - mongodb - ftp - meilisearch ports: - \"${PUBLIC_NETWORK_IP}:80:80\" - \"${PUBLIC_NETWORK_IP}:443:443\" php-code-server: build: context: ./php-code-server dockerfile: Dockerfile container_name: php-code-server hostname: php-code-server restart: always user: root environment: - PASSWORD=${CODE_SERVER_PASSWORD} - SUDO_PASSWORD=${CODE_SERVER_SUDO_PASSWORD} - PROXY_DOMAIN=${CODE_SERVER_DOMAIN}:7443 - DEFAULT_WORKSPACE=/var/www/vhosts - TZ=Etc/UTC - ALLOW_ROOT=true volumes: - ./php-code-server/run/:/run/php/ - ./vhosts:/var/www/vhosts - ./php-code-server/supervisor.d:/etc/supervisor/conf.d/ - ./php-code-server/8.4/fpm.d/:/etc/php/8.4/fpm/pool.d/ - ./php-code-server/8.3/fpm.d:/etc/php/8.3/fpm/pool.d/ - ./php-code-server/8.2/fpm.d:/etc/php/8.2/fpm/pool.d/ - ./php-code-server/8.1/fpm.d:/etc/php/8.1/fpm/pool.d/ - ./php-code-server/8.0/fpm.d:/etc/php/8.0/fpm/pool.d/ - ./php-code-server/php.ini:/etc/php/8.4/fpm/conf.d/99999-custom.ini - ./php-code-server/php.ini:/etc/php/8.3/fpm/conf.d/99999-custom.ini - ./php-code-server/php.ini:/etc/php/8.2/fpm/conf.d/99999-custom.ini - ./php-code-server/php.ini:/etc/php/8.1/fpm/conf.d/99999-custom.ini - ./php-code-server/php.ini:/etc/php/8.0/fpm/conf.d/99999-custom.ini - ./ftp-config/users.env:/etc/users.env:ro - ./code-server/data:/root - ./apache/sites-enabled:/etc/apache2/sites-enabled - ./apache/conf-enabled/remote_ip.conf:/etc/apache2/conf-enabled/remote_ip.conf - ./apache/conf-enabled/cloudflare.conf:/etc/apache2/conf-enabled/cloudflare.conf - ./apache/conf-enabled/security.conf:/etc/apache2/conf-enabled/security.conf - ./apache/conf-enabled/deflate.conf:/etc/apache2/conf-enabled/deflate.conf - ./vhosts:/var/www/vhosts - ./php-code-server/run/:/run/php/ depends_on: - mysql - mongodb - redis - meilisearch - ftp networks: - vhost_network meilisearch: image: getmeili/meilisearch:v1.14 container_name: meilisearch hostname: meilisearch volumes: - ./meilisearch/data:/meili_data - ./meilisearch/tmp:/tmp restart: always environment: - MEILI_ENV=production - TMPDIR=/tmp ports: - \"${PRIVATE_NETWORK_IP}:7700:7700\" networks: - vhost_network command: [\"meilisearch\", \"--master-key\", \"${MEILISEARCH_MASTER_KEY}\"] mysql: image: mysql:9.3.0 container_name: mysql hostname: db volumes: - ./mysql/data:/var/lib/mysql - ./mysql/conf.d:/etc/mysql/conf.d restart: always environment: MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} ports: - \"${PRIVATE_NETWORK_IP}:3306:3306\" networks: - vhost_network # aliases: # - db.niyazi.org redis: image: redis:latest container_name: redis hostname: redis.niyazi.org restart: always volumes: - ./redis:/data ports: - \"${PRIVATE_NETWORK_IP}:6379:6379\" networks: - vhost_network mongodb: image: mongodb/mongodb-community-server:8.0.8-ubuntu2204 container_name: mongodb hostname: mongodb.niyazi.org restart: always user: root volumes: - ./mongodb:/data/db ports: - \"${PRIVATE_NETWORK_IP}:27017:27017\" networks: - vhost_network backlink_service: build: context: ./vhosts/backlink.name/service dockerfile: Dockerfile container_name: backlink_service hostname: backlinkdb restart: always volumes: - ./vhosts/backlink.name/service:/app networks: - vhost_network password: image: \"vaultwarden/server:latest\" hostname: \"${VAULTWARDEN_DOMAIN}\" container_name: password restart: always volumes: - \"./vaultwarden/data:/data/\" environment: - \"DATABASE_URL=mysql://${VAULTWARDEN_DB_USER}:${VAULTWARDEN_DB_PASSWORD}@${VAULTWARDEN_DB_HOST}/${VAULTWARDEN_DB_NAME}\" - \"RUST_BACKTRACE=1\" networks: - vhost_network phpmyadmin: image: phpmyadmin:latest container_name: phpmyadmin hostname: pma.niyazi.org restart: always environment: PMA_HOST: mysql PMA_PORT: 3306 # PMA_USER: root # PMA_PASSWORD: ${MYSQL_ROOT_PASSWORD} networks: - vhost_network ftp: image: delfer/alpine-ftp-server # Alpine + vsftpd, FTPS destekli container_name: ftp-server hostname: ftp-server restart: always ports: - \"${PRIVATE_NETWORK_IP}:21:21\" # komut kanalı - \"${PRIVATE_NETWORK_IP}:21000-21010:21000-21010\" # pasif mod port aralığı environment: # Dış IP veya hostname (PASV yanıtlarında kullanılır) ADDRESS: server.niyazi.org MIN_PORT: 21000 MAX_PORT: 21010 env_file: - ./ftp-config/users.env entrypoint: [\"/init.sh\"] volumes: - ./vhosts:/var/www/vhosts:rw - ./ftp-config/users.env:/config/users.env:ro - ./ftp-config/init.sh:/init.sh:ro networks: - vhost_network networks: vhost_network: name: vhost_network driver: bridge Burada çoğunlukla ek olarak kendi kullandığım bazı servisler de mevcut, servisleri çalıştırmadan önce kullanmayacağınız servisleri buradan çıkarabilirsiniz. Örneğin alpha_panel_web, alpha_panel_webhook, ve backlink_service bunları yaml dosyasından kaldırarak kullanabilirsiniz. projenin github linkini aşağıya bırakıyorum. https://github.com/niyazialpay/AlphaWebServer