Let's Encrypt! This page describes how to enable SSL using letsencrypt for example.com. Log in through ssh to ssh.hcoop.net, then follow the instructions below
Contents
1. First time setup
At the end of these steps, you'll have a certificate for www.example.com. If you want to use a different subdomain (example.com, git.example.com, etc.), you can follow this multi-domain configuration example.
1.1. Set up your new website with http
echo 'dom "example.com" with end;' > ~/.domtool/example.com
1.2. Set up your environment
These steps are recommended but optional. If you skip them, you'll need to run source ~/.acme.sh/acme.sh.env each time before you generate certs.
The hcoop environment doesn't use a .bashrc file by default, but acme.sh expects one. First create the file
touch ~/.bashrc
Then load it in each new session. Add the following lines to ~/.bash_profile
if [ -f ~/.bashrc ]; then . ~/.bashrc fi
1.3. Download and install `acme.sh`
Acme.sh is a client for the ACME protocol, written in pure bash. The third command may complain that you are not allowed to use crontab. This is fine.
git clone https://github.com/acmesh-official/acme.sh.git cd acme.sh ./acme.sh --install
Security Precautions
Since afs is publicly accessible, you need to take a few precautions to ensure that your certificate and private key remain private. For all key operations, keep the files in a directory that only you and the admins can read.
Set the correct permissions:
fs sa ~/.acme.sh -clear YOUR_USERNAME all system:administrators all
You'll have to do this once, or you can log out and reconnect (if you set up your .bashrc):
source ~/.acme.sh/acme.sh.env
Additionally, acme.sh now uses ZeroSSL as their default CA service, which requires providing an email to the client, linked to a server. If you want to continue using LetsEncrypt, you may want to run the following to change the default CA back to LetsEncrtpy, before continuing:
acme.sh --set-default-ca --server letsencrypt
1.4. Generate the cert
If the example.com document root is ~/public_html/, run
acme.sh --issue -k 2048 -d example.com -w ~/public_html/
(If the document root is some weird subdirectory, like ~/public_html/weird, set the -w option to that instead.)
The -k 2048 argument requests a 2048-bit RSA key; by default, acme.sh generates ECC keys, which aren't yet supported (as of January 2023).
At the end, it will print Your cert is in and then a path to a file ending in .cer. Copy this path without the .cer extension. In the next section, replace $FILE with this path.
1.5. Request cert installation from hcoop admins
Send a SSL certificate permission request. Fields are filled out with:
Subdomain: www
Domain: example.com
OpenSSL certificate: $FILE.cer $FILE.key
See section above for context.
You must also request certificate installation whenever you renew the certificate.
1.6. Update domtool config to use SSL
Now that your cert has been installed, its path will appear on the certificate permission request page, under the heading "Your certificates." Let's say the cert path is /etc/apache2/ssl/user/www.example.com.pem. (That directory is really called user; it's not a username stand-in!) You need to add this path to your domtool configuration.
Here's a simple example config, which redirects all traffic to https in a single domain.
dom "example.com" where SSL = use_cert "/etc/apache2/ssl/user/www.example.com.pem" with web "www" with rewriteRule "^(.*)$" "https://www.example.com$1" [redirectWith temp] end; end;
Here are more single-domain examples and a multi-domain example. For reference, here's the domtool manual.
2. Existing setups & tweaks
Under construction
This section is under construction.
2.1. Multi-domain configuration example
.domtool/lib.dtl
val acmeChallengeAlias = begin location "/.well-known/acme-challenge" with unset_options [indexes]; end; alias "/.well-known/acme-challenge" "/afs/hcoop.net/user/b/bk/bkhl/www/acme/.well-known/acme-challenge"; end;
.domtool/elektrubadur.se:
val elektrubadurCertificate = use_cert "/etc/apache2/ssl/user/elektrubadur.se.pem"; val elektrubadurRewrite = rewriteRule "^(.*)$" "https://elektrubadur.se$1" [redirectWith permanent]; val elektrubadurSubdomainAlias = \name -> begin web name with elektrubadurRewrite; end; web name where SSL = elektrubadurCertificate; with elektrubadurRewrite; end; end; dom "elektrubadur.se" where DocumentRoot = home "www/elektrubadur.se"; CreateWWW = false; with addDefaultSPF; vhostDefault where SSL = elektrubadurCertificate; with errorDocument "404" "/404.html"; expiresByType "text/plain" access 1 days; expiresByType "text/css" access 1 days; expiresByType "image/jpeg" access 1 weeks; expiresByType "image/png" access 1 weeks; expiresByType "image/gif" access 1 weeks; expiresByType "image/svg" access 1 weeks; expiresByType "image/vnd.microsoft.icon" access 1 weeks; acmeChallengeAlias; end; vhostDefault with elektrubadurRewrite; end; elektrubadurSubdomainAlias "www"; elektrubadurSubdomainAlias "bkhl"; web "test" where DocumentRoot = home "www/test.elektrubadur.se"; SSL = elektrubadurCertificate; with acmeChallengeAlias; end; web "test" with rewriteRule "^(.*)$" "https://test.elektrubadur.se$1" [redirectWith permanent]; end; web "cloud" where DocumentRoot = home "www/cloud.elektrubadur.se"; SSL = elektrubadurCertificate; with location "/" with unset_options [indexes, multiViews]; directoryIndex ["index.php", "index.html"]; end; expiresByType "text/css" access 1 weeks; expiresByType "application/javascript" access 1 weeks; expiresByType "image/svg" access 1 weeks; expiresByType "image/gif" access 1 weeks; expiresByType "application/font-woff2" access 1 weeks; setEnvIfNoCase "^Authorization$" "(.+)" ["XAUTHORIZATION=$1"]; rewriteCond "%{HTTP_USER_AGENT}" "DavClnt" []; rewriteRule "^$" "/remote.php/webdav/" [redirectWith temp, last]; rewriteRule ".*" "-" [env "HTTP_AUTHORIZATION" "%{HTTP:Authorization}"]; rewriteRule "^\.well-known/host-meta" "/public.php?service=host-meta" [qsappend, last]; rewriteRule "^\.well-known/host-meta\.json" "/public.php?service=host-meta-json" [qsappend, last]; rewriteRule "^\.well-known/webfinger" "/public.php?service=webfinger" [qsappend, last]; rewriteRule "^\.well-known/carddav" "/remote.php/dav/" [redirectWith permanent, last]; rewriteRule "^\.well-known/caldav" "/remote.php/dav/" [redirectWith permanent, last]; rewriteRule "^remote/(.*)" "remote.php" [qsappend, last]; rewriteRule "^(?:build|tests|config|lib|3rdparty|templates)/.*" "-" [redirectWith notfound, last]; rewriteCond "%{REQUEST_URI}" "!^/\.well-known/(acme-challenge|pki-validation)/.*" []; rewriteRule "^(?:\.|autotest|occ|issue|indie|db_|console).*" "-" [redirectWith notfound, last]; acmeChallengeAlias; end; web "cloud" with rewriteRule "^(.*)$" "https://cloud.elektrubadur.se$1" [redirectWith permanent]; end; emailAlias "admin" "bkhl"; emailAlias "info" "bkhl"; end;
command:
~/.acme.sh/acme.sh --issue -d elektrubadur.se -d www.elektrubadur.se -d bkhl.elektrubadur.se -d cloud.elektrubadur.se -d test.elektrubadur.se -w $HOME/www/acme/
And later on just ~/.acme.sh/acme.sh --renew-all
2.2. Mostly-automated renewals
You can edit example.com in the command below to be your domain paths and put the following into your ~/.bashrc. Then you just need to run letsencrypt_renew and open the link to submit the request.
. "$HOME/.acme.sh/acme.sh.env" letsencrypt_renew() { local domain="example.com" local cert_dir="$HOME/certificates/$domain" local keyfile="$cert_dir/$(date --iso-8601)-$domain.pem" acme.sh --renew-all "$@" && cat "$cert_dir/$domain".{cer,key} "$cert_dir"/ca.cer > "$keyfile" if test -f "$keyfile" then >&2 printf 'Open this link to submit:\n' >&2 printf \ 'https://members.hcoop.net/portal/cert?cmd=request&cert=%s&domain=%s&subdomain=&msg=routine+renewal\n' \ "$keyfile" "$domain" else >&2 printf 'Error renewing cert, see above for more info (hopefully)\n' fi }