How to Setup the Caddy Web Server with php-fpm

A month ago I wrote about an exciting open source project called Caddy. In case you missed it, you can catch it here. The project offers a lightweight, powerful web server aimed at lowering the technical barrier to entry for just about anyone wanting to serve content from a self hosted web server. In this post I want to cover how to setup the Caddy web server to serve PHP pages. I’ll be configuring Caddy to use php-fpm. I encourage you to follow along in your own dev environment.

 

Requirements:

Ubuntu 14.04
curl
php-fpm
Caddy web server binary (download)

 

Let’s begin.

 

Open a terminal on your Ubuntu 14.04 server or desktop and install php, php-fpm, and curl:

sudo apt-get install php5-fpm php5-cli curl

Once you’ve downloaded the Caddy binary, extract it:

sudo mkdir /opt/caddy-server; sudo tar xvzf caddy_linux_amd64_custom.tar.gz -C /opt/caddy-server

Create the docroot we’ll be using for this example, and give yourself perms to write to it:

sudo mkdir /opt/caddywww; sudo chown `whoami` /opt/caddywww

Now let’s make a Caddyfile. A Caddyfile is Caddy’s configuration file. We’ll create this file:

/etc/Caddyfile

With this text:

:80
tls off
root /opt/caddywww
gzip
log /var/log/caddyaccess.log
errors /var/log/caddyerror.log
fastcgi / /var/run/php5-fpm.sock php

 

If you’re used to configuring Nginx or Apache, the format of this file will look unfamiliar. Once you’ve configured a few options in a Caddyfile, you’ll get the hang of it pretty fast. The documentation makes it easy to reference the functionality you’re looking for. Let’s sidetrack for a minute, and discuss the Caddyfile and each of the directives, to briefly explain what they mean.
This line tells Caddy to answer on port 80, no matter how it’s called.
:80

If you want to lock it to a virtual host definition you would simply change this to the following, which will tell Caddy to only answer if port 80 was accessed using example.com. Any other request using a different hostname would receive an error from Caddy.
example.com:80

The following tells Caddy to disable serving sites over TLS. I’m putting this here, because Caddy will automatically setup a certificate with Let’s Encrypt if you use a valid and registered domain name for your site. This is a very cool feature, but for the purposes of this demo, I’m leaving it out. I’ll cover this on a future blog post.
[ UPDATE: Matt (author of Caddy) has pointed out that since we are explicitly defining port 80, we don’t actually need this, but we can leave it in to be explicit. ]
tls off

This is the docroot where our php and html files will go:
root /opt/caddywww

This tells Caddy to enable gzip compression with default values. You can set more specific options, like file types or compression level, but for this example, default settings are fine:
gzip

Set your access log:
log /var/log/caddyaccess.log

Set your error log:
errors /var/log/caddyerror.log

This tells Caddy how to talk to your php5-fpm service. First it directs all requests from the root of your site to the php-fpm socket using the php preset:
fastcgi / /var/run/php5-fpm.sock php

If you need to configure your php settings with more granularity, you can use the fastcgi directive in the following way. The breakdown for each option is: If the requested file has the .php extension use fastcgi proxy(ext), store anything after .php in the PATH_INFO CGI variable(split), and check for index.php if no file is specified in the URL(index). These are also the default settings for the php preset.

fastcgi / /var/run/php5-fpm.sock {
    ext 	.php
    split	.php
    index	index.php
}

 

The Caddyfile, while simple in syntax, can also provide advanced features. One useful feature is the ability to describe virtual hosts. A very simple example of defining two virtual hosts in a Caddyfile would be like this:

myfirstsite.com:80 {
     root /www/myfirstsite.com
     gzip
     tls off
}

mysecondsite.com:80 {
    root /www/mysecondsite.com
    gzip
    tls off
}

 

Alright let’s get back to the task at hand. At this point we should configure some php items. We’ll leave the default config for php5-fpm alone, but for convenience let’s make sure short_open_tag is set to On in the PHP config. You’ll edit the following file to make that change:

/etc/php5/fpm/php.ini

Line 212 reads:

short_open_tag = Off

Change it to:

short_open_tag = On

Now let’s restart php-fpm*:

sudo restart php5-fpm

*this should already be started, restarting should grab the new php.ini changes.

Alright, time to start Caddy:

sudo /opt/caddy-server/caddy -conf="/etc/Caddyfile"

You should see:

Activating privacy features... done.
:80

**On a fresh system you may get this error message:

Warning: File descriptor limit 1024 is too low for production sites. At least 4096 is recommended. Set with "ulimit -n 4096".

You can either run that command, or just leave it. For this example, it’s fine. If you’re running this in production, of course you’ll want to increase the file descriptor limit.

Now let’s leave that terminal alone, start a new one, and create a small file in our docroot to make sure PHP is working. Create:

/opt/caddywww/index.php

With:

<? echo 'PHP version: ' . phpversion() . "\n" ?>

I threw the new line in there at the end so that when you use curl to request this page, you’ll get a clean prompt back.

Now run it:

curl localhost:80

You should see:

PHP version: 5.5.9-1ubuntu4.14

And if it worked, congrats, you’ve just setup Caddy with PHP support! Not bad huh? When I attempted this, it worked on my first try. How many of you have had that happen the first time you tried setting up php-fpm with Apache or Nginx? Caddy makes it easier for sure.

Thanks for reading!

[ UPDATE: For those of you who want a simple init.d script to start Caddy so it runs in the background, I’ve added one here: https://github.com/nortone/caddythings.

Also, Caddy has released a PHP-FPM FastCGI troubleshooting page here in case you have any issues: https://github.com/mholt/caddy/wiki/Troubleshooting-PHP-FPM-and-FastCGI ]

  • https://twitter.com/mholt6 Matt

    Hi! Author of Caddy here. Nice tutorial. A few things to note that should make it even simpler:

    – The fastcgi directive has a php “preset” that sets those extra properties for you. So you can replace those lines with one line: fastcgi / /var/run/php5-fpm.sock php – see fastcgi docs for more details.

    – Since you explicitly define port 80 in the address, you don’t need tls off (but you can leave it if you want to be explicit).

    -There’s a new PHP & FastCGI troubleshooting guide here: https://github.com/mholt/caddy/wiki/Troubleshooting-PHP-FPM-and-FastCGI – check it out if you have any problems!

    -If you have a working setup with a popular PHP application, feel free to share your simple tutorial in the caddyserver/examples repository.

    • http://shad.me Shad Mickelberry

      Thanks for the post and thanks for your added comment Matt. I was playing around with replacing Apache with Caddy using fastcgi and I was unsure about the virtual hosts. Once question if you don’t mind… If setting up a remote server is there anything you need to do to keep Caddy running when the terminal connection is shut off? Thanks again.

      • http://depado.markdownblog.com Depado

        There are multiple ways to keep a process running when the connection is closed. I wrote an article on how to do that http://depado.markdownblog.com/2015-12-07-setting-up-caddy-server-on-debian. I personnaly use supervisor to do so. But you can also start caddy in a tmux or a screen process, or even “nohup caddy&” I guess.

      • Eric

        Hi Shad, I added an init.d script here so you can run Caddy in the background: https://github.com/nortone/caddythings/ ,as @Depado:disqus mentions, supervisor is a good choice too.

    • Eric

      Thank you for the feedback Matt, and thank you for Caddy! I’ve updated my post to reflect those good bits of knowledge.

Leave a Comment