Install and configure Caddy 2 web server with automatic HTTPS and PHP-FPM

Beginner 25 min Apr 17, 2026 24 views
Ubuntu 24.04 Ubuntu 22.04 Debian 12 AlmaLinux 9 Rocky Linux 9 Fedora 41

Set up Caddy 2 web server with automatic HTTPS certificates from Let's Encrypt and PHP-FPM integration for dynamic content. Includes virtual hosts, security headers, and systemd service configuration.

Prerequisites

  • Root or sudo access
  • Domain name pointing to server
  • Ports 80 and 443 accessible from internet

What this solves

Caddy 2 is a modern web server that automatically obtains and renews HTTPS certificates from Let's Encrypt without manual configuration. Unlike traditional web servers that require separate SSL certificate management, Caddy handles HTTPS automatically while providing excellent performance and a simple configuration format called the Caddyfile.

Step-by-step installation

Update system packages

Start by updating your package manager to ensure you get the latest versions of all packages.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install required packages

Install curl and basic tools needed for the Caddy installation process.

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
sudo dnf install -y curl

Add Caddy official repository

Add the official Caddy repository to get the latest stable version with automatic updates.

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo dnf copr enable @caddy/caddy -y

Install Caddy 2

Install Caddy from the official repository to ensure you get the latest version with all security updates.

sudo apt install -y caddy
sudo dnf install -y caddy

Install PHP-FPM

Install PHP-FPM to handle dynamic PHP content. This installs PHP 8.1+ with the FastCGI Process Manager for optimal performance.

sudo apt install -y php-fpm php-mysql php-curl php-json php-mbstring
sudo dnf install -y php-fpm php-mysqlnd php-curl php-json php-mbstring

Create web root directory

Create the directory structure for your websites and set appropriate ownership and permissions.

sudo mkdir -p /var/www/html/example.com
sudo chown -R caddy:caddy /var/www/html
sudo chmod -R 755 /var/www/html
Never use chmod 777. It gives every user on the system full access to your files. Instead, fix ownership with chown and use minimal permissions like 755 for directories and 644 for files.

Create a basic Caddyfile configuration

Create the main Caddy configuration file that defines how your web server handles requests and enables automatic HTTPS.

{
    # Global options
    email admin@example.com
    admin localhost:2019
}

HTTP to HTTPS redirect

http://example.com { redir https://example.com{uri} permanent }

Main site with automatic HTTPS

example.com { root * /var/www/html/example.com # Enable file server for static content file_server # PHP-FPM integration php_fastcgi unix//run/php/php-fpm.sock { index index.php } # Security headers header { X-Content-Type-Options nosniff X-Frame-Options DENY X-XSS-Protection "1; mode=block" Strict-Transport-Security "max-age=31536000; includeSubDomains" Referrer-Policy strict-origin-when-cross-origin } # Rate limiting rate_limit { zone static_files { key {remote_host} events 100 window 1m } } # Logging log { output file /var/log/caddy/example.com.log { roll_size 100mb roll_keep 5 roll_keep_for 720h } } }

Create log directory

Create the log directory for Caddy and set proper permissions so Caddy can write log files.

sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy
sudo chmod 755 /var/log/caddy

Create test PHP file

Create a simple PHP file to test that PHP-FPM integration is working correctly.

<?php
phpinfo();
?>
sudo chown caddy:caddy /var/www/html/example.com/index.php
sudo chmod 644 /var/www/html/example.com/index.php

Configure PHP-FPM pool

Configure PHP-FPM to work optimally with Caddy by adjusting the process manager and socket permissions.

# Find PHP-FPM version
php --version | head -1

Edit the www pool config (adjust path for your PHP version)

sudo nano /etc/php/8.*/fpm/pool.d/www.conf

Update these settings in the PHP-FPM pool configuration:

user = caddy
group = caddy
listen.owner = caddy
listen.group = caddy
listen.mode = 0660
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

Enable and start services

Enable both Caddy and PHP-FPM services to start automatically on boot and start them now.

sudo systemctl enable --now caddy
sudo systemctl enable --now php*-fpm
sudo systemctl status caddy
sudo systemctl status php*-fpm

Configure virtual hosts

Add additional virtual hosts to serve multiple domains from the same server.

sudo mkdir -p /var/www/html/blog.example.com
sudo chown -R caddy:caddy /var/www/html/blog.example.com

Add the virtual host configuration to your Caddyfile:

# Add this to your existing Caddyfile
blog.example.com {
    root * /var/www/html/blog.example.com
    file_server
    php_fastcgi unix//run/php/php-fpm.sock
    
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        X-XSS-Protection "1; mode=block"
    }
}

Configure firewall

Open the necessary ports for HTTP and HTTPS traffic. Caddy needs both ports to handle redirects and serve content.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Reload Caddy configuration

Reload Caddy to apply the new configuration. Caddy will automatically obtain SSL certificates from Let's Encrypt.

sudo systemctl reload caddy
Note: For automatic HTTPS to work, your domain must point to your server's public IP address and ports 80/443 must be accessible from the internet.

Verify your setup

Check that both Caddy and PHP-FPM are running properly and that SSL certificates were obtained successfully.

sudo systemctl status caddy
sudo systemctl status php*-fpm
caddy version

Check if certificates were obtained

sudo ls -la /var/lib/caddy/.local/share/caddy/certificates/

Test configuration syntax

sudo caddy validate --config /etc/caddy/Caddyfile

View recent logs

sudo journalctl -u caddy --lines=20

Visit https://example.com in your browser to confirm the SSL certificate is working and PHP information is displayed.

Common issues

SymptomCauseFix
502 Bad GatewayPHP-FPM not running or wrong socket pathsudo systemctl start php*-fpm and check socket path in Caddyfile
Certificate not obtainedDomain not pointing to server or ports blockedCheck DNS records and firewall rules for ports 80/443
Permission denied errorsWrong file ownershipsudo chown -R caddy:caddy /var/www/html
Caddy won't startConfiguration syntax errorsudo caddy validate --config /etc/caddy/Caddyfile
PHP files download instead of executePHP-FPM not configured or wrong MIME typesCheck php_fastcgi directive and restart services

Next steps

Running this in production?

Want this handled for you? This works for a single server. When you run multiple environments or need this available 24/7, keeping it healthy is a different job. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed cloud infrastructure for businesses that depend on uptime. From initial setup to ongoing operations.