Introduction to Caddy
Caddy is a powerful, enterprise-ready, open-source web server with automatic HTTPS. It is known for its simplicity, flexibility, and security features. Caddy automatically manages SSL certificates using Let’s Encrypt and provides easy configuration with its user-friendly Caddyfile syntax.
Whether you’re serving a single site, multiple domains, or configuring advanced proxy settings, Caddy offers a range of options to meet your needs. Proper configuration and maintenance, including using Certbot for SSL certificates if desired, ensure your server runs securely and efficiently.
Installing Caddy
Installing Caddy is straightforward across different Linux distributions. Here’s how to do it on some popular distros:
Ubuntu/Debian:
sudo apt update sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo apt-key add - 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 apt install caddy
CentOS/RHEL:
sudo yum install yum-plugin-copr sudo yum copr enable @caddy/caddy sudo yum install caddy
Fedora:
sudo dnf copr enable @caddy/caddy sudo dnf install caddy
Once installed, you can start Caddy:
sudo systemctl start caddy
Basic Configuration
Caddy’s configuration is managed using a file called Caddyfile, typically located in /etc/caddy/. Here’s a simple configuration example to serve a static website:
example.com { root * /var/www/html file_server }
Serving a Single Website
To serve a single website, place your website files in the root directory specified in the Caddyfile. Ensure the proper permissions are set:
sudo mkdir -p /var/www/html sudo chown -R www-data:www-data /var/www/html sudo chmod -R 755 /var/www/html
Restart Caddy to apply the changes:
sudo systemctl restart caddy
Serving Multiple Websites
Caddy can serve multiple websites using multiple site blocks in the Caddyfile. Here’s an example configuration for two websites:
site1.com { root * /var/www/site1 file_server } site2.com { root * /var/www/site2 file_server }
Set permissions for each document root directory:
sudo mkdir -p /var/www/site1 /var/www/site2 sudo chown -R www-data:www-data /var/www/site1 /var/www/site2 sudo chmod -R 755 /var/www/site1 /var/www/site2
Restart Caddy to apply the changes:
sudo systemctl restart caddy
Configuring Reverse Proxy
To configure Caddy as a reverse proxy for multiple domains, use the reverse_proxy directive in the Caddy file for each domain. Here’s an example:
# Reverse proxy for site1.com site1.com { tls email@example.com reverse_proxy backend1:80 } # Reverse proxy for site2.com site2.com { tls email@example.com reverse_proxy backend2:80 }
Replace backend1:80 and backend2:80 with the actual addresses and ports of your backend servers. Also, replace email@example.com with your actual email address for Let’s Encrypt certificate management.
Restart Caddy to apply the changes:
sudo systemctl restart caddy
Configuring Forward Proxy
Caddy can also be configured as a forward proxy using the forwardproxy plugin. First, you need to install the plugin. Then, configure it in the Caddyfile:
Install Forward Proxy Plugin:
You need to download a Caddy binary with the forwardproxy plugin or build Caddy with the plugin.
Configure Forward Proxy:
:8080 { forwardproxy { basic_auth user pass } }
Restart Caddy to apply the changes:
sudo systemctl restart caddy
Advanced Configuration Options
Caddy supports various advanced configurations such as URL rewriting, load balancing, and caching.
The following advanced configurations in Caddy provide powerful tools to manage various aspects of web server operations, from security and performance to URL management and user experience enhancements.
1. URL Rewriting
URL rewriting is useful when you want to change the URL structure without altering the content structure, such as redirecting outdated URLs to new ones or providing cleaner URLs.
Configuration Example:
example.com { root * /var/www/html file_server @oldpage { path /oldpage.html } rewrite @oldpage /newpage.html }
root * /var/www/html: Specifies the root directory for the website files.
file_server: Enables serving static files from the root directory.
@oldpage: Defines a named matcher for the path /oldpage.html.
rewrite @oldpage /newpage.html: Rewrites requests from /oldpage.html to /newpage.html.
2. Load Balancing
Load balancing is used to distribute incoming network traffic across multiple servers to ensure no single server bears too much load, improving reliability and performance.
Configuration Example:
example.com { reverse_proxy /api/* { to http://backend1:8080 http://backend2:8080 http://backend3:8080 lb_policy random } }
reverse_proxy /api/*: Configures a reverse proxy for all paths starting with /api/.
to http://backend1:8080 http://backend2:8080 http://backend3:8080: Specifies backend servers.
lb_policy random: Sets the load balancing policy to randomly distribute requests among the backend servers.
3. Caching
Caching improves website performance by storing copies of files or responses so that future requests for those resources can be served faster.
Configuration Example:
example.com { root * /var/www/html file_server route { try_files {path} {path}/ /index.html } route /api/* { reverse_proxy http://api_backend:8080 } @cacheable { path_regexp cacheable \.(html|css|js|png|jpg|jpeg|gif|svg|woff|woff2)$ } header @cacheable Cache-Control "public, max-age=31536000" }
route: Defines a sequence of handlers.
try_files {path} {path}/ /index.html: Tries to serve the requested file, directory, or falls back to index.html.
@cacheable: Uses a regular expression to match cacheable file types.
header @cacheable Cache-Control “public, max-age=31536000”: Adds a Cache-Control header to cacheable files.
4. HTTPS with Automatic Certificate Management
Enables HTTPS to secure data transmission and manage SSL/TLS certificates automatically.
Configuration Example:
example.com { root * /var/www/html file_server tls { issuer acme { email your-email@example.com } } }
tls: Enables TLS (HTTPS).
issuer acme: Uses ACME protocol for certificate management.
email your-email@example.com: Email for certificate notifications.
5. Basic Authentication
Protects specific parts of a website with a username and password, useful for admin panels or private content.
Configuration Example:
example.com { root * /var/www/html file_server @protected { path /admin/* } basicauth @protected { username hashed_password } }
@protected: Defines a named matcher for the path /admin/*.
basicauth @protected { username hashed_password }: Configures basic authentication for the matched path.
6. IP Whitelisting
Restricts access to certain IP addresses, useful for securing admin areas or limiting access to certain parts of a website.
Configuration Example:
example.com { root * /var/www/html file_server @whitelist { remote_ip 192.168.1.1 192.168.1.2 } respond @whitelist "Access Denied" 403 }
@whitelist: Matches requests from specific IP addresses.
respond @whitelist “Access Denied” 403: Responds with a 403 status code for non-whitelisted IP addresses.
7. Custom Error Pages
Provides user-friendly error pages for specific HTTP status codes, improving the user experience during errors.
Configuration Example:
example.com { root * /var/www/html file_server handle_errors { @404 { expression {http.error.status_code} == 404 } rewrite @404 /404.html file_server } }
handle_errors: Defines custom error handling.
@404: Matches 404 status code errors.
rewrite @404 /404.html: Serves a custom 404 error page.
8. Rate Limiting
Limits the number of requests a client can make in a given time period to protect against abuse and ensure fair usage.
Configuration Example:
example.com { root * /var/www/html file_server rate_limit { zone example { key client.ip events 20 window 1m } } }
rate_limit: Configures rate limiting.
zone example: Defines a rate limiting zone.
key client.ip: Uses the client’s IP address as the key.
events 20: Allows 20 requests.
window 1m: Per 1 minute time window.
9. Redirects
Redirects old URLs to new URLs, useful for SEO or restructuring a site without breaking existing links.
Configuration Example:
example.com { root * /var/www/html file_server @oldpath { path /oldpath } redir @oldpath /newpath }
@oldpath: Matches the old URL /oldpath.
redir @oldpath /newpath: Redirects requests from /oldpath to /newpath.
10. Header Manipulation
Modifies HTTP headers for responses, useful for security headers, custom headers, or controlling caching.
Configuration Example:
example.com { root * /var/www/html file_server header { X-Frame-Options "DENY" X-Content-Type-Options "nosniff" Referrer-Policy "no-referrer" } }
header: Configures custom HTTP headers.
X-Frame-Options “DENY”: Prevents clickjacking.
X-Content-Type-Options “nosniff”: Prevents MIME type sniffing.
Referrer-Policy “no-referrer”: Disables referrer information.
Security Considerations
Securing Caddy involves several best practices:
Automatic HTTPS: Caddy automatically handles SSL certificates with Let’s Encrypt.
Restrict Access: Use basicauth or jwt to restrict access to sensitive directories.
Using Certbot for SSL Certificates
Securing Caddy involves implementing several best practices to ensure that your web server is protected against potential threats. Below, I’ll explain each of the best practices and provide detailed configurations and use cases for each option:
1. Automatic HTTPS with Caddy
Caddy is known for its automatic HTTPS feature, which simplifies the process of obtaining and renewing SSL certificates using Let’s Encrypt.
Configuration:
Caddy automatically handles SSL certificates if you specify your domain in the Caddyfile. Here’s a basic example:
example.com { root * /var/www/html file_server }
Use Case:
Ideal for users who want a hassle-free setup for HTTPS without manually managing SSL certificates.
Suitable for small to medium-sized websites where ease of configuration and automatic renewal are priorities.
2. Restrict Access Using basicauth or jwt
To secure sensitive directories, you can use basicauth or jwt (JSON Web Tokens) to restrict access.
Configuration for basicauth
example.com { root * /var/www/html file_server basicauth /admin { admin JDJhJDE0JFZKZjBnQmUuLzNpVkpDZGhNTjlnSUZWSzVvQ1hlS2FXbFZVSVpVdUJja1lqbk4wMndrbzZZ } }
The string after admin is a bcrypt-hashed password.
Use Case:
Use basicauth for simple username/password protection.
Suitable for small websites or administrative areas where you need to restrict access to specific users.
Configuration for jwt -> Caddyfile:
example.com { root * /var/www/html file_server jwt { primary yes trusted_tokens { static_secret { token_name access_token token_secret my_secret_key } } } route /admin* { jwt { allow roles admin } reverse_proxy /admin http://localhost:8080 } }
Use Case:
Use jwt for more advanced authentication scenarios involving token-based authentication.
Suitable for APIs or applications requiring robust security with role-based access control.
3. Using Certbot with Caddy
While Caddy’s automatic HTTPS is convenient, you might prefer to use Certbot for SSL certificates, especially if you have an existing workflow with Certbot.
Install Certbot:
Ubuntu/Debian:
sudo apt update sudo apt install certbot
CentOS/RHEL:
sudo yum install certbot
Fedora:
sudo dnf install certbot
Obtain SSL Certificate:
sudo certbot certonly --webroot -w /var/www/html -d yourdomain.com -d www.yourdomain.com
Configure Caddy for SSL:
example.com { root * /var/www/html file_server tls /etc/letsencrypt/live/yourdomain.com/fullchain.pem /etc/letsencrypt/live/yourdomain.com/privkey.pem }
Use Case:
When you need more control over your SSL certificates and prefer to use Certbot.
Useful for complex environments or when integrating with existing Certbot-managed certificates.
4. Auto-Renew SSL Certificate:
Certbot sets up a cron job to automatically renew certificates. Verify it’s working correctly with:
sudo systemctl status certbot.timer
Use Case:
Ensures that your SSL certificates are always up to date without manual intervention.
Critical for production environments where uninterrupted HTTPS availability is essential.
Summary
Automatic HTTPS: Easiest option, fully managed by Caddy.
Restrict Access: Use basicauth for simple cases, jwt for advanced scenarios.
Certbot with Caddy: When more control over SSL management is required.
Auto-Renew: Ensures continuous certificate validity.