summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-07-13 05:20:54 +0000
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-07-13 05:20:54 +0000
commited13bd129a85d8133137086adba56649b395444a (patch)
tree988df4180b086d46dbf315bb268d6e8041c51049
parent2c363690324401c2edd40013f432113ae0d8354e (diff)
add certbot and uwsgi configs
-rw-r--r--config-certbot.PKGBUILD189
-rw-r--r--config-uwsgi.PKGBUILD61
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'))
+}