Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Full caddy production environment in a single command. #388

Closed
calebmer opened this issue Dec 5, 2015 · 45 comments
Closed

Full caddy production environment in a single command. #388

calebmer opened this issue Dec 5, 2015 · 45 comments
Labels
CI/CD 🔩 Automated tests, releases discussion 💬 The right solution needs to be found

Comments

@calebmer
Copy link

calebmer commented Dec 5, 2015

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:

  1. Add environment variables from a local .env file (see the node dotenv package for more information, although it is using the bash script formatting options).
  2. Redirect caddy output to a log file.
  3. Run caddy in the background so it persists after ending an SSH session.

Are these things possible? Is nohup the right way to run caddy in production?

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

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.

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

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.

@klingtnet
Copy link

SystemD Service

  • create the service file:
cat <<EOF > /etc/systemd/system/caddy@.service
[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
  • reload the systemd daemon: systemctl daemon-reload
  • start the service: systemctl start caddy@someuser
  • enable it (to start it automatically on boot): systemctl enable caddy@someuser

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

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.

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

Good suggestion...

@matthewp
Copy link

matthewp commented Dec 5, 2015

@klingtnet will that work and start on ports 80 and 443 with a regular user?

@mholt
Copy link
Member

mholt commented Dec 5, 2015

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.

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

@mholt but that's something most of your target users will eventually want to do. Adding start/stop commands would fulfill most basic cases.

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

@DenBeke using upstart, where is the .caddy folder supposed to go?

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

.caddy folder?

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

Where lets encrypt key pairs go. Normally it's in the home folder (~/.caddy).

@klingtnet
Copy link

@matthewp If you have run setcap cap_net_bind_service=+ep $(which caddy) beforehand, then yes.

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

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, ...?

@klingtnet
Copy link

I could setup an AUR repository for Arch Linux if someone is interested.

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

@DenBeke it seems $HOME is an empty string in the upstart script, should I put it at root?

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

@calebmer How do you mean?

@calebmer
Copy link
Author

calebmer commented Dec 5, 2015

@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?

@abiosoft
Copy link

abiosoft commented Dec 5, 2015

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

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

@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...

@abiosoft
Copy link

abiosoft commented Dec 5, 2015

@DenBeke I'd love your help 👍

@mholt
Copy link
Member

mholt commented Dec 5, 2015

I don't know if this will be helpful, but https://getcaddy.com

@DenBeke
Copy link

DenBeke commented Dec 5, 2015

That's a good starting point, @mholt!
Together with that we should install service files (matching the system), set cap, ...

@alexbilbie
Copy link

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

@justrjlewis
Copy link

Got this working on my FreeBSD Server: https://gist.github.com/justrjlewis/a3b4c36767a98b8b3c75

@faddat
Copy link
Contributor

faddat commented Feb 8, 2016

@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....)

@mholt
Copy link
Member

mholt commented Feb 8, 2016

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.

@jungle-boogie
Copy link

@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.

@basbebe
Copy link

basbebe commented Feb 9, 2016

@jungle-boogie that would be great!

@justrjlewis
Copy link

@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! 👍

@jungle-boogie
Copy link

Thanks, @justrjlewis

@andyjeffries
Copy link

@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"

@klingtnet
Copy link

@andyjeffries

wget -qO - getcaddy.com works fine. curl needs the L switch to follow redirects:

curl -L getcaddy.com | bash

@andyjeffries
Copy link

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.

@abiosoft
Copy link

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.

@mholt
Copy link
Member

mholt commented Feb 19, 2016

Thanks for the reminder; will update that soon.

@justrjlewis
Copy link

Hey guys! FYI: new freebsd service script. I haven't tried it yet, but looks legit. 👍
https://www.davd.eu/posts/caddy-freebsd-init-script/

@dstapp
Copy link

dstapp commented Mar 5, 2016

@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.

@justrjlewis
Copy link

@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.

@jungle-boogie
Copy link

Yeah, with freeBSD you can use jails or MAC port access until Caddy can support some kind of privileg dropping: #528

@dstapp
Copy link

dstapp commented Mar 5, 2016

@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.

@mholt
Copy link
Member

mholt commented Mar 5, 2016

@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.

@mholt
Copy link
Member

mholt commented Mar 16, 2016

@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.

@klingtnet
Copy link

@mholt Great! I will review my SystemD service file tomorrow and create a PR.

@dstapp
Copy link

dstapp commented Mar 17, 2016

@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.

@mholt
Copy link
Member

mholt commented Mar 21, 2016

Yay, we've got two now.

I also welcome discussion on how to improve getcaddy.com without getting too crazy about it. 😄

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.

@mholt mholt closed this as completed Mar 21, 2016
@mholt mholt added discussion 💬 The right solution needs to be found CI/CD 🔩 Automated tests, releases labels Mar 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI/CD 🔩 Automated tests, releases discussion 💬 The right solution needs to be found
Projects
None yet
Development

No branches or pull requests