DEV Community

Cover image for Getting started with caddy web server
Osita Chibuike for Legobox

Posted on • Edited on

Getting started with caddy web server

The piece was originally published on my blog at legobox

Background

Last year I came across a server called caddy, I kinda liked it because it's 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 it's 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 good understanding of servers and proxying.
  • A general understanding of SSL - Secure Shell Layer and HTTPs

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:

    sudo cp /path/to/caddy /usr/local/bin
    sudo chown root:root /usr/local/bin/caddy
    sudo chmod 755 /usr/local/bin/caddy
Enter fullscreen mode Exit fullscreen mode

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


    sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy
Enter fullscreen mode Exit fullscreen mode

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

    sudo groupadd -g 33 www-data
    sudo useradd \
      -g www-data --no-user-group \
      --home-dir /var/www --no-create-home \
      --shell /usr/sbin/nologin \
      --system --uid 33 www-data

    sudo mkdir /etc/caddy
    sudo chown -R root:www-data /etc/caddy
    sudo mkdir /etc/ssl/caddy
    sudo chown -R root:www-data /etc/ssl/caddy
    sudo chmod 0770 /etc/ssl/caddy
Enter fullscreen mode Exit fullscreen mode

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


    sudo cp /path/to/Caddyfile /etc/caddy/
    sudo chown www-data:www-data /etc/caddy/Caddyfile
    sudo chmod 444 /etc/caddy/Caddyfile
Enter fullscreen mode Exit fullscreen mode

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


    sudo mkdir /var/www
    sudo chown www-data:www-data /var/www
    sudo chmod 555 /var/www
Enter fullscreen mode Exit fullscreen mode

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:

    sudo cp -R example.com /var/www/
    sudo chown -R www-data:www-data /var/www/example.com
    sudo chmod -R 555 /var/www/example.com
Enter fullscreen mode Exit fullscreen mode

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:

    example.com {
        root /var/www/example.com
        ...
    }
Enter fullscreen mode Exit fullscreen mode

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

    wget https://raw.githubusercontent.com/mholt/caddy/master/dist/init/linux-systemd/caddy.service
    sudo cp caddy.service /etc/systemd/system/
    sudo chown root:root /etc/systemd/system/caddy.service
    sudo chmod 644 /etc/systemd/system/caddy.service
    sudo systemctl daemon-reload
    sudo systemctl start caddy.service
Enter fullscreen mode Exit fullscreen mode

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

    sudo systemctl enable caddy.service
Enter fullscreen mode Exit fullscreen mode

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

    journalctl --boot -u caddy.service
Enter fullscreen mode Exit fullscreen mode

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:

    journalctl -f -u caddy.service
Enter fullscreen mode Exit fullscreen mode

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

    setfacl -m user:www-data:r-- /etc/ssl/private/my.key
Enter fullscreen mode Exit fullscreen mode

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://mydopesite.com {
      root /path/to/site_files
    }
Enter fullscreen mode Exit fullscreen mode

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):

    :2015                    # Host: (any), Port: 2015
    localhost                # Host: localhost; Port: 2015
    localhost:8080           # Host: localhost; Port: 8080
    example.com              # Host: example.com; Ports: 80->443
    http://example.com       # Host: example.com; Port: 80
    https://example.com      # Host: example.com; Ports: 80->443
    http://example.com:1234  # Host: example.com; Port: 1234
Enter fullscreen mode Exit fullscreen mode

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://mydomain.here{
      // usual structure is (proxy from to)
      proxy /api localhost:9005
    }
Enter fullscreen mode Exit fullscreen mode

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.

    proxy / web1.local:80 web2.local:90 web3.local:100 {
            policy round_robin
    }
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)