diff options
author | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-07-13 05:20:54 +0000 |
---|---|---|
committer | Luke Shumaker <lukeshu@sbcglobal.net> | 2016-07-13 05:20:54 +0000 |
commit | ed13bd129a85d8133137086adba56649b395444a (patch) | |
tree | 988df4180b086d46dbf315bb268d6e8041c51049 | |
parent | 2c363690324401c2edd40013f432113ae0d8354e (diff) |
add certbot and uwsgi configs
-rw-r--r-- | config-certbot.PKGBUILD | 189 | ||||
-rw-r--r-- | config-uwsgi.PKGBUILD | 61 |
2 files changed, 250 insertions, 0 deletions
diff --git a/config-certbot.PKGBUILD b/config-certbot.PKGBUILD new file mode 100644 index 0000000..acffa7a --- /dev/null +++ b/config-certbot.PKGBUILD @@ -0,0 +1,189 @@ +. ${BUILDFILE%/*}/common.sh +pkgver=20160713 + +depends=(certbot) + +package() { +cd "$pkgdir" + +# Winston uses the [certbot][] ACME client to get certificates from +# [Let's Encrypt][]. +# +# [certbot]: https://www.parabola.nu/packages/community/any/certbot/ +# [Let's Encrypt]: https://letsencrypt.org/ + +# All domains handled by the server are shoved in as Subject +# Alternative Names in a single certificate. This makes configuring +# nginx easier. + +# ## issuance, renewal, and installation + +# Unlike acmetool, certbot doesn't have an easy way of saying "please +# add this domain as a Subject Alternative Name". You have to re-run +# the same (long) command to get the cert, but with the domain added. +# So, I've encapsulated this into the script +# `/etc/ssl/misc/certbot-get`. Edit the array of domains at the top +# of the script, then run it. +add-file -m755 etc/ssl/misc/certbot-get <<<'#!/bin/bash + +# The first name listed should be the canonical host name +domains=( + winston.parabola.nu + {git,projects}.{parabola.nu,parabolagnulinux.org} +) + +######################################################################## +{ + set -eu + + if [[ "`whoami`" != '\''keys'\'' ]]; then + >&2 printf '\''%q: This script must be run as user `%s'\''\'\'''\''\n'\'' "$0" keys + exit 1 + fi + + msg=( + + Our "\`${0##*/}\`" script is used to '\''*add*'\'' or + '\''*remove*'\'' certificates\; use '\''`certbot renew`'\'' to + renew them. To use "${0##*/}," edit the + '\''hostnames=()'\'' list of domains at the beginning of the + script, '\''then'\'' run it to get a new certificate with a + new Subject Alternative Name field matching the new + list of domains. + + $'\''\n\n'\''Are you sure that you are ready to run this? + It will eat into the "Let'\''s Encrypt" usage limit. + + ) + + dialog --yesno "${msg[*]}" '\'''\'' '\'''\'' || { echo; exit 0; } + + cmd=( + certbot certonly + --email "`whoami`@${domains[0]}" + --webroot -w /var/lib/letsencrypt + ) + + for domain in "${domains[@]}"; do + cmd+=(-d "$domain") + done + + umask 0027 + "${cmd[@]}" + sudo /etc/ssl/misc/certbot-hook +} +' + +# Renewal, however, is very simple. It is handled by +# `certbot-renew.service` (triggered by the associated `.timer`). It +# runs `certbot renew` with a couple of flags. +add-file etc/systemd/system/certbot-renew.timer <<EOF +[Unit] +Description=Daily renewal of Let's Encrypt's certificates + +[Timer] +OnCalendar=daily +Persistent=true + +[Install] +WantedBy=timers.target +EOF +add-file etc/systemd/system/certbot-renew.service <<EOF +[Unit] +Description=Let's Encrypt certificate renewal + +[Service] +Type=oneshot +ExecStart=/usr/bin/certbot renew --quiet --renew-hook 'sudo /etc/ssl/misc/certbot-hook' + +User=keys +UMask=0027 +EOF + +# Both `certbot-get` and `certbot-renew.serviceq prove ownership of +# the domain via the `http-01` challenge. `/etc/nginx/nginx.conf` +# includes `/etc/nginx/snippets/ssl.conf`, which has a `server{}` +# block that handles ACME http-01 challenges. +add-file etc/nginx/snippets/ssl.conf <<EOF +# -*- Mode: nginx; nginx-indent-level: 8; indent-tabs-mode: t -*- + +# This is based on Mozilla Security's recommended web server +# configuration generator[1]: +# Generated date: 2016-06-28 +# Server: Nginx +# Clients: Intermediate +# Server Version: 1.10.1 +# OpenSSL Version: 1.0.2h +# HSTS Enabled: yes +# +# [1]: https://mozilla.github.io/server-side-tls/ssl-config-generator/ +# +# Obviously, all of the '/path/to/' paths have been filled in. The +# 'resolver' line has been commented out. The SSL information has +# been promoted to be in the http{} block directly, instead of having +# to be in each server{} block. The HTTP->HTTPS redirector has had +# ACME support added. + +# Redirect everything on port 80 to HTTPS +server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + + + # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response. + location / { return 301 https://\$host\$request_uri; } + + # Except for ACME http-01 validations + location /.well-known/acme-challenge { + root /var/lib/letsencrypt; + default_type "text/plain"; + #try_files \$uri =404; + } +} + +# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate +ssl_certificate /etc/letsencrypt/live/winston.parabola.nu/fullchain.pem; +ssl_certificate_key /etc/letsencrypt/live/winston.parabola.nu/privkey.pem; +ssl_session_timeout 1d; +ssl_session_cache shared:SSL:50m; +ssl_session_tickets off; + +# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits +ssl_dhparam /etc/ssl/private/dhparam-2048.pem; + +# intermediate configuration. tweak to your needs. +ssl_protocols TLSv1 TLSv1.1 TLSv1.2; +ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS'; +ssl_prefer_server_ciphers on; + +# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) +add_header Strict-Transport-Security max-age=15768000; + +# OCSP Stapling --- +# fetch OCSP records from URL in ssl_certificate and cache them +ssl_stapling on; +ssl_stapling_verify on; + +## verify chain of trust of OCSP response using Root CA and Intermediate certs +#ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + +#resolver <IP DNS resolver>; +EOF + +# Both `certbot-get` and `certbot-renew.service` have been written to +# run `sudo /etc/ssl/misc/certbot-hook` after certificates have been +# updated, and `sudo` has been configured to allow the keys user to do +# this without a password. Right now `certbot-hook` just runs +# `systemctl reload nginx.service`. +add-file etc/ssl/misc/certbot-hook <<EOF +#!/bin/bash +systemctl reload nginx.service +EOF +install -dm750 etc/sudoers.d +add-file etc/sudoers.d/10-certbot <<EOF +keys ALL=(ALL) NOPASSWD: /etc/ssl/misc/certbot-hook +EOF + +backup=($(find "$pkgdir" -type f -printf '%P\n')) +} diff --git a/config-uwsgi.PKGBUILD b/config-uwsgi.PKGBUILD new file mode 100644 index 0000000..663f00c --- /dev/null +++ b/config-uwsgi.PKGBUILD @@ -0,0 +1,61 @@ +. ${BUILDFILE%/*}/common.sh +pkgver=20160713 + +depends=(uwsgi) + +package() { +cd "$pkgdir" + +# Wherever possible, we should use uWSGI for process management of our +# HTTP services. This allows for much more consistent management and +# configuration than the hodge-podge of PHP-FPM, manage.py, fcgiwrap, +# et c. that we used to have on Proton. + +# uWSGI is the program, uwsgi is the protocol it speaks with nginx. A +# pool of workers is called a vassal, and is configured in +# `/etc/uwsgi/${vassal}.ini`, and activated by +# `uwsgi@${vassal}.socket`; a socket speaking the uwsgi protocol is +# created at `/var/run/uwsgi/${vassal}.sock`. + +# We use systemd socket activation rather than a uWSGI emperor because +# they provide largely the same functionality; the only real advantage +# that a uWSGI emperor would provide over systemd socket activation is +# if you ran it in tyrant mode, it lets you do some cool things with +# unpriveleged access, which would be useful for a shared web host. +# We aren't a shared web host, and have no reason to run emperor in +# tyrant mode. + +# Since the `uwsgi@.service` vassal unit is written to support +# socket-activated or non-socket-activated use, it is normally +# possible to accidentally start it without the associated `.socket` +# unit; which is an error with how our vassal configurations are +# written. To fix this, `uwsgi@.service.d/socket.conf` overrides the +# unit a bit to disable non-socket-activated use. +add-file etc/systemd/system/uwsgi@.service.d/socket.conf <<EOF +# Avoid accidentally starting the service without the socket +[Unit] +Requires=uwsgi@%i.socket +After=uwsgi@%i.socket +EOF + +# The ownership and permissions for the socket are configured in +# `uwsgi@.socket.d/owner.conf`, which sets the owner to `http:http` +# and the mode to 0600. +add-file etc/systemd/system/uwsgi@.socket.d/owner.conf <<EOF +[Socket] +SocketUser=http +SocketGroup=http +SocketMode=0600 +EOF + +# uWSGI supports thread pools in addition to process pools, but many +# of the actual workers you'll want to use aren't thread safe, so +# stick to process pools unless you specifically know that your worker +# is thread-safe (for example, PHP, at least with the modules needed +# for MediaWiki, is not thread-safe). + +# Individual vassal configurations are documented in the section for +# the service that they provide, not here. + +backup=($(find "$pkgdir" -type f -printf '%P\n')) +} |