If you’re just as excited about Caddy 2.0 as I am, you probably can’t wait to install it. Unfortunately, there are some extra hoops you need to go through to install it on a FreeBSD 12.1 (or similar) server. In this tutorial, i’ll break down the steps to get you there.
Install go
Currently pkg
has version 1.13.5. But, we need 1.14 according to Caddy’s Github.
Luckily, the port for go
has been updated. So let’s download it and get it compiling!
First you’ll want to use portsnap fetch
to get the latest snapshot
portsnap fetch
Looking up portsnap.FreeBSD.org mirrors... 6 mirrors found.
Fetching public key from your-org.portsnap.freebsd.org... done.
Fetching snapshot tag from your-org.portsnap.freebsd.org... done.
Fetching snapshot metadata... done.
Fetching snapshot generated at Fri Mar 6 00:07:46 UTC 2020:
82ae2cbdbee69b4371b8b15b03b9f1ed1bc5da3955f46e 83 MB 22 MBps 04s
Extracting snapshot... done.
Verifying snapshot integrity...
Then extract go
and Mk
portsnap extract lang/go
portsnap extract Mk
portsnap extract Templates
Then start the compilation process!
cd /usr/ports/lang/go/ && make install clean
===> License BSD3CLAUSE accepted by the user
===> go-1.14_1,1 depends on file: /usr/local/sbin/pkg - found
=> go1.14.src.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://golang.org/dl/go1.14.src.tar.gz
...
This will take a few minutes depending the speed of your processor. You can make sure it’s installed by running go version
after the compilation has completed:
go version
go version go1.14 freebsd/amd64
Install caddy
Once installed, you’ll need to clone the Caddy repository. Place it in your GOPATH/src/
directory.
git clone "https://github.com/caddyserver/caddy.git"
git checkout v2.0.0-beta.15
Then change directories, make sure that GO111MODULE
is set and start the build!
cd caddy/cmd/caddy/
setenv GO111MODULE auto
go build
Once complete you should have a nice caddy
binary file in the caddy/cmd/caddy
directory:
./caddy
Caddy is an extensible server platform.
usage:
caddy <command> [<args...>]
commands:
adapt Adapts a configuration to Caddy's native JSON
build-info Prints information about this build
environ Prints the environment
file-server Spins up a production-ready file server
hash-password Hashes a password and writes base64
help Shows help for a Caddy subcommand
list-modules Lists the installed Caddy modules
reload Changes the config of the running Caddy instance
reverse-proxy A quick and production-ready reverse proxy
run Starts the Caddy process and blocks indefinitely
start Starts the Caddy process in the background and then returns
stop Gracefully stops a started Caddy process
validate Tests whether a configuration file is valid
version Prints the version
Use 'caddy help <command>' for more information about a command.
Booya!
Finally you should copy it over to /usr/local/bin/
or similar depending on how your system is set up. If you’re using a jail management software like Bastille, you can use the cp
command:
bastille cp caddyjail ./caddy /usr/local/bin/
This will copy over your binary to the jail of your choice. In this case i’m transferring to a jail called caddyjail
.
Starting caddy
on boot
If you want to start caddy
on startup (or as a service) you’ll need to install an rc.d
script. Here’s an example of one i’ve borrowed and modified (credit to riggs
for the original!)
# $FreeBSD: head/net/caddy/files/caddy.in 452063 2017-10-14 12:58:24Z riggs $
#
# PROVIDE: caddy
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# caddy_enable (bool): Set to NO by default.
# Set it to YES to enable caddy.
# caddy_user (user): Set user to run caddy.
# Default is "caddy".
# caddy_group (group): Set group to run caddy.
# Default is "caddy".
# caddy_conf (path): Path to caddy configuration file.
# Default is /usr/local/etc/caddyfile.conf
. /etc/rc.subr
name=caddy
rcvar=caddy_enable
load_rc_config $name
: ${caddy_enable:="NO"}
: ${caddy_user:="caddy"}
: ${caddy_group:="caddy"}
: ${caddy_conf:="/usr/local/etc/caddyfile.conf"}
: ${caddy_log:="/home/caddy/caddy.log"}
: ${caddy_env:="CADDYPATH=/home/caddy/"}
: ${caddy_https_port:="4443"}
: ${caddy_http_port:="8880"}
pidfile=/var/run/caddy.pid
procname="/usr/local/bin/caddy"
command="/usr/sbin/daemon"
command_args="-f -p ${pidfile} /usr/bin/env ${caddy_env} ${procname} -agree -http-port ${caddy_http_port} -https-port ${caddy_https_port} -conf=${caddy_conf} -log=${caddy_log} ${caddy_args}"
start_precmd=caddy_startprecmd
caddy_startprecmd()
{
if [ ! -e ${pidfile} ]; then
install -o ${caddy_user} -g ${caddy_group} /dev/null ${pidfile};
fi
}
run_rc_command "$1"
You can place it in /usr/local/etc/rc.d/caddy
. Then add it to your boot up using sysrc
:
sysrc caddy_enable="YES"
Or you can edit /etc/rc.conf
directly. The choice is yours.
If you’re using Bastille, you can also run bastille sysrc caddyjail caddy_enable="YES"
to accomplish the same for the jail.
Note: because I’m running caddy
in a jail, i’ve changed the https port and http port to 4443
and 8880
respectively. That way you can forward connections on 443
and 80
using your pf
firewall. Example below:
ext_if="vtnet0"
# ! IMPORTANT: this needs to be set before it's copied.
ext_addr=<your server ip>
# Caddy related
caddy_addr=<address of your caddy jail>
set block-policy return
scrub in on $ext_if all fragment reassemble
set skip on lo
table <jails> persist
nat on $ext_if from <jails> to any -> $ext_addr
# container routes
rdr pass inet proto tcp from any to port 80 -> $caddy_addr port 8880
rdr pass inet proto tcp from any to port 443 -> $caddy_addr port 4443
# Enable dynamic rdr (see below)
rdr-anchor "rdr/*"
block in all
pass out quick modulate state
antispoof for $ext_if inet
pass in inet proto tcp from any to any port ssh flags S/SA keep state
# make sure you also open up ports that you are going to use for dynamic rdr
pass in inet proto tcp from any to any port 80 flags S/SA keep state
pass in inet proto tcp from any to any port 443 flags S/SA keep state
Even if you’re not running it in a jail, you’ll likely want to forward privileged ports to non-priviledged ones.
Final Configuration
Additionally, you may need ca_root_nss
installed. Simply run pkg install ca_root_nss
on your target system/jail. You can also use bastille pkg caddyjail install ca_root_nss
You also may have noticed in the rc.d script, we’re using a caddy
user to run caddy. You can set that up by using the pw
command:
pw useradd caddy -m -s /usr/sbin/nologin
Or with Bastille like so:
bastille cmd caddy pw useradd caddy -m -s /usr/sbin/nologin
This will create a user that can’t log in but can be used to help “sandbox” the caddy daemon even further.
Finally, the rc.d
script is expecting a configuration file in /usr/local/etc/caddyfile.conf
You should place your configuration file here.
Finally start your caddy service using service
:
service caddy start
By default logs go to /home/caddy/caddy.log
. You can run tail -f /home/caddy/caddy.log
to watch the server boot up. If you are using TLS, Caddy will attempt to get your certificate. As long as port 80
& 443
are unblocked, you should be good to go!
Conclusion
In this very quick and dirty tutorial, you’ve learned how to compile and install Caddy on FreeBSD 12.1. At this point you should be ready to customize, add domains and more. So let the fun begin!
Last Modified: 2020.3.7