Our website is made possible by displaying online advertisements to our visitors. Please consider supporting us by disabling your ad blocker.

Serve Your Web Applications With Minimal Effort Using Caddy

TwitterFacebookRedditLinkedInHacker News

I’ve been in the web game for quite some time and have my fair share of web server software. I’ve used Microsoft’s Internet Information Services (IIS), Apache httpd, as well as NGINX, and while they all thrive in their own ways, they’ve been overkill for most of my use cases. This is where Caddy comes in, a lightweight alternative to these seasoned, but often heavy web servers.

We’re going to see how to use Caddy and learn why it is so powerful while using minimal effort on a developer operations side.

Understanding the Caddy Basics

If you’ve been keeping up with the blog, you’ll remember that this isn’t the first time I talked about Caddy. I actually interviewed its creator, Matt Holt, on a podcast episode titled, The Go Programming Language and Modern Development. If you haven’t listened to the episode, I encourage you to check it out. However, from the title alone you can probably determine that Caddy was written using the Go programming language. Given the nature of Go, this means that a Caddy binary was cross-compiled to work on virtually every platform out there, including Mac, Windows, Linux and even Internet of Things (IoT). The cross-platform functionality is great, but what’s awesome is that it is a self contained application, meaning you have a Caddy binary and a site configuration file.

From a features perspective, Caddy offers the following:

  • HTTPS by default
  • Static as well as dynamic sites
  • A huge amount of plugins for functionality as well as third-party services
  • Caching and compression
  • Easy configuration on a per application basis

Of course those are not all the features, but they are the few that I found value in when having experienced them with other servers.

Let’s dig deeper into the easy configuration aspect of Caddy.

Each application that you serve will use what is known as a Caddyfile and it contains, in most scenarios, just a few lines of configuration data rather than the hundreds that you might find with NGINX or Apache httpd. Take a look at the example below:

*:8080 {
    root /path/to/html

The above example is probably the most basic Caddyfile file you can have. It is saying to listen on port 8080 and serve content at the listed path.

Alright, let’s add a little complexity to the configuration file:

*:8080 {
    root /path/to/html
    errors {
        404 404.html
    expires {
        match .html$ 1d
        match .xml$ 1d
        match .json$ 1d
        match .js$ 1w
        match .css$ 1w
        match .png$ 1w
        match .jpg$ 1w
        match .gif$ 1w
        match .svg$ 1w
        match .ogg$ 1m
        match .ttf$ 1m
        match .otf$ 1m
        match .woff$ 1m
        match .eot$ 1m

We’ve changed the configuration a bit. This time we are compressing the server responses, defining a landing page for any 404 errors, and defining cache expiration times for various file extensions.

A full list of the configurations that you can add to your Caddyfile file can be found in the official documentation.

Deploying an Application with Caddy as Stand-Alone or with Docker

So we have our Caddyfile file created, now we might want to use it to serve our application either directly on the host or within a Docker container.

The easiest thing to do would be to run Caddy from the Terminal:


The above command assumes that you’re in the same directory as your Caddyfile file. If you’re not, then it will use the bare minimum to serve your application, kind of like how Python does it. You could also execute the following:

caddy -conf /path/to/Caddyfile

Not difficult as of now, correct?

Let’s take a look at the Docker approach to deploying a web application with Caddy. Assuming that you’ve got Docker installed and configured, create a Dockerfile with the following:

FROM alpine:latest

RUN apk add --no-cache openssh-client tar curl
RUN curl --silent -o - "https://caddyserver.com/download/linux/amd64?license=personal" | tar --no-same-owner -C /usr/bin/ -xz caddy
RUN chmod 0755 /usr/bin/caddy

EXPOSE 80 443


COPY . /srv/

ENTRYPOINT /usr/bin/caddy

The above blueprint will use the very sleek and very slim Alpine Linux. It will install the necessary dependencies and obtain Caddy via a cURL command. The same command will drop Caddy into a more appropriate directory and then give it the correct permissions.

Assuming the Dockerfile file is in the same directory as our Caddyfile file and our web content to be served, it will all be copied into a /srv directory in the Docker image. When we deploy the image as a container, Caddy will run, using the transferred Caddyfile configuration file.

We can build a Docker image with the following command:

docker build -t caddy-project .

The above command will create an image called caddy-project using the contents of the current working path. To deploy our image as a container we could do the following:

docker run -d -p 80:8080 --name caddyproject caddy-project

The above command will port map 80 on the host to 8080 in the container. This assumes that 8080 is the port in the Caddyfile file.

Still not so bad, correct?


While I didn’t go into intense amounts of detail on what you can do with Caddy, take my word on it that Caddy is a powerful tool and a great alternative to some of the other software out there such as NGINX and Apache httpd. You can do a lot with a little when it comes to Caddy and that is why I like it so much. Gone are the days where you have to be an expert with system administration and developer operations. Instead you can take an easy to understand configuration file and deploy your application with minimal effort.

Nic Raboy

Nic Raboy

Nic Raboy is an advocate of modern web and mobile development technologies. He has experience in C#, JavaScript, Golang and a variety of frameworks such as Angular, NativeScript, and Unity. Nic writes about his development experiences related to making web and mobile development easier to understand.