Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 57 additions & 53 deletions templates/web.letsencrypt.ssl.template.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
env:
LETSENCRYPT_DIR: "/shared/letsencrypt"
DISCOURSE_FORCE_HTTPS: true

hooks:
after_ssl:
- exec:
cmd:
- if [ -z "$LETSENCRYPT_ACCOUNT_EMAIL" ]; then echo "LETSENCRYPT_ACCOUNT_EMAIL ENV variable is required and has not been set."; exit 1; fi
- /bin/bash -c "if [[ ! \"$LETSENCRYPT_ACCOUNT_EMAIL\" =~ ([^@]+)@([^\.]+) ]]; then echo \"LETSENCRYPT_ACCOUNT_EMAIL is not a valid email address\"; exit 1; fi"

- exec:
cmd:
- cd /root && git clone --branch 3.0.6 --depth 1 https://github.com/acmesh-official/acme.sh.git && cd /root/acme.sh
- touch /var/spool/cron/crontabs/root
- install -d -m 0755 -g root -o root $LETSENCRYPT_DIR
- cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --install --log "${LETSENCRYPT_DIR}/acme.sh.log"
- cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --upgrade --auto-upgrade
- cd /root/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --set-default-ca --server letsencrypt

- file:
path: "/etc/nginx/letsencrypt.conf"
contents: |
run:
- exec:
cmd:
- cd /opt && git clone --branch 3.0.6 --depth 1 https://github.com/acmesh-official/acme.sh.git
- file:
path: "/usr/local/bin/configure-letsencrypt"
chmod: "+x"
contents: |
#!/bin/bash
touch /var/spool/cron/crontabs/root
LETSENCRYPT_DIR="/shared/letsencrypt"
install -d -m 0755 -g root -o root $LETSENCRYPT_DIR
cd /opt/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --install --log "${LETSENCRYPT_DIR}/acme.sh.log"
cd /opt/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --upgrade --auto-upgrade
cd /opt/acme.sh && LE_WORKING_DIR="${LETSENCRYPT_DIR}" ./acme.sh --set-default-ca --server letsencrypt

cat << EOF > /etc/nginx/letsencrypt.conf
user www-data;
worker_processes auto;
daemon on;
Expand Down Expand Up @@ -50,20 +47,34 @@ hooks:
}
}
}
EOF

- file:
path: /etc/runit/1.d/letsencrypt
chmod: "+x"
contents: |
sed -Ei "s/^#?ACCOUNT_EMAIL=.+/ACCOUNT_EMAIL=${LETSENCRYPT_ACCOUNT_EMAIL}/" \
/shared/letsencrypt/account.conf

sed -Ei "s/ssl_certificate .+/ssl_certificate \/shared\/ssl\/${DISCOURSE_HOSTNAME}.cer;\
ssl_certificate \/shared\/ssl\/${DISCOURSE_HOSTNAME}_ecc.cer;/" \
/etc/nginx/conf.d/outlets/server/20-https.conf
sed -Ei "s/ssl_certificate_key .+/ssl_certificate_key \/shared\/ssl\/${DISCOURSE_HOSTNAME}.key; \
ssl_certificate_key \/shared\/ssl\/${DISCOURSE_HOSTNAME}_ecc.key;/" \
/etc/nginx/conf.d/outlets/server/20-https.conf

exec /usr/local/bin/letsencrypt

- file:
path: /usr/local/bin/letsencrypt
chmod: "+x"
contents: |
#!/bin/bash
LETSENCRYPT_DIR="/shared/letsencrypt"
/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf

issue_cert() {
LE_WORKING_DIR="${LETSENCRYPT_DIR}" $$ENV_LETSENCRYPT_DIR/acme.sh --issue $2 -d $$ENV_DISCOURSE_HOSTNAME --keylength $1 -w /var/www/discourse/public
LE_WORKING_DIR="${LETSENCRYPT_DIR}" ${LETSENCRYPT_DIR}/acme.sh --issue $2 -d ${DISCOURSE_HOSTNAME} --keylength $1 -w /var/www/discourse/public
}

cert_exists() {
[[ "$(cd $$ENV_LETSENCRYPT_DIR/$$ENV_DISCOURSE_HOSTNAME$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")" ]]
[[ "$(cd ${LETSENCRYPT_DIR}/${DISCOURSE_HOSTNAME}$1 && openssl verify -CAfile <(openssl x509 -in ca.cer) fullchain.cer | grep "OK")" ]]
}

########################################################
Expand All @@ -76,11 +87,11 @@ hooks:
issue_cert "4096" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" $$ENV_LETSENCRYPT_DIR/acme.sh \
LE_WORKING_DIR="${LETSENCRYPT_DIR}" ${LETSENCRYPT_DIR}/acme.sh \
--installcert \
-d $$ENV_DISCOURSE_HOSTNAME \
--fullchainpath /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer \
--keypath /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key \
-d ${DISCOURSE_HOSTNAME} \
--fullchainpath /shared/ssl/${DISCOURSE_HOSTNAME}.cer \
--keypath /shared/ssl/${DISCOURSE_HOSTNAME}.key \
--reloadcmd "sv reload nginx"

########################################################
Expand All @@ -93,11 +104,11 @@ hooks:
issue_cert "ec-256" "--force"
fi

LE_WORKING_DIR="${LETSENCRYPT_DIR}" $$ENV_LETSENCRYPT_DIR/acme.sh \
LE_WORKING_DIR="${LETSENCRYPT_DIR}" ${LETSENCRYPT_DIR}/acme.sh \
--installcert --ecc \
-d $$ENV_DISCOURSE_HOSTNAME \
--fullchainpath /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer \
--keypath /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key \
-d ${DISCOURSE_HOSTNAME} \
--fullchainpath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.cer \
--keypath /shared/ssl/${DISCOURSE_HOSTNAME}_ecc.key \
--reloadcmd "sv reload nginx"

if cert_exists "" || cert_exists "_ecc"; then
Expand All @@ -106,22 +117,15 @@ hooks:

/usr/sbin/nginx -c /etc/nginx/letsencrypt.conf -s stop

- replace:
filename: /shared/letsencrypt/account.conf
from: /#?ACCOUNT_EMAIL=.+/
to: |
ACCOUNT_EMAIL=$$ENV_LETSENCRYPT_ACCOUNT_EMAIL

- replace:
filename: "/etc/nginx/conf.d/outlets/server/20-https.conf"
from: /ssl_certificate.+/
to: |
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.cer;
ssl_certificate /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.cer;

- replace:
filename: "/etc/nginx/conf.d/outlets/server/20-https.conf"
from: /ssl_certificate_key.+/
to: |
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME.key;
ssl_certificate_key /shared/ssl/$$ENV_DISCOURSE_HOSTNAME_ecc.key;
hooks:
after_ssl:
- file:
path: /etc/runit/1.d/install-ssl
chmod: "+x"
contents: |
#!/bin/bash
if [ -z "$DISCOURSE_HOSTNAME" ]; then echo "DISCOURSE_HOSTNAME expected"; exit 1; fi
if [ -z "$LETSENCRYPT_ACCOUNT_EMAIL" ]; then echo "LETSENCRYPT_ACCOUNT_EMAIL ENV not set. Skipping Let's Encrypt setup."; exit 0; fi
if [[ ! "$LETSENCRYPT_ACCOUNT_EMAIL" =~ ([^@]+)@([^\.]+) ]]; then echo "LETSENCRYPT_ACCOUNT_EMAIL is not a valid email address"; exit 1; fi
/usr/local/bin/configure-ssl
exec /usr/local/bin/configure-letsencrypt
56 changes: 32 additions & 24 deletions templates/web.ssl.template.yml
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
run:
- exec:
cmd:
- "mkdir -p /shared/ssl/"
- file:
path: "/etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf"
path: /etc/runit/1.d/install-ssl
hook: ssl
chmod: "+x"
contents: |
#!/bin/bash
if [ -z "$DISCOURSE_HOSTNAME" ]; then echo "DISCOURSE_HOSTNAME expected"; exit 1; fi
if [ ! -z "$ENABLE_SSL" ]; then
exec /usr/local/bin/configure-ssl
fi

- file:
path: "/usr/local/bin/configure-ssl"
chmod: "+x"
contents: |
#!/bin/bash
mkdir -p /shared/ssl/
cat << EOF > /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf
server {
listen 80;
return 301 https://$$ENV_DISCOURSE_HOSTNAME$request_uri;
return 301 https://${DISCOURSE_HOSTNAME}$request_uri;
}
- file:
path: "/etc/nginx/conf.d/outlets/server/10-http.conf"
contents: ""
- file:
hook: ssl
path: "/etc/nginx/conf.d/outlets/server/20-https.conf"
contents: |
EOF

> /etc/nginx/conf.d/outlets/server/10-http.conf
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This redirection is non-idiomatic. Use touch or install /dev/null.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of this line is to empty the file. I've updated to use install /dev/null - thanks for the pointer!

Copy link
Member

@andrewschleifer andrewschleifer Jul 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh, that was a possibility I had not considered. echo > $FILE is the normal way to do that, sorry. (Possibly with a comment to explain that it already exists and we want to wipe out the contents.)


cat << EOF > /etc/nginx/conf.d/outlets/server/20-https.conf
listen 443 ssl;
http2 on;

Expand All @@ -32,17 +42,15 @@ run:

add_header Strict-Transport-Security 'max-age=31536000';

if ($http_host != $$ENV_DISCOURSE_HOSTNAME) {
rewrite (.*) https://$$ENV_DISCOURSE_HOSTNAME$1 permanent;
if (\$http_host != ${DISCOURSE_HOSTNAME}) {
rewrite (.*) https://${DISCOURSE_HOSTNAME}\$1 permanent;
}
- file:
path: "/etc/nginx/conf.d/outlets/discourse/20-https.conf"
contents: |
EOF

cat << EOF > /etc/nginx/conf.d/outlets/discourse/20-https.conf
add_header Strict-Transport-Security 'max-age=31536000';
- exec:
cmd:
- |-
if [ -f "/proc/net/if_inet6" ] ; then
sed -i 's/listen 80;/listen 80;\nlisten [::]:80;/g' /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf
sed -i 's/listen 443 ssl;/listen 443 ssl;\nlisten [::]:443 ssl;/g' /etc/nginx/conf.d/outlets/server/20-https.conf
fi
EOF
if [ -f "/proc/net/if_inet6" ] ; then
sed -i 's/listen 80;/listen 80;\nlisten [::]:80;/g' /etc/nginx/conf.d/outlets/before-server/20-redirect-http-to-https.conf
sed -i 's/listen 443 ssl;/listen 443 ssl;\nlisten [::]:443 ssl;/g' /etc/nginx/conf.d/outlets/server/20-https.conf
fi