DebianDebian Based

How To Install Caddy on Debian 13

Install Caddy on Debian 13

Caddy has emerged as one of the most innovative web servers in recent years, offering a refreshing alternative to traditional solutions like Apache and Nginx. This modern, open-source web server stands out with its automatic HTTPS capabilities via Let’s Encrypt integration, eliminating the tedious manual certificate management that plagues many administrators. Built using the Go programming language, Caddy requires no external dependencies and provides HTTP/2 and HTTP/3 support by default, making it exceptionally fast and efficient for modern web applications.

The Caddyfile configuration syntax is remarkably simple compared to other web servers, allowing even newcomers to set up complex hosting environments with minimal learning curve. Whether you’re deploying static websites, dynamic PHP applications, or sophisticated reverse proxy setups, Caddy handles it all with grace. This comprehensive guide walks you through the complete installation and configuration of Caddy web server on Debian 13 (Trixie), from initial system preparation to hosting your first application with automatic SSL certificates.

What is Caddy Web Server

Caddy represents a paradigm shift in web server technology. This powerful, open-source HTTP server was designed from the ground up with security and simplicity as core principles. Unlike legacy web servers that require extensive configuration files and manual certificate management, Caddy automates the most tedious aspects of web hosting.

The server’s flagship feature is its automatic HTTPS implementation. When you configure Caddy with a domain name, it automatically obtains, installs, and renews SSL/TLS certificates from Let’s Encrypt without any intervention. This means your websites are secure by default, with no cron jobs or separate certificate management tools required. The automatic certificate renewal happens in the background, ensuring your sites never experience downtime due to expired certificates.

Caddy supports HTTP/2 and HTTP/3 protocols out of the box, providing superior performance compared to older HTTP/1.1 implementations. These modern protocols enable multiplexing, header compression, and server push capabilities that dramatically improve page load times. The web server also includes built-in support for virtual hosting, allowing you to serve multiple websites from a single server instance.

Beyond basic web serving, Caddy excels as a reverse proxy, load balancer, and API gateway. Its modular architecture supports plugins and extensions, enabling customization for specific use cases. The server performs zero-downtime configuration reloads, meaning you can update your settings without disrupting active connections. Cross-platform compatibility ensures Caddy runs smoothly on Linux, BSD, Windows, macOS, Solaris, and even Android systems.

Caddy vs Traditional Web Servers

When compared to Apache and Nginx, Caddy’s advantages become immediately apparent. The Caddyfile uses an intuitive, human-readable syntax that doesn’t require memorizing cryptic directives. Configuration blocks are organized logically, making maintenance straightforward even months after initial setup.

Apache requires mod_ssl and separate tools like Certbot for HTTPS automation. Nginx needs similar third-party solutions. Caddy integrates everything natively, reducing your technology stack and potential points of failure. The server’s memory footprint remains minimal even under heavy load, thanks to Go’s efficient concurrency model. For system administrators and developers seeking a modern, secure, and easy-to-manage web server, Caddy represents the logical choice.

Prerequisites

Before beginning the installation process, ensure your system meets these requirements. You’ll need a fresh or existing Debian 13 (Trixie) installation with root or sudo user access. At least 1 GB of RAM is recommended, though Caddy runs efficiently on smaller systems for light workloads.

An active internet connection is essential for downloading packages and, if you plan to enable automatic HTTPS, for communicating with Let’s Encrypt’s certificate authority. Having a registered domain name pointed to your server’s IP address isn’t mandatory but unlocks Caddy’s automatic SSL certificate features. Without a domain, you can still use Caddy for local development or with self-signed certificates.

Basic command-line knowledge will help you follow along smoothly. Familiarity with text editors like nano or vim, understanding file permissions, and comfort with the terminal environment make the process more intuitive. Additionally, configure your firewall to allow incoming connections on ports 80 (HTTP) and 443 (HTTPS) to ensure your web server remains accessible from the internet.

Security best practices dictate performing this installation under a non-root user account with sudo privileges rather than directly as root. This approach limits potential damage from accidental commands and follows the principle of least privilege.

Step 1: Update System Packages

Begin by refreshing your system’s package index and upgrading existing packages. This critical first step ensures you have the latest security patches and dependency versions, preventing compatibility issues during Caddy installation.

sudo apt update && sudo apt upgrade -y

The apt update command contacts all configured repositories and downloads current package lists. This doesn’t install anything but refreshes the local database of available software. The apt upgrade command then installs newer versions of packages already present on your system. The -y flag automatically confirms prompts, streamlining the process.

Depending on how recently you’ve updated your system, this process takes anywhere from a few seconds to several minutes. You’ll see output listing packages being upgraded, including their old and new version numbers. If kernel updates are installed, consider rebooting your system before proceeding with Caddy installation.

Step 2: Install Required Dependencies

Several packages are necessary for adding third-party repositories securely and downloading files. These dependencies enable APT to work with HTTPS sources and verify package authenticity through GPG signatures.

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

Each package serves a specific purpose in the installation pipeline. The gnupg package provides GNU Privacy Guard tools for verifying cryptographic signatures on downloaded packages. This ensures the software you install comes from trusted sources and hasn’t been tampered with during transit.

The curl utility transfers data from or to servers using various protocols, including HTTPS. You’ll use it to download Caddy’s repository configuration and GPG keys. Meanwhile, apt-transport-https allows the APT package manager to retrieve packages over secure HTTPS connections rather than unencrypted HTTP.

Both debian-keyring and debian-archive-keyring contain the official GPG keys for Debian’s package repositories. These keyrings establish a chain of trust for package verification. Once installation completes, verify by checking versions: curl --version and gpg --version should both return output.

Step 3: Add Official Caddy Repository

Rather than manually downloading Caddy binaries, adding the official repository ensures you receive automatic updates through your system’s normal package management workflow.

Import Caddy GPG Key

GPG keys provide cryptographic verification that packages come from legitimate sources. Without importing Caddy’s signing key, APT would reject packages from their repository as unverified.

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

Breaking down this command: -1 forces curl to use TLS version 1, -s enables silent mode suppressing progress meters, -L follows redirects, and -f fails silently on server errors. The pipe (|) sends curl’s output to gpg --dearmor, which converts the ASCII-armored key into binary format. Finally, the binary key is saved to /usr/share/keyrings/, the standard location for repository signing keys on Debian systems.

Add Repository to Sources List

Next, download and install the repository configuration file that tells APT where to find Caddy packages:

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list

The tee command reads from standard input and writes to both standard output and the specified file. This creates /etc/apt/sources.list.d/caddy-stable.list containing the repository URL and configuration. Using the official Cloudsmith-hosted repository guarantees you receive the latest stable Caddy releases.

Refresh Package Index

Update APT’s cache to include packages from the newly added Caddy repository:

sudo apt update

The output should now mention the Caddy repository, confirming APT can successfully communicate with it. You’ll see a line referencing “dl.cloudsmith.io” among the repository sources being queried.

Step 4: Install Caddy Web Server

With the repository configured, installing Caddy becomes a single command:

sudo apt install caddy -y

APT downloads the Caddy package, approximately 16 MB in size, along with any additional dependencies. The installation process automatically creates a systemd service unit, configures default directories, and generates an initial Caddyfile at /etc/caddy/Caddyfile.

During installation, you’ll see output indicating packages being unpacked and configured. The Caddy service starts automatically upon installation completion and is enabled to launch on system boot. This means your server will have Caddy running immediately after installation without manual service management.

The installer creates a dedicated caddy user and group for running the web server process. This security measure ensures Caddy operates with minimal privileges, limiting potential damage if the service were compromised. File permissions are set appropriately for configuration files, web roots, and data directories.

Step 5: Verify Caddy Installation

Confirming successful installation involves several verification steps that check different components.

Check Caddy Version

Query the installed Caddy version to confirm the binary is accessible:

caddy version

You should see output similar to v2.8.4 or newer, depending on when you install. This command also displays the Go version used to compile Caddy, providing useful debugging information if issues arise.

Verify Binary Location

Confirm the Caddy executable resides in the expected system path:

which caddy

This command returns /usr/bin/caddy, indicating the binary is in your system’s PATH and can be executed from any directory.

Check Service Status

Verify the systemd service is active and running:

sudo systemctl status caddy

Look for “active (running)” in green text near the top of the output. The status display includes the process ID (PID), memory usage, and the path to the configuration file being used. You’ll also see recent log entries showing Caddy’s startup messages.

If the status shows “inactive” or “failed,” investigate with sudo journalctl -u caddy -n 50 to view the last 50 log entries for troubleshooting.

Access Default Welcome Page

Open a web browser and navigate to http://YOUR_SERVER_IP, replacing YOUR_SERVER_IP with your actual server address. You should see a simple Caddy welcome page or directory listing, confirming the web server is responding to HTTP requests.

If you cannot access the page, check your firewall settings and ensure Caddy is listening on port 80 with sudo netstat -tulpn | grep :80.

Step 6: Understanding Caddy Directory Structure

Caddy’s installation creates several important directories and files, each serving specific purposes in the web server’s operation.

The main configuration file lives at /etc/caddy/Caddyfile. This is where you define sites, domains, and server behavior. The file uses Caddy’s intuitive configuration syntax with site blocks enclosed in curly braces.

Caddy stores persistent data in /var/lib/caddy/, including automatically obtained SSL/TLS certificates, OCSP staples, and internal state information. Never manually edit files in this directory; Caddy manages its own data.

The default web root directory is /var/www/html/, following standard Linux web server conventions. Place your website files here, or configure alternative locations in the Caddyfile. The Caddy binary executable resides at /usr/bin/caddy, allowing you to run Caddy commands from any terminal location.

The systemd service unit file at /usr/lib/systemd/system/caddy.service defines how the service starts, stops, and runs. Modifying this file requires systemd daemon reloading. SSL certificates obtained automatically are stored in /etc/ssl/caddy/ or within Caddy’s data directory, depending on configuration.

Log file locations depend on your Caddyfile configuration. By default, Caddy logs to systemd’s journal, accessible via journalctl -u caddy. You can configure alternative log destinations for easier analysis or integration with log management systems.

Step 7: Configure Firewall Rules

Proper firewall configuration ensures legitimate traffic reaches your web server while blocking unauthorized access.

If using UFW (Uncomplicated Firewall), allow HTTP and HTTPS traffic with these commands:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload

UFW’s simple syntax makes firewall management accessible. The first command creates a rule allowing TCP traffic on port 80 (HTTP), while the second permits port 443 (HTTPS). Reloading UFW applies the new rules without disrupting existing connections.

For systems using iptables directly, add these rules:

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables-save | sudo tee /etc/iptables/rules.v4

These iptables commands append rules to the INPUT chain, accepting TCP packets destined for ports 80 and 443. The final command saves rules persistently so they survive system reboots.

Port 80 is essential even for HTTPS-only sites because Let’s Encrypt uses HTTP-01 challenges for domain verification during certificate issuance. Caddy also uses port 80 for automatic HTTP-to-HTTPS redirects. Without both ports open, you’ll experience certificate acquisition failures or accessibility issues.

Step 8: Basic Caddy Configuration

The Caddyfile uses an intuitive, declarative syntax that describes what you want rather than how to achieve it.

Understanding the Caddyfile

Each site configuration begins with an address (domain, IP, or port) followed by directives within curly braces. Directives are keywords that tell Caddy what to do—serve files, reverse proxy requests, enable compression, etc.

Comments start with # and are ignored by Caddy. Indentation isn’t syntactically required but improves readability. The order of directives generally doesn’t matter, as Caddy applies them intelligently.

Creating a Simple Configuration

Edit the Caddyfile to serve static content:

sudo nano /etc/caddy/Caddyfile

Replace the contents with this basic configuration:

:80 {
    root * /var/www/html
    file_server
}

The :80 address tells Caddy to listen on port 80 for all hostnames. The root directive specifies where website files are located, with the asterisk (*) acting as a path matcher applying to all requests. The file_server directive enables static file serving from the root directory.

Domain-Based Configuration with Automatic HTTPS

For production websites with domain names, specify your domain to enable automatic HTTPS:

example.com {
    root * /var/www/html
    encode gzip zstd
    file_server
}

Replace example.com with your actual domain. Caddy automatically obtains an SSL certificate from Let’s Encrypt, configures HTTPS, and redirects HTTP traffic to HTTPS. The encode directive enables gzip and zstd compression for faster page loads.

Configuration Best Practices

Always validate configuration syntax before applying changes to avoid service disruptions. Use meaningful site blocks organized logically by domain or purpose. Leverage automatic HTTPS whenever possible for enhanced security without complexity.

Enable compression for improved performance, especially for text-based resources like HTML, CSS, and JavaScript. Comment complex configurations to aid future maintenance and troubleshooting.

Reload Configuration

After editing the Caddyfile, validate syntax and reload:

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

The validate command checks for syntax errors without applying changes. If validation passes, reload applies the new configuration with zero downtime—existing connections remain undisturbed.

Step 9: Configure Caddy for PHP Applications

Many web applications require PHP processing capabilities. Integrating PHP-FPM with Caddy enables dynamic content generation.

Install PHP and PHP-FPM

Install PHP along with commonly needed extensions:

sudo apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip -y

This command installs PHP-FPM (FastCGI Process Manager) and extensions for database connectivity (php-mysql), HTTP requests (php-curl), image manipulation (php-gd), multibyte string handling (php-mbstring), XML parsing (php-xml), and archive handling (php-zip).

Configure PHP-FPM for Caddy

By default, PHP-FPM runs as the www-data user. For security and compatibility, change this to match Caddy’s user:

sudo nano /etc/php/8.3/fpm/pool.d/www.conf

Find and modify these lines:

user = caddy
group = caddy
listen.owner = caddy
listen.group = caddy

Save changes and restart PHP-FPM:

sudo systemctl restart php8.3-fpm
sudo systemctl enable php8.3-fpm

Verify PHP-FPM is running: sudo systemctl status php8.3-fpm

Create Caddyfile for PHP

Update your Caddyfile to process PHP files:

example.com {
    root * /var/www/html
    encode gzip zstd
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}

The php_fastcgi directive configures Caddy to forward PHP requests to PHP-FPM via Unix socket. This approach is more efficient than TCP sockets for local communication. Caddy automatically handles common PHP patterns, including index.php routing and script filename resolution.

Test PHP Installation

Create a test PHP file:

echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php

Visit http://your-domain.com/info.php in your browser. You should see PHP’s configuration information page, confirming successful integration. Remove this file after testing for security: sudo rm /var/www/html/info.php

Step 10: Managing Caddy Service

Systemd provides comprehensive service management capabilities for controlling Caddy:

sudo systemctl start caddy      # Start Caddy service
sudo systemctl stop caddy       # Stop Caddy service
sudo systemctl restart caddy    # Restart Caddy service
sudo systemctl reload caddy     # Reload configuration
sudo systemctl enable caddy     # Enable automatic startup
sudo systemctl disable caddy    # Disable automatic startup
sudo systemctl status caddy     # Check service status

Understanding the difference between restart and reload is crucial. Restart completely stops and starts the service, temporarily interrupting all connections. Reload applies configuration changes without disconnecting active clients, achieving zero-downtime updates—a key Caddy advantage.

View real-time Caddy logs with journalctl:

sudo journalctl -u caddy -f

The -f flag follows the log, displaying new entries as they occur. Remove it to view historical logs. Use -n 50 to limit output to the last 50 lines. Logs include request details, errors, certificate operations, and configuration reload events—invaluable for troubleshooting.

Step 11: Security Hardening

Enhancing Caddy’s security posture protects your server and data from potential threats.

Running Caddy as Non-Root User

Caddy runs as a non-privileged user by default, but binding to ports below 1024 typically requires root. Grant Caddy this capability without full root access:

sudo setcap 'cap_net_bind_service=+ep' /usr/bin/caddy

This command uses Linux capabilities to allow the Caddy binary to bind privileged ports while running as the caddy user. It’s more secure than running the entire service as root.

TLS Configuration Best Practices

Enforce strong TLS versions and ciphers:

example.com {
    tls [email protected] {
        protocols tls1.2 tls1.3
    }
    root * /var/www/html
    file_server
}

This configuration specifies an email address for Let’s Encrypt notifications and restricts TLS to versions 1.2 and 1.3, excluding older, vulnerable versions. Caddy selects secure cipher suites automatically.

File Permissions

Ensure proper ownership and permissions for Caddy files:

sudo chown -R root:root /etc/caddy
sudo chmod 644 /etc/caddy/Caddyfile
sudo chown -R caddy:caddy /var/www/html
sudo chmod 0770 /etc/ssl/caddy

Configuration files should be owned by root but readable by Caddy. Web content should be owned by the Caddy user. Certificate directories need restricted permissions to protect private keys.

Security Headers

Add security headers to protect against common web vulnerabilities:

example.com {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
    }
    root * /var/www/html
    file_server
}

These headers enforce HTTPS usage, prevent MIME sniffing, block iframe embedding, enable XSS filtering, and control referrer information leakage.

Troubleshooting Common Issues

Even with careful configuration, issues occasionally arise. These solutions address frequent problems.

Caddy Won’t Start

When Caddy fails to start, check configuration syntax first:

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

Syntax errors display with line numbers and descriptions. Review recent logs for additional clues:

sudo journalctl -u caddy -n 50 --no-pager

Verify no other services occupy ports 80 or 443:

sudo netstat -tulpn | grep :80
sudo netstat -tulpn | grep :443

If another process uses these ports, stop it or configure Caddy to use alternative ports.

Certificate Issues

Automatic HTTPS requires proper DNS configuration. Ensure your domain’s A record points to your server’s public IP address. Check DNS propagation with:

dig example.com +short
nslookup example.com

Let’s Encrypt must reach your server on port 80 for HTTP-01 challenges. Verify firewall rules allow incoming connections. Check Let’s Encrypt rate limits if you’ve repeatedly attempted certificate issuance—they restrict failed attempts per domain per hour.

Review certificate-related logs specifically:

sudo journalctl -u caddy | grep -i certificate

Permission Errors

Permission issues typically stem from incorrect file ownership or mode settings. Ensure the Caddy user can read web root files:

sudo chown -R caddy:caddy /var/www/html
sudo chmod -R 755 /var/www/html

Check SELinux or AppArmor policies if enabled. These security frameworks can block legitimate access. Temporarily set SELinux to permissive mode for testing:

sudo setenforce 0

If this resolves the issue, create proper policies rather than permanently disabling security modules.

Port Already in Use

Identify processes using required ports:

sudo lsof -i :80
sudo lsof -i :443

Common culprits include Apache, Nginx, or previous Caddy instances. Stop conflicting services:

sudo systemctl stop apache2
sudo systemctl stop nginx

Disable them permanently if Caddy is your chosen web server:

sudo systemctl disable apache2
sudo systemctl disable nginx

Configuration Not Applying

When changes don’t take effect, verify you’re editing the correct Caddyfile. Check which file Caddy loads:

sudo systemctl status caddy

The output shows the configuration file path. After making changes, always reload rather than restart for zero-downtime updates. Clear browser cache or use incognito mode to avoid seeing cached content instead of your changes.

Performance Optimization Tips

Maximizing Caddy’s performance ensures fast, responsive websites even under heavy traffic.

Enable both gzip and zstd compression for optimal file size reduction. Zstd offers better compression ratios than gzip with similar CPU usage. Configure caching headers to leverage browser caching:

header Cache-Control "public, max-age=31536000"

Use HTTP/2 server push for critical resources like CSS and JavaScript, reducing page load times. Enable file server browsing only when needed—disabling it for production sites improves security.

Implement rate limiting for API endpoints to prevent abuse:

rate_limit {
    zone dynamic_zone {
        key {remote_host}
        events 100
        window 1m
    }
}

Monitor resource usage with systemd tools:

systemd-cgtop

This displays real-time CPU and memory usage per service. Consider CDN integration for static assets, reducing server load and improving global performance.

Optimize PHP-FPM pool settings based on available RAM and expected concurrent users. Adjust pm.max_children, pm.start_servers, and related parameters in PHP-FPM’s pool configuration.

Configure log rotation to prevent log files from consuming excessive disk space:

sudo nano /etc/logrotate.d/caddy

Add rotation rules specifying retention periods and compression settings.

Congratulations! You have successfully installed Caddy. Thanks for using this tutorial to install the latest version of the Caddy web server on Debian 13 “Trixie” system. For additional help or useful information, we recommend you check the official Caddy website.

VPS Manage Service Offer
If you don’t have time to do all of this stuff, or if this is not your area of expertise, we offer a service to do “VPS Manage Service Offer”, starting from $10 (Paypal payment). Please contact us to get the best deal!

r00t

r00t is an experienced Linux enthusiast and technical writer with a passion for open-source software. With years of hands-on experience in various Linux distributions, r00t has developed a deep understanding of the Linux ecosystem and its powerful tools. He holds certifications in SCE and has contributed to several open-source projects. r00t is dedicated to sharing her knowledge and expertise through well-researched and informative articles, helping others navigate the world of Linux with confidence.
Back to top button