This is the multi-page printable view of this section. Click here to print.
Servers
- 1: Caddy
- 1.1: Installation
- 1.2: Logging
- 1.3: WebDAV
- 1.4: MFA
- 1.5: Wildcard DNS
1 - Caddy
Caddy is a web server that runs SSL by default by automatically grabing a cert from Let’s Encrypt. It comes as a stand-alone binary, written in Go, and makes a decent reverse proxy.
1.1 - Installation
Installation
Caddy recommends “using our official package for your distro” and for debian flavors they include the basic instructions you’d expect.
Configuration
The easiest way to configure Caddy is by editing the Caddyfile
sudo vi /etc/caddy/Caddyfile
sudo systemctl reload caddy.service
Sites
You define websites with a block that includes a root
and the file_server
directive. Once you reload, and assuming you already have the DNS in place, Caddy will reach out to Let’s Encrypt, acquire a certificate, and automatically forward from port 80 to 443
site.your.org {
root * /var/www/site.your.org
file_server
}
Authentication
You can add basic auth to a site by creating a hash and adding a directive to the site.
caddy hash-password
site.your.org {
root * /var/www/site.your.org
file_server
basic_auth {
allen SomeBigLongStringFromTheCaddyHashPasswordCommand
}
}
Reverse Proxy
Caddy also makes a decent reverse proxy.
site.your.org {
reverse_proxy * http://some.server.lan:8080
}
You can also take advantage of path-based reverse proxy. Note the rewrite to accommodate the trailing-slash potentially missing.
site.your.org {
rewrite /audiobooks /audiobooks/
handle_path /audiobooks/* {
uri strip_prefix /audiobooks/
reverse_proxy * http://some.server.lan:8080
}
}
Import
You can define common elements at the top (snippets) or in files and import them multiple times to save duplication. This helps when you have many sites.
# At the top in the global section of your Caddyfile
(logging) {
log {
output file /var/log/caddy/access.log
}
}
site.your.org {
import logging
reverse_proxy * http://some.server.lan:8080
}
Modules
Caddy is a single binary so when adding a new module (aka feature) you are essentially downloading a new version that has them compiled in. You can find the list of packages at their download page.
Do this at the command line with caddy itself.
sudo caddy add-package github.com/mholt/caddy-webdav
systemctl restart caddy
Security
Drop Unknown Domains
Caddy will accept connections to port 80, announce that it’s a Caddy web server and redirect you to https before realizing it doesn’t have a site or cert for you. Configure this directive at the bottom so it drops immediately.
http:// {
abort
}
Crowdsec
Caddy runs as it’s own user and is fairly memory-safe. But installing Crowdsec helps identify some types of intrusion attempts.
Troubleshooting
You can test your config file and look at the logs like so
caddy validate --config /etc/caddy/Caddyfile
journalctl --no-pager -u caddy
1.2 - Logging
Access Logs
In general, you should create a snippet and import into each block.
#
# Global Options Block
#
{
...
...
}
#
# Importable Snippets
#
(logging) {
log {
output file /var/log/caddy/access.log
}
}
#
# Host Blocks
#
site.your.org {
import logging
reverse_proxy * http://some.server.lan:8080
}
other.your.org {
import logging
reverse_proxy * http://other.server.lan:8080
}
Per VHost Files
If you want separate logs for separate vhosts, add a parameter to the import that changes the output file name.
#
# Global Options Block
#
{
...
...
}
#
# Importable Snippets
#
(logging) {
log {
# args[0] is appended at run time
output file /var/log/caddy/access-{args[0]}.log
}
}
#
# Host Blocks
#
site.your.org {
import logging site.your.org
reverse_proxy * http://some.server.lan:8080
}
other.your.org {
import logging other.your.org
reverse_proxy * http://other.server.lan:8080
}
Wildcard Sites
Wildcard sites only have one block so you must use the hostname
directive to separate vhost logs. This both sends a vhost to the file you want, and filters them out of others. You can also use an import argument as shown in this caddy example to save space. (I would never have deduced this on my own.)
#
# Global Options Block
#
{
...
...
}
#
# Importable Snippets
#
(logging) {
log {
output file /var/log/caddy/access.log {
roll_size 5MiB
roll_keep 5
}
}
}
(domain-logging) {
log {
hostnames {args[0]}
output file /var/log/caddy/{args[0]}.log {
roll_size 5MiB
roll_keep 5
}
}
}
#
# Main Block
#
*.site.org, site.org {
# Everything goes to this file unless it's filtered out by another log block
import logging
@site host some.site.org
handle @site {
reverse_proxy * http://internal.site
}
# the www site will write to just this log file
import domain-logging www.site.org
@www host www.site.org
handle @www {
root * /var/www/www.site.org
file_server
}
# This site will write to the normal file
@site host other.site.org
handle @site {
reverse_proxy * http://other.site
}
Logging Credentials
If you want to track users, add a directive to the global headers.
#
# Global Options Block
#
{
servers {
log_credentials
}
}
File Permissions
By default, only caddy can read the log files. This is a problem when you have a log analysis package. In recent versions of caddy however, you can set the mode.
log {
output file /var/log/caddy/access.log {
mode 644
}
}
If the log file doesn’t change modes, check the version of caddy. It must be newer than v2.8.4 for the change.
Troubleshooting
You can have a case where the domain specific file never gets created. This usually happens when there us nothing to write to it. Check the hostname
is correct.
1.3 - WebDAV
Caddy can also serve WebDAV requests with the appropriate module. This is important because for many clients, such as Kodi, WebDAV is significantly faster.
sudo caddy add-package github.com/mholt/caddy-webdav
sudo systemctl restart caddy
{ # Custom modules require order of precedence be defined
order webdav last
}
site.your.org {
root * /var/www/site.your.org
webdav *
}
You can combine WebDAV and Directly Listing - highly recommended - so you can browse the directory contents with a normal web browser as well. Since WebDAV doesn’t use the GET method, you can use the @get
filter to route those to the file_server module so it can serve up indexes via the browse
argument.
site.your.org {
@get method GET
root * /var/www/site.your.org
webdav *
file_server @get browse
}
Sources
https://github.com/mholt/caddy-webdav https://marko.euptera.com/posts/caddy-webdav.html
1.4 - MFA
The package caddy-security offers a suite of auth functions. Among these is MFA and a portal for end-user management of tokens.
Installation
# Install a version of caddy with the security module
sudo caddy add-package github.com/greenpau/caddy-security
sudo systemctl restart caddy
Configuration
/var/lib/caddy/.local/caddy/users.json
caddy hash-password
Troubleshooting
journalctl –no-pager -u caddy
1.5 - Wildcard DNS
Caddy has an individual cert for every virtual host you create. This is fine, but Let’s Encrypt publishes these as part of certificate transparency and the bad guys are watching. If you create a new site in caddy, you’ll see bots probing for weaknesses within 30 min - without you even having published the URL. There’s no security in anonymity, but the need-to-know principle suggests we shouldn’t be informing the whole world about sites of limited scope.
One solution is a wildcard cert. It’s published as just ‘*.some.org’ so there’s no information disclosed. Caddy supports this, but it requires a little extra work.
Installation
In this example we are already using the default Caddy binary but want to connect to CloudFlare’s DNS service. We must change to a custom Caddy binary for that. Check https://github.com/caddy-dns to see if your DNS provider is available.
# Divert the default binary from the repo
sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy
sudo cp /usr/bin/caddy.default /usr/bin/caddy.custom
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50
# Add the package and restart.
sudo caddy add-package github.com/caddy-dns/cloudflare
sudo systemctl restart caddy.service
Warning:
Because we’ve diverted, apt update
will not update caddy. This also stops unattended-updates
. You must use caddy upgrade
instead. The devs don’t think this should be an issue. I disagree. but you can add a cron job if you like.
DNS Provider Configuration
For Cloudflare, a decent example is below. Just use the ‘Getting the Cloudflare API Token’ part
https://roelofjanelsinga.com/articles/using-caddy-ssl-with-cloudflare/
Caddy Configuration
Use the acme-dns
global option and then create a single site (used to determine the cert) and match the actual vhosts with subsites.
{
acme_dns cloudflare alotcharactersandnumbershere
}
*.some.org, some.org {
@site1 host site1.some.org
handle @site1 {
reverse_proxy * http://localhost:3200
}
@site2 host site2.some.org
handle @site2 {
root * /srv/www/site2
}
}