A Caddyfile config example for Laravel

Want to help support this blog? Try out Oh Dear, the best all-in-one monitoring tool for your entire website, co-founded by me (the guy that wrote this blogpost). Start with a 10-day trial, no strings attached.

We offer uptime monitoring, SSL checks, broken links checking, performance & cronjob monitoring, branded status pages & so much more. Try us out today!

Profile image of Mattias Geniar

Mattias Geniar, November 25, 2019

Follow me on Twitter as @mattiasgeniar

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 301
}

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

	# Point to the upstream PHP-FPM socket
	fastcgi / unix:/run/php/robotstudios.be-fpm.sock php

	# This rewrite is to prevent access to dot files and folders such
	# as .htaccess, .git, etc.
	rewrite {
		# This regex catches everything that contains "/." in the URL
		r \/\.
		if {path} not_starts_with .well-known
		to /index.php{uri}
	}

	# Rewrite non-existent URLs to our index.php controller
	rewrite {
		if {file} not favicon.ico
		to {path} {path}/ /index.php?{query}
	}

	header / {
		Strict-Transport-Security	"max-age=30758400"
		X-Content-Type-Options		"nosniff"
		X-Frame-Options			"deny"
		X-XSS-Protection		"1; mode=block"
		Referrer-Policy			"same-origin"
	}

	# Access logging in the combined format
	log / /var/www/html/robotstudios.be/logs/access.log "{combined}" {
		rotate_size 50
		rotate_age 14
		rotate_keep 14
		rotate_compress
	}

	# Error logs in a separate file
	errors /var/www/html/robotstudios.be/logs/error.log {
		rotate_size 50
		rotate_age 14
		rotate_keep 14
		rotate_compress
	}
}

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 combined format, so I get the referer header & user agents too.

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



Want to subscribe to the cron.weekly newsletter?

I write a weekly-ish newsletter on Linux, open source & webdevelopment called cron.weekly.

It features the latest news, guides & tutorials and new open source projects. You can sign up via email below.

No spam. Just some good, practical Linux & open source content.