A Caddyfile config example for Laravel

I’ve been using the Caddy webserver for all my projects lately. Here’s my current default config for a Laravel project.

First, I want to separate all my configs in different config files, to keep things tidy. My Caddyfile is simply an import of all my vhosts.

$ cat /etc/caddy/Caddyfile
import /etc/caddy/conf.d/*.conf

As a result, all configs live in /etc/caddy/conf.d/.

Here’s an example for my own company, robotstudios.be . (which is a Laravel app just to receive Stripe payments via credit card. Damn international wire transfers suck.)

$ cat /etc/caddy/conf.d/robotstudios.be.conf
www.robotstudios.be {
	redir https://robotstudios.be{uri} permanent
}

# The actual vhost, on a single domain
robotstudios.be {
	root * /var/www/html/robotstudios.be/public
	encode gzip

	# This blocks access to dot files and folders such as .htaccess,
	# .git, etc., while still allowing the .well-known directory through.
	@hidden {
		path */.*
		not path /.well-known/*
	}
	respond @hidden 404

	# Point all PHP requests to the upstream PHP-FPM socket. php_fastcgi
	# also handles the front-controller rewrite to index.php for you, so
	# the explicit "rewrite to /index.php" rules from Caddy v1 are gone.
	php_fastcgi unix//run/php/robotstudios.be-fpm.sock

	# Serve static files (CSS, JS, images) that aren't handled by PHP
	file_server

	header {
		Strict-Transport-Security	"max-age=30758400"
		X-Content-Type-Options		"nosniff"
		X-Frame-Options			"deny"
		Referrer-Policy			"same-origin"
	}

	# Access logging in the combined format, rolled and kept for 14 days
	log {
		output file /var/www/html/robotstudios.be/logs/access.log {
			roll_size 50mb
			roll_keep 14
			roll_keep_for 336h
		}
		format transform `{request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
			time_format "02/Jan/2006:15:04:05 -0700"
		}
	}
}

This config serves a couple of purposes:

  • Redirect all versions of the domain to robotstudios.be, without the www-prefix
  • Enable gzip compression
  • Store logs in the home dir of the site, rotate them and keep 14 versions
  • Point all PHP requests to an upstream socket, served by php-fpm
  • Redirect all URLs to the index.php (for pretty-printed URLs)
  • Prevent access to files like .htaccess, .git, … (like robotstudios.be/.htaccess )
  • Set a sane set of default security headers, like HSTS (force HTTPS)

The logs use the transform encoder to produce the familiar Apache-style combined log line, so I get the referer header & user agents too. That encoder ships as the caddy-transform-encoder plugin, so it needs to be built into your Caddy binary (caddy add-package github.com/caddyserver/transform-encoder or via xcaddy).

It’s readable and pretty short, I like that.