HTTPS out of the box with the Caddy secure web server

Simply Secure

Lead Image © stockers9,

Lead Image © stockers9,

Article from Issue 213/2018
Author(s): , Author(s):

Caddy lets even the most inexperienced user set up a secure web server.

After hundreds of high-profile attacks on large and small websites, the web world is gradually giving up on old-fashioned, unsafe, unencrypted HTTP and is moving to the safer, encrypted variant known as HTTPS. HTTPS is based on the SSL/TSL protocols, which means you need to install, maintain, and regularly renew digital certificates for the website. The certificates are only valid for a limited period, which can vary between three months to 10 years, depending on the certificate authority.

All the major web servers, such as the Apache HTTP server, Microsoft's Internet Information Services (IIS), and Nginx, provide some means for HTTPS support, but the configuration steps are often complicated and more trouble than you need, especially if you just operate a small website.

Caddy [1] is a simple and easy web server that delivers simple and convenient HTTPS support. Caddy uses the Let's Encrypt [2] project for easy access to free digital certificates. (See the box titled "Simply Encrypted.") Caddy also includes support for HTTP/2 (see "From HTTP 1.1 to HTTP/2"), and it comes with other useful features, such as support for the Markdown and AsciiDoc formatting languages.

From HTTP 1.1 to HTTP/2

Version 2.0 of HTTP [3] was released in February 2015. HTTP/2, which is described in RFC 7540 [4], has been gradually replacing HTTP 1.1 since 1997. Evaluations of WWW data traffic revealed a 20 percent share of HTTP/2 traffic at the end of 2017. HTTP/2 comes with a number of innovations, including data compression of the HTTP headers and parallel execution of requests with a single TCP connection ("pipelining"). In general, the protocol aims to make better use of the available computing power and to minimize the time required to transmit a request.

Simply Encrypted

The Let's Encrypt project is the first major initiative of the non-profit organization Internet Security Research Group (ISRG). The goal of the ISRG is to make encrypted WWW connections the standard; in other words, HTTPS for everyone. Let's Encrypt uses domain validation certificates for encryption. To check whether the person submitting a certification request actually owns the domain, Let's Encrypt creates and sends a token to the requesting domain. This step is followed by a web or DNS query, in which the domain is verified using a key derived from this token. This ensures that the content actually originates from the operator of the website. Let's Encrypt also offers the greatest possible transparency for its own trustworthiness. The project uses free software and open standards, in combination with the regular publication of transparency reports. To date, the project has already issued certificates for 63 million domains.

Caddy is written in the Go programming language, and it is available as a free community version for private use. If you want to use the web server commercially, the developers would be happy to receive a one-off payment of $25. The project is licensed under Apache 2.0.

This article is adapted to Debian 9 and is partly based on a blog post by Supriyo Biswas [5].


Caddy is available for Linux, Windows, many BSD variants, and Mac OS. The Caddy developers do not provide separate versions for different Linux distributions. In the download area of the website, a configurator helps you select the appropriate binary for your system, as well as plugins you might want to integrate (Figure 1). The software then generates a package to suit your needs.

Figure 1: On the project page, you define which extensions you want to include with the software.

If you prefer to set up Caddy at the command line, say, for use on a headless system, first pick up a shell script from the Caddy project website (Listing 1, line  1), make it executable (line 2), and download the desired software image (line 3) by calling the script. You can specify additional plugins in the call as comma-separated parameters (line 4). Table 1 shows a small selection of available extensions.

Listing 1

Get Caddy

# wget -O getcaddy
# chmod +x getcaddy
# ./getcaddy personal
# ./getcaddy personal http.ipfilter,http.cache

Table 1

Caddy Plugins


Dynamic DNS, for example, via Cloudflare


Caching for HTTP


Extension with CGI scripts


Setting an expiration date


Publication/updates via git commands


Block access by selected IP addresses


Extension for WebDAV

Basic Setup

To test the functionality, first create an index.html file in the current directory; this file consists only of the HTML header and the body "Hello World." Then, launch Caddy by typing ./caddy in the same directory. To access the page in the web browser, use either the IP address of the host or localhost or and add port number 2015, on which Caddy listens for HTTP requests without any further settings (Figure 2).

Figure 2: The website for the functionality test and the call in the web browser.

To secure Caddy and set it up as a system service, create a separate account for Caddy, then assign it a home directory of /opt/caddy/ with the -rmd option (Listing 2, first line). This directory also contains the configuration files and the actual content of the website.

Listing 2

Securing Caddy

# useradd -rmd /opt/caddy caddy
# mkdir /opt/caddy/{store,logs,web}
# chown -R caddy: /opt/caddy

You'll need to create the three subdirectories store, logs, and web (Listing 2, second line); store contains – among other things – the SSL certificates, log contains the logfiles for the web server, and web contains the actual website. To make sure that Caddy can access it, assign the three directories to the previously created caddy account (Listing 2, last line).

Next, copy the previously created index.html file to /opt/caddy/web/. Caddy now needs some help in the form of a configuration file to find the contents. You can choose the name of the configuration file – in this article, the file is called /opt/caddy/caddy.config. Enter the contents from Listing 3, which is the configuration for a single website on the local computer.

Listing 3

Configuring a Website

01 http:// {
02   root /opt/caddy/web/default
03   log /opt/caddy/logs/default.log
04   gzip
05 }

Line 1 is for serving up HTTP content on port 80; line 2 defines the root directory of the website, and line 3 defines the corresponding logfiles. Line  4 contains the Gzip module, which ensures that Caddy delivers compressed HTML and text files. With the performance of today's systems, compression causes only a minimal delay, which more than compensates for the transmission time saved.

If you want to provide multiple web services on the system, you need to create a separate block for each service. In Listing  4, the third code block describes a web server that delivers its data via port 8080. All you need to do is enter :8080 after the domain name.

Now you need to set up Caddy as a regular service. For systems with a systemd, create a separate entry in the /etc/systemd/system/caddy.service file (Listing 5). In the Unit section, name the service and enter a description. The Service section defines the user and group, the environment variables, the start parameters, what happens when the process is restarted, and the limits for the number of open files and parallel processes. The Install section determines the target or runlevel for which the service is available.

Listing 4

Multiple Sites

http:// {
  root /opt/caddy/web/default
  log /opt/caddy/logs/default.log
} {
  root /opt/caddy/web/out-of-space
  log /opt/caddy/logs/out-of-space.log
} {
  root /opt/caddy/web/on-the-road
  log /opt/caddy/logs/on-the-road.log

Listing 5


Description=Caddy HTTP/2 web server
06 User=caddy
ExecStart=/usr/local/bin/caddy    -agree=true    -log=/opt/caddy/logs/caddy.log    -conf=/opt/caddy/caddy.config    -root=/dev/null
ExecReload=/bin/kill -USR1 $MAINPID

Use the first two commands from Listing 6 to start the previously configured service and check whether it is running correctly (Figure 3). Then, visit the website and check its accessibility. This time Caddy is no longer listening on port 2015, but on the usual port 80 for HTTP.

Listing 6

Start the Service

# systemctl enable caddy.service
# systemctl status caddy.service
# systemctl restart caddy.service
Figure 3: The systemd status display tells you that Caddy is doing its job.

If you change the configuration at a later time, you need to restart the service, as shown in the last line of Listing  6.

Switching to HTTPS

Caddy impresses with its integration of Let's Encrypt for secure HTTPS connections. To add Let's Encrypt, you must have a domain. In the second block of Listing 4, change http to https in the first line. Then add line 5 to the block (Listing  7). Let's Encrypt informs you about changes in the certificate for HTTPS, especially before it expires and needs to be renewed.

Listing 7

Adding Let's Encrypt {
  root /opt/caddy/web/out-of-space
  log /opt/caddy/logs/out-of-space.log

You do not need an explicit statement for HTTP. All requests for this protocol will automatically switch to HTTPS on port 443. Now restart Caddy, and it will automatically connect to Let's Encrypt and set up a certificate.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More