What is Caddy?

Caddy is a server written in Go with a focus on simplicity. All you need to run it is the executable, no dependencies required. While webservers like Apache and Nginx are more mature and well documented, and can be more suited to large-scale deployments, Caddy can provide a great alternative for situations where the complexity of these solutions is either overkill or actively discouraged.

The most common use of Caddy is as a simple reverse proxy or webserver, which will be covered in this article, but it can get a lot more granular (e.g. load balancing) depending on your use case.

Installation

Caddy can be run using a downloaded executable, but for best functionality you should use your preferred package manager. For example, on Debian or Ubuntu, using sudo apt install caddy will also install the /etc/caddy/Caddyfile config file, and a systemd service that you can use systemd start caddy to more robustly run in the background.

If you have a different environment, or need more detailed instructions, refer to the [Caddy installation page]

Quick Start

Simple Reverse Proxy

Caddy can be used to manage requests made to your host

Example: Show your project running on port 9000 when you type localhost in your browser

NOTE: by default, web browsers request port 80 unless a different protocol like https:// is specified or a different port is specified

caddy reverse-proxy --from :80 --to :9000

Simple File Server

Caddy can host a file server to browse and access files from a public folder on your server. The below would allow access through your webbrowser at https://example.com (assuming you have the domain example.com directed to your host’s ip using a registration service)

caddy file-server --root /srv --domain example.com --browse

Caddy can also serve static websites (i.e. plain HTML/CSS/JS) by using the above command without the --browse flag

caddy file-server --root /srv --domain example.com

Caddyfile

While there do exist ways to tackle configuration using other formats, the most common (and easiest) way to do so is through the Caddyfile. All configuration you’ll ever need to do can be done through it, though you can always keep different aspects of what you’re doing in separate files and import them as necessary if your project is better organized that way.

Common Caddy Subcommands

The following commands will default to reading /etc/caddy/Caddyfile. A different location can be specified using the --config flag. Full documentation on using can be found at https://caddyserver.com/docs/command-line

caddy validate

caddy run

caddy start and caddy stop

Caddyfile Examples

NOTE: The following examples assume your frontend and backend are running on the same machine caddy is running on, with your frontend on port 8080 and your backend on port 9000

Example: Serving API and frontend from the same machine, accessed through different subdomains

# No port specified will default to port 80 for HTTP
# And port 443 for HTTPS 
example.com {
        reverse_proxy localhost:8080
}

api.example.com {
        reverse_proxy localhost:9000
}

Example: Serving API from specific path through a single domain/subdomain

example.com {
    # Caddy will stop at the first match

    # * indicates that it is not an exact path, 
    # and to enable partial-matching
    reverse_proxy /api/* localhost:9000

    # no path given is equivalent to *, in other words a catch-all
    reverse_proxy localhost:8080
}

Going Farther with the Caddyfile

Syntax

The Caddyfile is written in its own syntax which is similar to a mix between YAML and JSON (Both of which can be used instead if desired), but will not be covered by this guide

Global Options Block

A curly-brace block with nothing before it is used for global options, and will apply to everything else in your configuration.

{
    # Caddy by default will handle HTTPS certificates renewal and redirecting HTTP to HTTPS,
    # but in a development environment this might not be what we want, so this option will turn
    # those features off
    auto_https off
}
{
    # Alternatively, we could have everything served by internal local certs
    # https://caddyserver.com/docs/caddyfile/directives/tls#internal
    local_certs
    tls internal
}

Addresses

In the context of a Caddyfile, an Address is the part of what is specifically being requested by the requestor (e.g. what is entered into a web browser URL bar, or what is provided by the Host header of an HTTP request) that identifies the host, and can be simplified in a few ways. The following are all valid addresses by Caddy per the documentation:

As you can see, the protocol (HTTP vs HTTPS) and port (:8080) can be specified

Single Address in File

When using Caddy to serve content from a single Address, e.g. localhost, no brackets around the options provided to the Address are required. Simply type your Address at the top of the file, and list options (known as directives) line by line.

Example: Both of the following are complete Caddyfiles that will do the same thing as the first example on this page

localhost {
    reverse_proxy :9000
}
# since this Caddyfile only involves one Address (localhost), we can put the options for it on new lines and avoid brackets!
localhost

reverse_proxy :9000

Example: Caddyfile version of the Simple File Server

# Any desired global options can go here
{
}

# address by which to access Caddy
# normally the options below this would need to be enclosed
# in a {} block following the Address, but since this file
# only involves this one, we can keep the options as new lines 
localhost 

# Brackets ARE needed to specify multiple arguments to individual directives. 
file_server {
    
    # sets the file_server to serve from this folder
    root * /srv 

    # hides hidden folders in the root directory (but not sub-folders)
    hide .*

    # instructs Caddy to generate and serve 
    # a browsable index of files rather than 
    # making our own 
    browse
}