<?xml version="1.0" encoding="utf-8"?><!DOCTYPE article  PUBLIC '-//OASIS//DTD DocBook XML V4.4//EN'  'http://www.docbook.org/xml/4.4/docbookx.dtd'><article><articleinfo><title>MemberManual/ServingWebsites/SslCert/LetsEncrypt</title><revhistory><revision><revnumber>17</revnumber><date>2024-02-25 17:57:43</date><authorinitials>173.93.103.73</authorinitials></revision><revision><revnumber>16</revnumber><date>2023-09-07 00:10:58</date><authorinitials>StephenMichel</authorinitials><revremark>Update letsencrypt-renew script</revremark></revision><revision><revnumber>15</revnumber><date>2023-01-30 01:40:43</date><authorinitials>RobinTempleton</authorinitials><revremark>acme.sh should request an RSA key</revremark></revision><revision><revnumber>14</revnumber><date>2022-05-12 00:00:34</date><authorinitials>StephenMichel</authorinitials><revremark>Add renew function</revremark></revision><revision><revnumber>13</revnumber><date>2021-09-14 22:38:34</date><authorinitials>2600:1700:7a80:2180:e9c1:55b2:b51f:df4</authorinitials><revremark>acme.sh defaults have changed.</revremark></revision><revision><revnumber>12</revnumber><date>2021-02-03 12:40:00</date><authorinitials>193.51.104.22</authorinitials><revremark>Link multi-domain configuration steps</revremark></revision><revision><revnumber>11</revnumber><date>2021-02-03 12:37:17</date><authorinitials>193.51.104.22</authorinitials><revremark>Cert generation does work as written! Clarify webroot setting</revremark></revision><revision><revnumber>10</revnumber><date>2021-02-03 12:20:20</date><authorinitials>193.51.104.22</authorinitials><revremark>Explain how to find cert path</revremark></revision><revision><revnumber>9</revnumber><date>2020-03-20 14:17:24</date><authorinitials>StephenMichel</authorinitials></revision><revision><revnumber>8</revnumber><date>2020-03-20 14:16:35</date><authorinitials>StephenMichel</authorinitials></revision><revision><revnumber>7</revnumber><date>2020-03-20 11:51:53</date><authorinitials>StephenMichel</authorinitials><revremark>The real purpose of this is adding a version with the apostrophe so that a search for &quot;Let's Encrypt&quot; will find this page.</revremark></revision><revision><revnumber>6</revnumber><date>2019-05-25 23:19:04</date><authorinitials>ClintonEbadi</authorinitials><revremark>explicitly mention that cert installation must be requested on renewal</revremark></revision><revision><revnumber>5</revnumber><date>2019-01-30 20:33:33</date><authorinitials>SrikanthSastry</authorinitials><revremark>Updated acme shell script install and usage instructions</revremark></revision><revision><revnumber>4</revnumber><date>2016-04-18 02:05:22</date><authorinitials>NickMD</authorinitials><revremark>I realised I didn't really understand what I was doing. However some of the 'le' do need updating to 'acme' - programs new name.</revremark></revision><revision><revnumber>3</revnumber><date>2016-04-18 01:32:37</date><authorinitials>NickMD</authorinitials><revremark>updated for new script name</revremark></revision><revision><revnumber>2</revnumber><date>2016-03-31 19:28:41</date><authorinitials>c-71-192-154-186.hsd1.ma.comcast.net</authorinitials></revision><revision><revnumber>1</revnumber><date>2016-03-31 19:27:44</date><authorinitials>c-71-192-154-186.hsd1.ma.comcast.net</authorinitials></revision></revhistory></articleinfo><para>Let's Encrypt! This page describes how to enable SSL using letsencrypt for <emphasis>example.com</emphasis>. Log in through ssh to <code>ssh.hcoop.net</code>, then follow the instructions below </para><section><title>First time setup</title><para>At the end of these steps, you'll have a certificate for <emphasis>www.example.com</emphasis>. If you want to use a different subdomain (<emphasis>example.com</emphasis>, <emphasis>git.example.com</emphasis>, etc.), you can follow this <link linkend="Multi-domain_configuration_example">multi-domain configuration example</link>. </para><section><title>Set up your new website with http</title><screen><![CDATA[echo 'dom "example.com" with end;' > ~/.domtool/example.com]]></screen></section><section><title>Set up your environment</title><para>These steps are recommended but optional. If you skip them, you'll need to run <code>source ~/.acme.sh/acme.sh.env</code> each time before you generate certs. </para><para>The hcoop environment doesn't use a .bashrc file by default, but <code>acme.sh</code> expects one. First create the file </para><screen><![CDATA[touch ~/.bashrc]]></screen><para>Then load it in each new session. Add the following lines to ~/.bash_profile </para><screen><![CDATA[if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi]]></screen></section><section><title>Download and install `acme.sh`</title><para>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. </para><screen><![CDATA[git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install]]></screen><warning><para><emphasis role="strong">Security Precautions</emphasis> </para><para>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. </para></warning><para>Set the correct permissions: </para><screen><![CDATA[fs sa ~/.acme.sh -clear YOUR_USERNAME all system:administrators all]]></screen><para>You'll have to do this once, or you can log out and reconnect (if you set up your .bashrc): </para><screen><![CDATA[source ~/.acme.sh/acme.sh.env]]></screen><para>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 <ulink url="https://wiki.hcoop.net/MemberManual/ServingWebsites/SslCert/LetsEncrypt/LetsEncrypt#">LetsEncrypt</ulink>, you may want to run the following to change the default CA back to <ulink url="https://wiki.hcoop.net/MemberManual/ServingWebsites/SslCert/LetsEncrypt/LetsEncrtpy#">LetsEncrtpy</ulink>, before continuing: </para><screen><![CDATA[acme.sh --set-default-ca --server letsencrypt]]></screen></section><section><title>Generate the cert</title><para>If the <emphasis>example.com</emphasis> document root is <code>~/public_html/</code>, run </para><screen><![CDATA[acme.sh --issue -k 2048 -d example.com -w ~/public_html/]]></screen><para>(If the document root is some weird subdirectory, like <code>~/public_html/weird</code>, set the <code>-w</code> option to that instead.) </para><para>The <code>-k 2048</code> argument requests a 2048-bit RSA key; by default, <code>acme.sh</code> generates ECC keys, which aren't yet supported (as of January 2023). </para><para>At the end, it will print <code>Your cert is in</code> and then a path to a file ending in <code>.cer</code>. Copy this path <emphasis role="strong">without the .cer extension</emphasis>. In the next section, replace <code>$FILE</code> with this path. </para></section><section><title>Request cert installation from hcoop admins</title><para>Send a <ulink url="https://members.hcoop.net/portal/cert">SSL certificate permission request</ulink>. Fields are filled out with: </para><para>Subdomain: <code>www</code> </para><para>Domain: <code>example.com</code> </para><para>OpenSSL certificate: <code>$FILE.cer $FILE.key</code> </para><para>See section above for context. </para><para>You must also request certificate installation whenever you renew the certificate. </para></section><section><title>Update domtool config to use SSL</title><para>Now that your cert has been installed, its path will appear on the <ulink url="https://members.hcoop.net/portal/cert">certificate permission request</ulink> page, under the heading &quot;Your certificates.&quot; Let's say the cert path is <code>/etc/apache2/ssl/user/www.example.com.pem</code>. (That directory is really called <code>user</code>; it's not a username stand-in!) You need to add this path to your domtool configuration. </para><para>Here's a simple example config, which redirects all traffic to https in a single domain. </para><screen><![CDATA[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;]]></screen><para>Here are <ulink url="https://wiki.hcoop.net/MemberManual/ServingWebsites/SslCert/LetsEncrypt/DomTool/Examples#Using_SSL_.28HTTPS.29">more single-domain examples</ulink> and <link linkend="Multi-domain_configuration_example">a multi-domain example</link>. For reference, here's the <ulink url="https://wiki.hcoop.net/MemberManual/ServingWebsites/SslCert/LetsEncrypt/DomTool#">domtool manual</ulink>. </para></section></section><section><title>Existing setups &amp; tweaks</title><note><para><emphasis role="strong">Under construction</emphasis> </para><para>This section is under construction. </para></note><section><title>Multi-domain configuration example</title><para><code>.domtool/lib.dtl</code> </para><screen><![CDATA[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;]]></screen><para><code>.domtool/elektrubadur.se</code>: </para><screen><![CDATA[val elektrubadurCertificate = use_cert "/etc/apache2/ssl/user/elektrubadur.se.pem";
]]><![CDATA[
val elektrubadurRewrite = rewriteRule "^(.*)$" "https://elektrubadur.se$1" [redirectWith permanent];
]]><![CDATA[
val elektrubadurSubdomainAlias = \name -> begin
    web name with elektrubadurRewrite; end;
    web name where SSL = elektrubadurCertificate; with elektrubadurRewrite; end;
end;
]]><![CDATA[
dom "elektrubadur.se" where
    DocumentRoot = home "www/elektrubadur.se";
    CreateWWW = false;
with
    addDefaultSPF;
]]><![CDATA[
    vhostDefault where
        SSL = elektrubadurCertificate;
    with
        errorDocument "404" "/404.html";
]]><![CDATA[
        expiresByType "text/plain" access 1 days;
        expiresByType "text/css" access 1 days;
]]><![CDATA[
        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;
]]><![CDATA[
        acmeChallengeAlias;
    end;
]]><![CDATA[
    vhostDefault with elektrubadurRewrite; end;
]]><![CDATA[
    elektrubadurSubdomainAlias "www";
    elektrubadurSubdomainAlias "bkhl";
]]><![CDATA[
    web "test" where
        DocumentRoot = home "www/test.elektrubadur.se";
        SSL = elektrubadurCertificate;
    with
        acmeChallengeAlias;
    end;
]]><![CDATA[
    web "test" with
        rewriteRule "^(.*)$" "https://test.elektrubadur.se$1" [redirectWith permanent];
    end;
]]><![CDATA[
    web "cloud" where
        DocumentRoot = home "www/cloud.elektrubadur.se";
        SSL = elektrubadurCertificate;
    with
        location "/" with
            unset_options [indexes, multiViews];
            directoryIndex ["index.php", "index.html"];
        end;
]]><![CDATA[
        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;
]]><![CDATA[
        setEnvIfNoCase "^Authorization$" "(.+)" ["XAUTHORIZATION=$1"];
]]><![CDATA[
        rewriteCond "%{HTTP_USER_AGENT}" "DavClnt" [];
        rewriteRule "^$" "/remote.php/webdav/" [redirectWith temp, last];
]]><![CDATA[
        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];
]]><![CDATA[
        acmeChallengeAlias;
    end;
]]><![CDATA[
    web "cloud" with
        rewriteRule "^(.*)$" "https://cloud.elektrubadur.se$1" [redirectWith permanent];
    end;
]]><![CDATA[
    emailAlias "admin" "bkhl";
    emailAlias "info" "bkhl";
end;]]></screen><para>command: </para><screen><![CDATA[~/.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/]]></screen><para>And later on just <code>~/.acme.sh/acme.sh --renew-all</code> </para></section><section><title>Mostly-automated renewals</title><para>You can edit <code>example.com</code> in the command below to be your domain paths and put the following into your <code>~/.bashrc</code>. Then you just need to run <code>letsencrypt_renew</code> and open the link to submit the request. </para><screen><![CDATA[. "$HOME/.acme.sh/acme.sh.env"
]]><![CDATA[
letsencrypt_renew() {
    local domain="example.com"
    local cert_dir="$HOME/certificates/$domain"
    local keyfile="$cert_dir/$(date --iso-8601)-$domain.pem"
]]><![CDATA[
    acme.sh --renew-all "$@" && cat "$cert_dir/$domain".{cer,key} "$cert_dir"/ca.cer > "$keyfile"
]]><![CDATA[
    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
}]]></screen></section></section></article>