Skip to content

Instantly share code, notes, and snippets.

@Mozartted
Created May 26, 2018 09:33
Show Gist options
  • Save Mozartted/b36fb85cc90f8d49d7a1f605e5871854 to your computer and use it in GitHub Desktop.
Save Mozartted/b36fb85cc90f8d49d7a1f605e5871854 to your computer and use it in GitHub Desktop.
title published description tags cover_image
Another kickass server called caddy
false
a super cool webserver for quickly spinning up https servers

Background

The piece was originally published on my blog at legobox

Last year I cam across a server called caddy, I kinda liked it cause its name sounded similar to that of one of my favourite rap artiste cardi b, sounds weird right?, just kidding that not why I loved the caddy web server, rather it was a much simpler server to install and configure than nginx, and what’s more it comes with its own integration of ssl certificates for your domains and these includes wildcards, in this article we are going to take a birds eye view of the server and get to understand why its a great tool.

Prerequisite

There are really not much to know about, before diving into this, but it would be nice if you’ve got the following.

  • At least a child’s like understanding of servers and proxying.
  • A general understanding of what SSL is.
  • An album of Cardi B playing in the background (Invasion of Privacy preferably) — Totally Optional though

With these, you are good to go.

Origins.

Long story short caddy was created by Light Code Labs, and made open source, it operates in a similar manner to nginx with the use of server blocks, just that in this case all configurations can be done in one file called the Caddyfile, It implements https (yea emphasis on s) once its specified as part of the domain name.

Its light and lightening fast and has lots of really good documentation associated with it. Since I’ve been able to convince you (hopefully), let us have a look at how we can install and setup caddy.

Setting up caddy

First things first, you can download caddy by visiting the website (https://caddyserver.com/download), installation is pretty straightforward and easy to get on with, Most of it has been specified by their documentation, If you are looking to set up for a docker container, you might be interested in checking out this docker image.

If you downloaded the zip file, The follow these instructions to get rolling.

First, put the caddy binary in the system wide binary directory and give it appropriate ownership and permissions:

https://gist.github.com/92ea709f374acfa480630f99b5fb439f

Give the caddy binary the ability to bind to privileged ports (e.g. 80, 443) as a non-root user:

https://gist.github.com/67bb79d42e753dc2d446add6d8cad33b

Set up the user, group, and directories that will be needed:

https://gist.github.com/9c33b2ab3388ba7cbf7f7c151bc6fbb9

Place your caddy configuration in the appropriate directory and give it appropriate ownership and permissions:

https://gist.github.com/5d65d4ebceb7eb935e1c19794b14b2b0

Create the home directory for the server and give it appropriate ownership and permissions:

https://gist.github.com/1b2e871b11283f2e00f4fb62331c68c6

Let's assume you have the contents of your website in a directory called 'example.com'. Put your website into place for it to be served by caddy:

https://gist.github.com/ac1487beafe9ee9d1ac1d9d968a8091f

You'll need to explicitly configure caddy to serve the site from this location by adding the following to your Caddyfile if you haven't already:

https://gist.github.com/faa31744d8f5642256825d0f724d1726

Install the systemd service unit configuration file, reload the systemd daemon, and start caddy:

https://gist.github.com/2836e583fce27f2b47ae2c07eee91f2e

Have the caddy service start automatically on boot if you like:

https://gist.github.com/209b963d01b71ba7b4186aa24968b790

If caddy doesn't seem to start properly you can view the log data to help figure out what the problem is:

https://gist.github.com/3bc2fe7a2cd2236168347c310287a9e3

Use log stdout and errors stderr in your Caddyfile to fully utilize systemd journaling.

If your GNU/Linux distribution does not use journald with systemd then check any logfiles in /var/log.

If you want to follow the latest logs from caddy you can do so like this:

https://gist.github.com/7545e9d9b8bafd026d624efd55257e85

You can make other certificates and private key files accessible to the www-data user with the following command:

https://gist.github.com/0ce91f9f52117ec2ceb900e4a681f8b2

The caddy file

While setting up you may have caught a glimpse of the caddyfile, now lets have a real look at it, how do we setup a server block, its as simple as this.

https://gist.github.com/bd8d08d1802937d7a667ee78b3ab4555

Voila, that simple. Let's break it down so we can understand it some more (since its so difficult)

Site Address

The HTTP server uses site addresses for labels. Addresses are specified in the form scheme``://``host``:``port``/``path, where all but one are optional.

The host portion is usually localhost or the domain name. The default port is 2015 (unless the site qualifies for automatic HTTPS, in which case it's changed to 443 for you). The scheme portion is another way to specify a port. Valid schemes are "http" or "https" which represent, respectively, ports 80 and 443. If both a scheme and port are specified, the port takes precedence. For example (this table assumes automatic HTTPS is applied where it qualifies):

https://gist.github.com/e7d4f56bf37fab2f4da242e734e40542

Wildcard characters * can be used in a hostname. A wildcard must take the place of an entire domain label: *.example.com is valid but foo*.example.com is not.

Path Matching.

Some directives accept an argument that specifies a base path to match. A base path is a prefix. If the URL starts with the base path, it will be a match. For example, a base path of /foo will match requests to /foo, /foo.html, /foobar, and /foo/bar.html.

Directives

Most directives invoke a layer of middleware. Middleware is a small layer in the application that handles HTTP requests and does one thing really well. Middleware are chained together (pre-compiled, if you will) at startup. Only middleware handlers which are invoked from the Caddyfile will be chained in, so small Caddyfiles are very fast and efficient.

The syntax of arguments varies from directive to directive. Some have required arguments, others don't. Consult the documentation of each directive for their signatures.

Placeholders

In some cases, directives will accept placeholders (replaceable values). These are words that are enclosed by curly braces { } and interpreted by the HTTP server at request-time. For example, {query} or {>Referer}. Think of them like variables. These placeholders have no relationship to the environment variables you can use in Caddyfiles, except we borrowed the syntax for familiarity.

If you are looking to understand some more about this, it would be wonderful to invest some time into the docs. (click here to get there)

Proxying and Load balancing in caddy

Pulling off proxy actions in caddy is as simple as setting up the proxy directive. This middleware adds a placeholder that can be used in log formats: {upstream} - the name of the upstream host to which the request was proxied.

https://gist.github.com/e792cad1fdcd7471af8ffacdfa811aac

The above proxy makes all /api routes redirect to localhost:9005 (the machine’s localhost). You can use the policy options in the proxy to set up proxying algorithm based on the same concept if the nginx algorithms.

https://gist.github.com/0442b11c35e6b94b9ed3a9567f3939de

Here are the policies associated with load balancing

Policies There are several load balancing policies available:

  • random (default) - Randomly select a backend
  • least_conn - Select backend with the fewest active connections
  • round_robin - Select backend in round-robin fashion
  • first - Select the first available backend in the order they are defined in the Caddyfile
  • ip_hash - Select backend by hashing the request IP, distributing evenly over the hash space based on the total number of backends
  • uri_hash - Select backend by hashing the request URI, distributing evenly over the hash space based on the total number of backends
  • header - Select by hashing the value of a given header, specified by the [value] after the policy name, distributing evenly over the hash space based on the total number of backends

Conclusion

It’s clear by now that I do love working with caddy, it's a simple tool that does the job so well, there are many options for web servers out there, but the benefits this server gives is quite exciting and worthwhile.

If you are looking to learn some more about it, feel free to check out the project on https://caddyserver.com.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment