There are a couple of steps I need to take to start up a caddy server in production:
$ sudo -s
$ source .env
$ nohup caddy >> logs/out.log &
Is there a way to minimize this into one command?
$ sudo caddy
Or maybe add a few new daemon style commands like:
$ caddy start
$ caddy logs
$ caddy stop
$ caddy logs https://example.org
$ caddy stop https://example.org
It would need to do the following which I currently do manually:
.env
file (see the node dotenv package for more information, although it is using the bash script formatting options).Are these things possible? Is nohup
the right way to run caddy in production?
Make a service of it... (either systemd or upstart).
I have created both an upstart and systemd script, maybe I can also share the second one, but I haven't got much experience with systemd.
Btw: why running Caddy as root? You can bind to port 80 as a normal user by using setcap
From the readme:
Running as root: We advise against this; use setcap instead, like so:
setcap cap_net_bind_service=+ep ./caddy
This will allow you to listen on
ports < 1024 like 80 and 443.
If you want to stick to nohup
you could create a 'start' script that writes the process id to a file, and then create a 'stop' script that reads the pid from the file and kills it.
cat <<EOF > /etc/systemd/system/[email protected]
[Unit]
Description=Caddy HTTP/2 web server %I
Documentation=https://caddyserver.com/docs
After=network.target
[Service]
User=%i
Environment=STNORESTART=yes
ExecStart=/usr/sbin/caddy -agree=true -conf=/etc/caddy/Caddyfile
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl start caddy@someuser
systemctl enable caddy@someuser
Thanks guys, this is seriously really helpful. However, if caddy wants to be the easiest solution to integrate, maybe it's worth considering abstracting this process?
Or at least put a tutorial somewhere with instructions for deploying a caddy server.
Good suggestion...
@klingtnet will that work and start on ports 80 and 443 with a regular user?
Deploying an application is very different from serving websites; I don't want to get into that business... sounds more like sysadmin work.
But perhaps we could post some examples to the caddyserver/examples repo in a new folder called "deployment" or something, since it's a common enough question.
@mholt but that's something most of your target users will eventually want to do. Adding start/stop commands would fulfill most basic cases.
@DenBeke using upstart, where is the .caddy
folder supposed to go?
.caddy
folder?
Where lets encrypt key pairs go. Normally it's in the home folder (~/.caddy
).
@matthewp If you have run setcap cap_net_bind_service=+ep $(which caddy)
beforehand, then yes.
Deploying an application is very different from serving websites; I don't want to get into that business... sounds more like sysadmin work.
Can't we have Caddy in the package managers? Or an install script which downloads caddy, detects the correct init system, creates the correct start files, ...?
I could setup an AUR repository for Arch Linux if someone is interested.
@DenBeke it seems $HOME
is an empty string in the upstart script, should I put it at root?
@calebmer How do you mean?
@DenBeke caddy wants to put all of the lets encrypt configuration into $HOME/.caddy
, however $HOME
is not defined in the upstart script/end script portion. What do I do? Does caddy allow me to reconfigure where that directory goes? Should I put the .caddy
folder at root to reflect that $HOME
is empty? Do I define $HOME
as the caddy user's home?
Can't we have Caddy in the package managers? Or an install script which downloads caddy, detects the correct init system, creates the correct start files, ...?
I am with @DenBeke on this. I think this needs to happen for greater adoption.
e.g. on Ubuntu
$ sudo apt-get install caddy
@abiosoft I'm afraid the Ubuntu packages won't be quickly enough released, so apt-get will always be an older version. Arch is much faster in this.
For now a bootstrap script is maybe the most easy solution. I can help with this...
@DenBeke I'd love your help :+1:
I don't know if this will be helpful, but https://getcaddy.com
That's a good starting point, @mholt!
Together with that we should install service files (matching the system), set cap, ...
This is the (SysV?) init script I'm using at /etc/init.d/caddy
#!/bin/bash
# Caddy daemon
# chkconfig: 345 20 80
# description: Caddy daemon
# processname: caddy
DAEMON_PATH="/usr/local/bin"
DAEMON='./caddy'
DAEMONOPTS="-conf=/etc/caddy/Caddyfile -log /var/log/caddy.log"
NAME=caddy
DESC="Caddy upstart"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
case "$1" in
start)
printf "%-50s" "Starting $NAME..."
cd $DAEMON_PATH
PID=`$DAEMON $DAEMONOPTS > /dev/null 2>&1 & echo $!`
echo "Saving PID" $PID " to " $PIDFILE
if [ -z $PID ]; then
printf "%s\n" "Fail"
else
echo $PID > $PIDFILE
printf "%s\n" "Ok"
fi
;;
status)
printf "%-50s" "Checking $NAME..."
if [ -f $PIDFILE ]; then
PID=`cat $PIDFILE`
if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then
printf "%s\n" "Process dead but pidfile exists"
else
echo "Running"
fi
else
printf "%s\n" "Service not running"
fi
;;
stop)
printf "%-50s" "Stopping $NAME"
PID=`cat $PIDFILE`
cd $DAEMON_PATH
if [ -f $PIDFILE ]; then
kill -HUP $PID
printf "%s\n" "Ok"
rm -f $PIDFILE
else
printf "%s\n" "pidfile not found"
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {status|start|stop|restart}"
exit 1
esac
Got this working on my FreeBSD Server: https://gist.github.com/justrjlewis/a3b4c36767a98b8b3c75
@mholt
I am puzzled beyond belief at your sysadmin vs serving websites comment. What is it you think that sysadmins do?
(NOT trolling: Definitely want to start a dialogue....)
I'm going to leave it up to the sysadmin to decide how he/she wants to run Caddy. All I meant by that comment is that Caddy serves websites, and I don't want the scope to creep up to the system environment level where it configures a system so it can run a certain way.
@justrjlewis, thank for the start up script! I'm considering attempting to make caddy a port/package with freeBSD and that will help out a lot.
@faddat, not everyone uses systemd and/or linux, and I'd rather a specific OS determine how to startup a process when it's installed in the OS.
@jungle-boogie that would be great!
@jungle-boogie That script needs some work - it's got some bugs. I haven't had a chance to jump back into it, but let me know if you come up with any changes! :+1:
Thanks, @justrjlewis
@mholt the comments at the top of https://getcaddy.com are wrong. It says:
# $ curl getcaddy.com | bash
# or
# $ wget -qO- getcaddy.com | bash
These now need to be:
# $ curl https://getcaddy.com | bash
# or
# $ wget -qO- https://getcaddy.com | bash
Or it fails saying "bash: line 1: a: No such file or directory"
@andyjeffries
wget -qO - getcaddy.com
works fine. curl needs the L
switch to follow redirects:
curl -L getcaddy.com | bash
OK. I'd already got past it, so it was more of a nudge so that "getcaddy.com" is updated and more people don't hit this. Thanks though.
I'd go with the https://
ones.
It is bad enough that it pipes directly to bash, the link being plain http will further put one off.
Yeah, I'm aware it will redirect to https and I know many apps still use this as default way of installation. Just thinking as a random cautious first time user.
Thanks for the reminder; will update that soon.
Hey guys! FYI: new freebsd service script. I haven't tried it yet, but looks legit. :+1:
https://www.davd.eu/posts/caddy-freebsd-init-script/
@justrjlewis I didn't recognize you already made a service script, otherwise I would've saved me the hassle ;-) I enhanced my script so that you could change the user the process runs on. Please let me know if there are further issues in case you decide to use it. What I would love to see is privilege dropping within Caddy because running a webserver as root user is a pain in the ass, especially on FreeBSD where setcap
is not really an option (at least as I'm aware of). I've now accomplished the permission issue by jailing the server but generally - having packages for both Linux and FreeBSD that provide anything to run Caddy in production including security concerns would be great. If anyone has motivation towards doing that for FreeBSD (either as a port or for pkgng) I'd like to help.
@dprandzioch
No worries. I'm anxious to try your implementation. I never thought of outputting the the log file, CPU settings, or testing for the email. Also, my script doesn't include a status message, so cool. I can't wait to play with it!
If you change your port binding, you can run as your caddy user.
The freebsd code is in the handbook under 15.5.4. The MAC Port Access Control List PolicyThe MAC Port Access Control List Policy
What I didn't get at first was that you have to use ALL of those commands, so it boils down to this:
net.inet.ip.portrange.reservedlow=0
net.inet.ip.portrange.reservedhigh=0
security.mac.portacl.port_high=1023
security.mac.portacl.suser_exempt=1
security.mac.portacl.rules=uid:[uid for desired user]:tcp:80,uid:[uid for desired user]:tcp:443,etc...
What I plan to work on, is updating the Caddy docs to be as platform agnostic as the server itself. It's early days, but for my mind doing that and having tons of examples for people is the key long term growth. I would love to see Caddy added to the package manager. I'm still new to freebsd myself and have four huge projects to finish up before I start playing with my freebsd box again, but message me if you start before I do. Also, check with @jungle-boogie - he may already be working on something.
Yeah, with freeBSD you can use jails or MAC port access until Caddy can support some kind of privileg dropping: https://github.com/mholt/caddy/issues/528
@justrjlewis Thanks you so much, I already tried to figure out to get this running but didn't succeed until now. :-)
@jungle-boogie Just added my 2c to #528. I'm currently running Caddy jailed anyway but'd rather prefer a native implementation that's just as self-contained as Caddy itself is. Anyway, I think it's better keeping that separate in the other bug report :-)
However, is there any development going on regarding providing Caddy packages for various Linux / BSD systems? I think that will be interesting for many people for the long run, including sample configuration (however the current documentation is very good anyway) and most certainly an init script for systemd/rc.d (I think sysvinit and upstart can be dropped by now as the most Linux distros are migrating to systemd just to not make it more complicated as it needs to be?). On the other hand this kind of reduces the portability of that single statically-linked executable that I like so much but I think especially when it comes to larger production deployments you might wanna have more framework around the webserver itself.
@dprandzioch There is some effort and definitely a lot of interest in distributing Caddy via system packages; anyone is welcome to step up to the plate in #395, where I invite anyone who would like to to be involved in that way.
@justrjlewis @jungle-boogie @alexbilbie @klingtnet @calebmer @DenBeke (phew!) There is now a folder in dist/init where we are assembling "init" scripts. These are not officially part of the project, but if you would like to add your own to that folder (and keep them maintained if they change, please), we'd really appreciate it! Thanks to David for that PR above with the idea.
When you submit your script, please include a brief paragraph in the README there about how to use it. Preferably, comment your script/config it so it can be customized easily, but choose sensible defaults. Also please include your GitHub username or email address so people can ask you their questions.
@mholt Great! I will review my SystemD service file tomorrow and create a PR.
@mholt I'm happy that this one finally made it into the repository. I'll try create a PR, commenting my init script as soon as possible.
Yay, we've got two now.
I also welcome discussion on how to improve getcaddy.com without getting too crazy about it. :smile:
I'm going to close this issue. Feel free to continue the discussion though, and remember that you can add your own scripts to dist/init! Pull requests welcome.
Most helpful comment
SystemD Service
systemctl daemon-reload
systemctl start caddy@someuser
systemctl enable caddy@someuser