Update README.html.
authorMatt Birkholz <matt@birchwood-abbey.net>
Thu, 28 Dec 2023 23:07:43 +0000 (16:07 -0700)
committerMatt Birkholz <matt@birchwood-abbey.net>
Thu, 28 Dec 2023 23:07:43 +0000 (16:07 -0700)
README.html

index e8d92c47250f6cc866b374c49f90771961541e40..dd4aae37688a684493d9a1eef2f58fdd1be241a9 100644 (file)
@@ -3,7 +3,7 @@
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
-<!-- 2023-12-17 Sun 16:05 -->
+<!-- 2023-12-28 Thu 16:07 -->
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
 <meta name="viewport" content="width=device-width, initial-scale=1" />
 <title>A Small Institute</title>
@@ -48,7 +48,7 @@ connects to Front making the institute email, cloud, etc. available to
 members off campus.
 </p>
 
-<pre class="example" id="org6dd28f2">
+<pre class="example" id="org212bb48">
                 =                                                   
               _|||_                                                 
         =-The-Institute-=                                           
@@ -149,12 +149,12 @@ month) because of this assumption.
 <div class="outline-text-2" id="text-3">
 <p>
 The small institute's network is designed to provide a number of
-services.  An understanding of how institute hosts co-operate is
-essential to understanding the configuration of specific hosts.  This
-chapter covers institute services from a network wide perspective, and
-gets right down in its subsections to the Ansible code that enforces
-its policies.  On first reading, those subsections should be skipped;
-they reference particulars first introduced in the following chapter.
+services.  Understanding how institute hosts co-operate is essential
+to understanding the configuration of specific hosts.  This chapter
+covers institute services from a network wide perspective, and gets
+right down in its subsections to the Ansible code that enforces its
+policies.  On first reading, those subsections should be skipped; they
+reference particulars first introduced in the following chapter.
 </p>
 </div>
 <div id="outline-container-org12ea1d0" class="outline-3">
@@ -227,7 +227,7 @@ declared by the institute's SPF (Sender Policy Framework) DNS record
 to be the only legitimate sender of institute emails.  Thus the
 Internet sees the institute's outgoing email coming from a server at
 an address matching the domain's SPF record.  The institute does <i>not</i>
-sign outgoing emails per DKIM (Domain Keys Identified Mail), yet.
+sign outgoing emails per DKIM (Domain Keys Identified Mail) yet.
 </p>
 
 <div class="org-src-container">
@@ -398,8 +398,8 @@ PHP) stack.
 Core provides a campus HTTP service with several virtual hosts.
 These web sites can only be accessed via the campus Ethernet or an
 institute VPN.  In either situation Core's many private domain names
-become available, e.g. <q>www.small.private</q>.  In many cases these
-domain names can be shortened e.g. to <q>www</q>.  Thus the campus home
+become available, e.g. <code>www.small.private</code>.  In many cases these
+domain names can be shortened e.g. to <code>www</code>.  Thus the campus home
 page is accessible in a dozen keystrokes: <code>http://www/</code> (plus Enter).
 </p>
 
@@ -607,9 +607,9 @@ initial, privileged user account the same name is given (e.g. as
 described in <a href="#org8d60b7b">The Core Machine</a>).  Installation may <i>not</i> prompt and
 still create an initial user account with a distribution specific name
 (e.g. <code>pi</code>).  Any name can be used as long as it is provided as the
-value of <code>ansible_user</code> in <q>hosts</q>.  Its password is specified by a
-vault-encrypted variable in the <q>Secret/become.yml</q> file.  (The
-<q>hosts</q> and <q>Secret/become.yml</q> files are described in <a href="#orgff33e02">The Ansible
+value of <code>ansible_user</code> in <a href="hosts"><q>hosts</q></a>.  Its password is specified by a
+vault-encrypted variable in the <a href="Secret/become.yml"><q>Secret/become.yml</q></a> file.  (The
+<a href="hosts"><q>hosts</q></a> and <a href="Secret/become.yml"><q>Secret/become.yml</q></a> files are described in <a href="#orgff33e02">The Ansible
 Configuration</a>.)
 </p>
 </div>
@@ -632,49 +632,51 @@ account is created on Front as well.
 <p>
 The institute keeps its "master secrets" in an encrypted
 volume on an off-line hard drive, e.g. a LUKS (Linux Unified Key
-Setup) format partition on a USB pen/stick.  The <q>Secret/</q>
+Setup) format partition on a USB pen/stick.  The <a href="Secret/"><q>Secret/</q></a>
 sub-directory is actually a symbolic link to this partition's
 automatic mount point, e.g.  <q>/media/sysadm/ADE7-F866/</q>.  Unless this
-volume is mounted (unlocked) at <q>Secret/</q>, none of the <code>./inst</code>
+volume is mounted (unlocked) at <a href="Secret/"><q>Secret/</q></a>, none of the <code>./inst</code>
 commands will work.
 </p>
 
 <p>
-Chief among the institute's master secrets is the SSH key to the
-privileged accounts on <i>all</i> of the institute servers.  It is stored
-in <q>Secret/ssh_admin/id_rsa</q>.  The institute uses several more SSH
-keys listed here:
+Chief among the institute's master secrets is the SSH key authorized
+to access privileged accounts on <i>all</i> of the institute servers.  It
+is stored in <a href="Secret/ssh_admin/id_rsa"><q>Secret/ssh_admin/id_rsa</q></a>.  The complete list of the
+institute's SSH keys:
 </p>
 
 <dl class="org-dl">
-<dt><q>Secret/ssh_admin/</q></dt><dd>The SSH key pair for A Small Institute
+<dt><a href="Secret/ssh_admin/"><q>Secret/ssh_admin/</q></a></dt><dd>The SSH key pair for A Small Institute
 Administrator.</dd>
-<dt><q>Secret/ssh_monkey/</q></dt><dd>The key pair used by Monkey to update the
+<dt><a href="Secret/ssh_monkey/"><q>Secret/ssh_monkey/</q></a></dt><dd>The key pair used by Monkey to update the
 website on Front (and other unprivileged tasks).</dd>
-<dt><q>Secret/ssh_front/</q></dt><dd>The host key pair used by Front to
-authenticate itself.</dd>
+<dt><a href="Secret/ssh_front/"><q>Secret/ssh_front/</q></a></dt><dd>The host key pair used by Front to
+authenticate itself.  The automatically generated key pair is
+<i>not</i> used.  (Thus Core's configuration does not depend on
+Front's.)</dd>
 </dl>
 
 <p>
 The institute uses a number of X.509 certificates to authenticate VPN
 clients and servers.  They are created by the EasyRSA Certificate
-Authority stored in <q>Secret/CA/</q>.
+Authority stored in <a href="Secret/CA/"><q>Secret/CA/</q></a>.
 </p>
 
 <dl class="org-dl">
-<dt><q>Secret/CA/pki/ca.crt</q></dt><dd>The institute CA (certificate
-authority).</dd>
+<dt><a href="Secret/CA/pki/ca.crt"><q>Secret/CA/pki/ca.crt</q></a></dt><dd>The institute CA certificate, used to
+sign the other certificates.</dd>
 
-<dt><q>Secret/CA/pki/issued/small.example.org.crt</q></dt><dd>The public Apache,
+<dt><a href="Secret/CA/pki/issued/small.example.org.crt"><q>Secret/CA/pki/issued/small.example.org.crt</q></a></dt><dd>The public Apache,
 Postfix, and OpenVPN servers on Front.</dd>
 
-<dt><q>Secret/CA/pki/issued/gate.small.private.crt</q></dt><dd>The campus
+<dt><a href="Secret/CA/pki/issued/gate.small.private.crt"><q>Secret/CA/pki/issued/gate.small.private.crt</q></a></dt><dd>The campus
 OpenVPN server on Gate.</dd>
 
-<dt><q>Secret/CA/pki/issued/core.small.private.crt</q></dt><dd>The campus
+<dt><a href="Secret/CA/pki/issued/core.small.private.crt"><q>Secret/CA/pki/issued/core.small.private.crt</q></a></dt><dd>The campus
 Apache (thus Nextcloud), and Dovecot-IMAPd servers.</dd>
 
-<dt><q>Secret/CA/pki/issued/core.crt</q></dt><dd>Core's client certificate by
+<dt><a href="Secret/CA/pki/issued/core.crt"><q>Secret/CA/pki/issued/core.crt</q></a></dt><dd>Core's client certificate, by
 which it authenticates to Front.</dd>
 </dl>
 
@@ -694,17 +696,17 @@ Finally, the institute uses an OpenPGP key to secure sensitive emails
 </p>
 
 <dl class="org-dl">
-<dt><q>Secret/root.gnupg/</q></dt><dd>The "home directory" used to create the
+<dt><a href="Secret/root.gnupg/"><q>Secret/root.gnupg/</q></a></dt><dd>The "home directory" used to create the
 public/secret key pair.</dd>
-<dt><q>Secret/root-pub.pem</q></dt><dd>The ASCII armored OpenPGP public key for
+<dt><a href="Secret/root-pub.pem"><q>Secret/root-pub.pem</q></a></dt><dd>The ASCII armored OpenPGP public key for
 e.g. <code>root@core.small.private</code>.</dd>
-<dt><q>Secret/root-sec.pem</q></dt><dd>The ASCII armored OpenPGP secret key.</dd>
+<dt><a href="Secret/root-sec.pem"><q>Secret/root-sec.pem</q></a></dt><dd>The ASCII armored OpenPGP secret key.</dd>
 </dl>
 
 <p>
-When <a href="#org671a111">The CA Command</a> sees an empty <q>Secret/CA/</q> directory, as
+When <a href="#org671a111">The CA Command</a> sees an empty <a href="Secret/CA/"><q>Secret/CA/</q></a> directory, as
 though just created by running the EasyRSA <code>make-cadir</code> command in
-<q>Secret/</q> (a new, encrypted volume), the <code>./inst CA</code> command creates
+<a href="Secret/"><q>Secret/</q></a> (a new, encrypted volume), the <code>./inst CA</code> command creates
 all of the certificates and keys mentioned above.  It may prompt for
 the institute's full name.
 </p>
@@ -766,7 +768,7 @@ files mentioned in the Nextcloud database dump).
 </p>
 
 <div class="org-src-container">
-<q>private/backup</q><pre class="src src-sh" id="org9d5954c"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">bash</span><span class="org-comment"> -e</span>
+<a href="private/backup"><q>private/backup</q></a><pre class="src src-sh" id="org9d5954c"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">bash</span><span class="org-comment"> -e</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span><span class="org-comment">DO NOT EDIT.  Maintained (will be replaced) by Ansible.</span>
 <span class="org-comment-delimiter">#</span>
@@ -877,7 +879,7 @@ This chapter introduces Ansible variables intended to simplify
 changes, like customization for another institute's particulars.  The
 variables are separated into <i>public</i> information (e.g. an institute's
 name) or <i>private</i> information (e.g. a network interface address), and
-stored in separate files: <q>public/vars.yml</q> and <q>private/vars.yml</q>.
+stored in separate files: <a href="public/vars.yml"><q>public/vars.yml</q></a> and <a href="private/var.yml"><q>private/vars.yml</q></a>.
 </p>
 
 <p>
@@ -898,7 +900,7 @@ replace <code>{{ domain_name }}</code> in the code with <code>small.example.org<
 </p>
 
 <div class="org-src-container">
-<q>public/vars.yml</q><pre class="src src-conf">---
+<a href="public/vars.yml"><q>public/vars.yml</q></a><pre class="src src-conf">---
 domain_name: small.example.org
 domain_priv: small.private
 </pre>
@@ -906,8 +908,8 @@ domain_priv: small.private
 
 <p>
 The private version of the institute's domain name should end with one
-of the top-level domains expected for this purpose: <q>.intranet</q>,
-<q>.internal</q>, <q>.private</q>, <q>.corp</q>, <q>.home</q> or <q>.lan</q>.<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>
+of the top-level domains expected for this purpose: <code>.intranet</code>,
+<code>.internal</code>, <code>.private</code>, <code>.corp</code>, <code>.home</code> or <code>.lan</code>.<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>
 </p>
 </div>
 </div>
@@ -1012,17 +1014,24 @@ example result follows the code.
 </pre>
 </div>
 
+<div class="TEXT" id="orgb4a45be">
+<p>
+=&gt; 10.62.17.0/24
+</p>
+
+</div>
+
 <p>
 The four private networks are named and given example CIDRs in the
 code block below.  The small institute treats these addresses as
 sensitive information so the code block below "tangles" into
-<q>private/vars.yml</q> rather than <q>public/vars.yml</q>.  Two of the
+<a href="private/vars.yml"><q>private/vars.yml</q></a> rather than <a href="public/vars.yml"><q>public/vars.yml</q></a>.  Two of the
 addresses are in <code>192.168</code> subnets because they are part of a test
 configuration using mostly-default VirtualBoxes (described <a href="#org74b454f">here</a>).
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">---
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">---
 private_net_cidr:           192.168.56.0/24
 public_vpn_net_cidr:        10.177.86.0/24
 campus_vpn_net_cidr:        10.84.138.0/24
@@ -1039,7 +1048,7 @@ e.g. <code>_net_and_mask</code> rather than <code>_net_cidr</code>.
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">private_net:             <span class="org-string">"{{ private_net_cidr | ipaddr('network') }}"</span>
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">private_net:             <span class="org-string">"{{ private_net_cidr | ipaddr('network') }}"</span>
 private_net_mask:        <span class="org-string">"{{ private_net_cidr | ipaddr('netmask') }}"</span>
 private_net_and_mask:      <span class="org-string">"{{ private_net }} {{ private_net_mask }}"</span>
 public_vpn_net:       <span class="org-string">"{{ public_vpn_net_cidr | ipaddr('network') }}"</span>
@@ -1066,7 +1075,7 @@ the institute's Internet domain name.
 </p>
 
 <div class="org-src-container">
-<q>public/vars.yml</q><pre class="src src-conf">front_addr: 192.168.15.5
+<a href="public/vars.yml"><q>public/vars.yml</q></a><pre class="src src-conf">front_addr: 192.168.15.5
 </pre>
 </div>
 
@@ -1090,7 +1099,7 @@ The following code block picks the obvious IP addresses for Core
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">core_addr_cidr:             <span class="org-string">"{{ private_net_cidr | ipaddr('1') }}"</span>
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">core_addr_cidr:             <span class="org-string">"{{ private_net_cidr | ipaddr('1') }}"</span>
 gate_addr_cidr:             <span class="org-string">"{{ private_net_cidr | ipaddr('2') }}"</span>
 gate_wifi_addr_cidr:        <span class="org-string">"{{ gate_wifi_net_cidr | ipaddr('1') }}"</span>
 wifi_wan_addr_cidr:         <span class="org-string">"{{ gate_wifi_net_cidr | ipaddr('2') }}"</span>
@@ -1180,8 +1189,8 @@ notebook$
 
 <p>
 The password was generated by <code>gpw</code>, saved in the administrator's
-password keep, and later added to <q>Secret/become.yml</q> as shown below.
-(Producing a working Ansible configuration with <q>Secret/become.yml</q>
+password keep, and later added to <a href="Secret/become.yml"><q>Secret/become.yml</q></a> as shown below.
+(Producing a working Ansible configuration with <a href="Secret/become.yml"><q>Secret/become.yml</q></a>
 file is described in <a href="#orgff33e02">The Ansible Configuration</a>.)
 </p>
 
@@ -1197,7 +1206,7 @@ notebook_     &gt;&gt;Secret/become.yml
 <p>
 After creating the <code>sysadm</code> account on the droplet, the administrator
 concatenated a personal public ssh key and the key found in
-<q>Secret/ssh_admin/</q> (created by <a href="#org671a111">The CA Command</a>) into an <q>admin_keys</q>
+<a href="Secret/ssh_admin/"><q>Secret/ssh_admin/</q></a> (created by <a href="#org671a111">The CA Command</a>) into an <q>admin_keys</q>
 file, copied it to the droplet, and installed it as the
 <q>authorized_keys</q> for <code>sysadm</code>.
 </p>
@@ -1299,8 +1308,8 @@ Is the information correct? [Y/n]
 
 <p>
 The password was generated by <code>gpw</code>, saved in the administrator's
-password keep, and later added to <q>Secret/become.yml</q> as shown below.
-(Producing a working Ansible configuration with <q>Secret/become.yml</q>
+password keep, and later added to <a href="Secret/become.yml"><q>Secret/become.yml</q></a> as shown below.
+(Producing a working Ansible configuration with <a href="Secret/become.yml"><q>Secret/become.yml</q></a>
 file is described in <a href="#orgff33e02">The Ansible Configuration</a>.)
 </p>
 
@@ -1340,7 +1349,7 @@ _                  libapache2-mod-php
 
 <p>
 Next, the administrator concatenated a personal public ssh key and the
-key found in <q>Secret/ssh_admin/</q> (created by <a href="#org671a111">The CA Command</a>) into an
+key found in <a href="Secret/ssh_admin/"><q>Secret/ssh_admin/</q></a> (created by <a href="#org671a111">The CA Command</a>) into an
 <q>admin_keys</q> file, copied it to Core, and installed it as the
 <q>authorized_keys</q> for <code>sysadm</code>.
 </p>
@@ -1420,7 +1429,7 @@ USB-Ethernet adapter, or a wireless adapter connected to a
 campground Wi-Fi access point, etc.</li>
 </ol>
 
-<pre class="example" id="org7728728">
+<pre class="example" id="org0804a36">
 =============== | ==================================================
                 |                                           Premises
           (Campus ISP)                                              
@@ -1443,7 +1452,7 @@ This avoids the need for a second Wi-Fi access point and leads to the
 following topology.
 </p>
 
-<pre class="example" id="orga571414">
+<pre class="example" id="orgc8b61ff">
 =============== | ==================================================
                 |                                           Premises
            (House ISP)                                              
@@ -1495,8 +1504,8 @@ Is the information correct? [Y/n]
 
 <p>
 The password was generated by <code>gpw</code>, saved in the administrator's
-password keep, and later added to <q>Secret/become.yml</q> as shown below.
-(Producing a working Ansible configuration with <q>Secret/become.yml</q>
+password keep, and later added to <a href="Secret/become.yml"><q>Secret/become.yml</q></a> as shown below.
+(Producing a working Ansible configuration with <a href="Secret/become.yml"><q>Secret/become.yml</q></a>
 file is described in <a href="#orgff33e02">The Ansible Configuration</a>.)
 </p>
 
@@ -1522,7 +1531,7 @@ $ sudo apt install openssh-server isc-dhcp-server netplan.io
 
 <p>
 Next, the administrator concatenated a personal public ssh key and the
-key found in <q>Secret/ssh_admin/</q> (created by <a href="#org671a111">The CA Command</a>) into an
+key found in <a href="Secret/ssh_admin/"><q>Secret/ssh_admin/</q></a> (created by <a href="#org671a111">The CA Command</a>) into an
 <q>admin_keys</q> file, copied it to Gate, and installed it as the
 <q>authorized_keys</q> for <code>sysadm</code>.
 </p>
@@ -1615,8 +1624,8 @@ uses the institute's CA and server certificates, and expects client
 certificates signed by the institute CA.
 </p>
 </div>
-<div id="outline-container-orgd751f3c" class="outline-3">
-<h3 id="orgd751f3c"><span class="section-number-3">6.1.</span> Include Particulars</h3>
+<div id="outline-container-orgf58fc42" class="outline-3">
+<h3 id="orgf58fc42"><span class="section-number-3">6.1.</span> Include Particulars</h3>
 <div class="outline-text-3" id="text-6-1">
 <p>
 The <code>front</code> role's tasks contain references to several common
@@ -1628,11 +1637,11 @@ Particulars</a> and <a href="#orge7fe793">Account Management</a>).
 
 <p>
 The code block below is the first to tangle into
-<q>roles/front/tasks/main.yml</q>.
+<a href="roles/front/tasks/main.yml"><q>roles/front/tasks/main.yml</q></a>.
 </p>
 
 <div class="org-src-container">
-<q>roles/front/tasks/main.yml</q><pre class="src src-conf">---
+<a href="roles/front/tasks/main.yml"><q>roles/front/tasks/main.yml</q></a><pre class="src src-conf">---
 - name: Include public variables.
   include_vars: ../public/vars.yml
   tags: accounts
@@ -1648,8 +1657,8 @@ The code block below is the first to tangle into
 </div>
 </div>
 </div>
-<div id="outline-container-orgd9ea791" class="outline-3">
-<h3 id="orgd9ea791"><span class="section-number-3">6.2.</span> Configure Hostname</h3>
+<div id="outline-container-org2cdf742" class="outline-3">
+<h3 id="org2cdf742"><span class="section-number-3">6.2.</span> Configure Hostname</h3>
 <div class="outline-text-3" id="text-6-2">
 <p>
 This task ensures that Front's <q>/etc/hostname</q> and <q>/etc/mailname</q> are
@@ -1658,7 +1667,7 @@ delivery.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">- name: Configure hostname.
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">- name: Configure hostname.
   become: yes
   copy:
     content: <span class="org-string">"{{ domain_name }}\n"</span>
@@ -1671,7 +1680,7 @@ delivery.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">---
 - name: Update hostname.
   become: yes
   command: hostname -F /etc/hostname
@@ -1701,7 +1710,7 @@ separate code block named <code>enable-resolved</code>.<sup><a id="fnr.2" class=
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install systemd-resolved.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=systemd-resolved
@@ -1773,8 +1782,8 @@ separate code block named <code>enable-resolved</code>.<sup><a id="fnr.2" class=
 </div>
 </div>
 </div>
-<div id="outline-container-orgb4fc0b7" class="outline-3">
-<h3 id="orgb4fc0b7"><span class="section-number-3">6.4.</span> Add Administrator to System Groups</h3>
+<div id="outline-container-org7985220" class="outline-3">
+<h3 id="org7985220"><span class="section-number-3">6.4.</span> Add Administrator to System Groups</h3>
 <div class="outline-text-3" id="text-6-4">
 <p>
 The administrator often needs to read (directories of) log files owned
@@ -1783,7 +1792,7 @@ these groups speeds up debugging.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Add {{ ansible_user }} to system groups.
   become: yes
   user:
@@ -1800,11 +1809,11 @@ these groups speeds up debugging.
 <p>
 The SSH service on Front needs to be known to Monkey.  The following
 tasks ensure this by replacing the automatically generated keys with
-those stored in <q>Secret/ssh_front/etc/ssh/</q> and restarting the server.
+those stored in <a href="Secret/ssh_front/etc/ssh/"><q>Secret/ssh_front/etc/ssh/</q></a> and restarting the server.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install SSH host keys.
   become: yes
   copy:
@@ -1823,7 +1832,7 @@ those stored in <q>Secret/ssh_front/etc/ssh/</q> and restarting the server.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload SSH server.
   become: yes
   systemd:
@@ -1833,8 +1842,8 @@ those stored in <q>Secret/ssh_front/etc/ssh/</q> and restarting the server.
 </div>
 </div>
 </div>
-<div id="outline-container-org79a6c80" class="outline-3">
-<h3 id="org79a6c80"><span class="section-number-3">6.6.</span> Configure Monkey</h3>
+<div id="outline-container-orgce99e39" class="outline-3">
+<h3 id="orgce99e39"><span class="section-number-3">6.6.</span> Configure Monkey</h3>
 <div class="outline-text-3" id="text-6-6">
 <p>
 The small institute runs cron jobs and web scripts that generate
@@ -1848,7 +1857,7 @@ key on Core.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create monkey.
   become: yes
   user:
@@ -1882,7 +1891,7 @@ Monkey uses Rsync to keep the institute's public web site up-to-date.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install rsync.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=rsync
@@ -1890,15 +1899,15 @@ Monkey uses Rsync to keep the institute's public web site up-to-date.
 </div>
 </div>
 </div>
-<div id="outline-container-orge48632b" class="outline-3">
-<h3 id="orge48632b"><span class="section-number-3">6.8.</span> Install Unattended Upgrades</h3>
+<div id="outline-container-orgf6a2764" class="outline-3">
+<h3 id="orgf6a2764"><span class="section-number-3">6.8.</span> Install Unattended Upgrades</h3>
 <div class="outline-text-3" id="text-6-8">
 <p>
 The institute prefers to install security updates as soon as possible.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install basic software.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=unattended-upgrades
@@ -1906,8 +1915,8 @@ The institute prefers to install security updates as soon as possible.
 </div>
 </div>
 </div>
-<div id="outline-container-org3664329" class="outline-3">
-<h3 id="org3664329"><span class="section-number-3">6.9.</span> Configure User Accounts</h3>
+<div id="outline-container-org754e3d3" class="outline-3">
+<h3 id="org754e3d3"><span class="section-number-3">6.9.</span> Configure User Accounts</h3>
 <div class="outline-text-3" id="text-6-9">
 <p>
 User accounts are created immediately so that Postfix and Dovecot can
@@ -1917,7 +1926,7 @@ recipient" replies.  The <a href="#orge7fe793">Account Management</a> chapter de
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create user accounts.
   become: yes
   user:
@@ -1950,8 +1959,8 @@ recipient" replies.  The <a href="#orge7fe793">Account Management</a> chapter de
 </div>
 </div>
 </div>
-<div id="outline-container-org725ad2b" class="outline-3">
-<h3 id="org725ad2b"><span class="section-number-3">6.10.</span> Trust Institute Certificate Authority</h3>
+<div id="outline-container-org615c988" class="outline-3">
+<h3 id="org615c988"><span class="section-number-3">6.10.</span> Trust Institute Certificate Authority</h3>
 <div class="outline-text-3" id="text-6-10">
 <p>
 Front should recognize the institute's Certificate Authority as
@@ -1961,7 +1970,7 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Trust the institute CA.
   become: yes
   copy:
@@ -1975,7 +1984,7 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Update CAs.
   become: yes
   command: update-ca-certificates
@@ -1983,8 +1992,8 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </div>
 </div>
 </div>
-<div id="outline-container-org507cda2" class="outline-3">
-<h3 id="org507cda2"><span class="section-number-3">6.11.</span> Install Server Certificate</h3>
+<div id="outline-container-org8773a2c" class="outline-3">
+<h3 id="org8773a2c"><span class="section-number-3">6.11.</span> Install Server Certificate</h3>
 <div class="outline-text-3" id="text-6-11">
 <p>
 The servers on Front use the same certificate (and key) to
@@ -1994,7 +2003,7 @@ readable by <code>root</code>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install server certificate/key.
   become: yes
   copy:
@@ -2133,7 +2142,7 @@ start and enable the service.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Postfix.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=postfix
@@ -2189,7 +2198,7 @@ start and enable the service.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Postfix.
   become: yes
   systemd:
@@ -2224,7 +2233,7 @@ created by a more specialized role.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">- name: Install institute email aliases.
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">- name: Install institute email aliases.
   become: yes
   blockinfile:
     block: |
@@ -2240,7 +2249,7 @@ created by a more specialized role.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: New aliases.
   become: yes
   command: newaliases
@@ -2248,8 +2257,8 @@ created by a more specialized role.
 </div>
 </div>
 </div>
-<div id="outline-container-orgc81ba1c" class="outline-3">
-<h3 id="orgc81ba1c"><span class="section-number-3">6.14.</span> Configure Dovecot IMAPd</h3>
+<div id="outline-container-org3ff50b5" class="outline-3">
+<h3 id="org3ff50b5"><span class="section-number-3">6.14.</span> Configure Dovecot IMAPd</h3>
 <div class="outline-text-3" id="text-6-14">
 <p>
 Front uses Dovecot's IMAPd to allow user Fetchmail jobs on Core to
@@ -2277,7 +2286,7 @@ and enables it to start at every reboot.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Dovecot IMAPd.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=dovecot-imapd
@@ -2309,7 +2318,7 @@ and enables it to start at every reboot.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Dovecot.
   become: yes
   systemd:
@@ -2530,7 +2539,7 @@ e.g. <q>/etc/apache2/sites-available/small.example.org.conf</q> and runs
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Apache2.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=apache2
@@ -2634,7 +2643,7 @@ e.g. <q>/etc/apache2/sites-available/small.example.org.conf</q> and runs
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Apache2.
   become: yes
   systemd:
@@ -2649,7 +2658,7 @@ that it does not interfere with its replacement.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Disable default vhosts.
   become: yes
   file:
@@ -2667,7 +2676,7 @@ same records as <q>access.log</q>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Disable other-vhosts-access-log option.
   become: yes
   file:
@@ -2683,7 +2692,7 @@ the users' <q>~/Public/HTML/</q> directories.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create UserDir.
   become: yes
   file:
@@ -2713,8 +2722,8 @@ the users' <q>~/Public/HTML/</q> directories.
 </div>
 </div>
 </div>
-<div id="outline-container-orgb08da16" class="outline-3">
-<h3 id="orgb08da16"><span class="section-number-3">6.16.</span> Configure OpenVPN</h3>
+<div id="outline-container-org567b473" class="outline-3">
+<h3 id="org567b473"><span class="section-number-3">6.16.</span> Configure OpenVPN</h3>
 <div class="outline-text-3" id="text-6-16">
 <p>
 Front uses OpenVPN to provide the institute's public VPN service.  The
@@ -2795,7 +2804,7 @@ configure the OpenVPN server on Front.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install OpenVPN.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=openvpn
@@ -2901,7 +2910,7 @@ configure the OpenVPN server on Front.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart OpenVPN.
   become: yes
   systemd:
@@ -2950,7 +2959,7 @@ The first step is to install Kamailio.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Kamailio.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=kamailio
@@ -2965,7 +2974,7 @@ be started before the <code>tun</code> device has appeared.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create Kamailio/Systemd configuration drop.
   become: yes
   file:
@@ -2985,7 +2994,7 @@ be started before the <code>tun</code> device has appeared.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload Systemd.
   become: yes
   command: systemctl daemon-reload
@@ -2997,7 +3006,7 @@ Finally, Kamailio can be configured and started.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/front/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/tasks/main.yml"><q>roles_t/front/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure Kamailio.
   become: yes
   copy:
@@ -3016,7 +3025,7 @@ Finally, Kamailio can be configured and started.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/front/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/front/handlers/main.yml"><q>roles_t/front/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Kamailio.
   become: yes
   systemd:
@@ -3038,8 +3047,8 @@ Debian install and remote access to a privileged, administrator's
 account.  (For details, see <a href="#org8d60b7b">The Core Machine</a>.)
 </p>
 </div>
-<div id="outline-container-org70b2741" class="outline-3">
-<h3 id="org70b2741"><span class="section-number-3">7.1.</span> Include Particulars</h3>
+<div id="outline-container-orga90d99c" class="outline-3">
+<h3 id="orga90d99c"><span class="section-number-3">7.1.</span> Include Particulars</h3>
 <div class="outline-text-3" id="text-7-1">
 <p>
 The first task, as in <a href="#org9240129">The Front Role</a>, is to include the institute
@@ -3047,7 +3056,7 @@ particulars and membership roll.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">---
 - name: Include public variables.
   include_vars: ../public/vars.yml
   tags: accounts
@@ -3061,8 +3070,8 @@ particulars and membership roll.
 </div>
 </div>
 </div>
-<div id="outline-container-org488abe5" class="outline-3">
-<h3 id="org488abe5"><span class="section-number-3">7.2.</span> Configure Hostname</h3>
+<div id="outline-container-orgf87fff2" class="outline-3">
+<h3 id="orgf87fff2"><span class="section-number-3">7.2.</span> Configure Hostname</h3>
 <div class="outline-text-3" id="text-7-2">
 <p>
 This task ensures that Core's <q>/etc/hostname</q> and <q>/etc/mailname</q> are
@@ -3073,7 +3082,7 @@ proper email delivery.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure hostname.
   become: yes
   copy:
@@ -3087,7 +3096,7 @@ proper email delivery.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">---
 - name: Update hostname.
   become: yes
   command: hostname -F /etc/hostname
@@ -3095,8 +3104,8 @@ proper email delivery.
 </div>
 </div>
 </div>
-<div id="outline-container-org87143f0" class="outline-3">
-<h3 id="org87143f0"><span class="section-number-3">7.3.</span> Enable Systemd Resolved</h3>
+<div id="outline-container-org04ee34b" class="outline-3">
+<h3 id="org04ee34b"><span class="section-number-3">7.3.</span> Enable Systemd Resolved</h3>
 <div class="outline-text-3" id="text-7-3">
 <p>
 Core starts the <code>systemd-networkd</code> and <code>systemd-resolved</code> service
@@ -3104,7 +3113,7 @@ units on boot.  See <a href="#org5738867">Enable Systemd Resolved</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install systemd-resolved.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=systemd-resolved
@@ -3140,8 +3149,8 @@ units on boot.  See <a href="#org5738867">Enable Systemd Resolved</a>.
 </div>
 </div>
 </div>
-<div id="outline-container-org223a52e" class="outline-3">
-<h3 id="org223a52e"><span class="section-number-3">7.4.</span> Configure Systemd Resolved</h3>
+<div id="outline-container-org31aa8c4" class="outline-3">
+<h3 id="org31aa8c4"><span class="section-number-3">7.4.</span> Configure Systemd Resolved</h3>
 <div class="outline-text-3" id="text-7-4">
 <p>
 Core runs the campus name server, so Resolved is configured to use it
@@ -3150,7 +3159,7 @@ list, and to disable its cache and stub listener.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure resolved.
   become: yes
   lineinfile:
@@ -3170,7 +3179,7 @@ list, and to disable its cache and stub listener.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload Systemd.
   become: yes
   command: systemctl daemon-reload
@@ -3198,7 +3207,7 @@ VPN.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install netplan.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=netplan.io
@@ -3224,7 +3233,7 @@ VPN.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Apply netplan.
   become: yes
   command: netplan apply
@@ -3244,16 +3253,16 @@ Service.
 </p>
 
 <p>
-The example configuration file, <q>private/core-dhcpd.conf</q>, uses
+The example configuration file, <a href="private/core-dhcpd.conf"><q>private/core-dhcpd.conf</q></a>, uses
 RFC3442's extension to encode a second (non-default) static route.
 The default route is through the campus ISP at Gate.  A second route
 directs campus traffic to the Front VPN through Core.  This is just an
 example file.  The administrator adds and removes actual machines from
-the actual <q>private/core-dhcpd.conf</q> file.
+the actual <a href="private/core-dhcpd.conf"><q>private/core-dhcpd.conf</q></a> file.
 </p>
 
 <div class="org-src-container">
-<q>private/core-dhcpd.conf</q><pre class="src src-conf">option domain-name <span class="org-string">"small.private"</span>;
+<a href="private/core-dhcpd.conf"><q>private/core-dhcpd.conf</q></a><pre class="src src-conf">option domain-name <span class="org-string">"small.private"</span>;
 option domain-name-servers 192.168.56.1;
 
 default-lease-time 3600;
@@ -3286,11 +3295,11 @@ log-facility daemon;
 
 <p>
 The following tasks install the ISC's DHCP server and configure it
-with the real <q>private/core-dhcpd.conf</q> (<i>not</i> the example above).
+with the real <a href="private/core-dhcpd.conf"><q>private/core-dhcpd.conf</q></a> (<i>not</i> the example above).
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install DHCP server.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=isc-dhcp-server
@@ -3320,7 +3329,7 @@ with the real <q>private/core-dhcpd.conf</q> (<i>not</i> the example above).
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart DHCP server.
   become: yes
   systemd:
@@ -3345,7 +3354,7 @@ The following tasks install and configure BIND9 on Core.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install BIND9.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=bind9
@@ -3440,7 +3449,7 @@ The following tasks install and configure BIND9 on Core.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload BIND9.
   become: yes
   systemd:
@@ -3524,7 +3533,7 @@ craps up <q>/var/log/</q> and the Systemd journal.
 </div>
 
 <div class="org-src-container">
-<q>private/db.domain</q><pre class="src src-conf">;
+<a href="private/db.domain"><q>private/db.domain</q></a><pre class="src src-conf">;
 ; BIND data file for a small institute<span class="org-string">'s PRIVATE domain names.</span>
 <span class="org-string">;</span>
 <span class="org-string">$TTL    604800</span>
@@ -3552,7 +3561,7 @@ craps up <q>/var/log/</q> and the Systemd journal.
 </div>
 
 <div class="org-src-container">
-<q>private/db.private</q><pre class="src src-conf">;
+<a href="private/db.private"><q>private/db.private</q></a><pre class="src src-conf">;
 ; BIND reverse data file for a small institute<span class="org-string">'s private Ethernet.</span>
 <span class="org-string">;</span>
 <span class="org-string">$TTL    604800</span>
@@ -3571,7 +3580,7 @@ craps up <q>/var/log/</q> and the Systemd journal.
 </div>
 
 <div class="org-src-container">
-<q>private/db.public_vpn</q><pre class="src src-conf">;
+<a href="private/db.public_vpn"><q>private/db.public_vpn</q></a><pre class="src src-conf">;
 ; BIND reverse data file for a small institute<span class="org-string">'s public VPN.</span>
 <span class="org-string">;</span>
 <span class="org-string">$TTL    604800</span>
@@ -3590,7 +3599,7 @@ craps up <q>/var/log/</q> and the Systemd journal.
 </div>
 
 <div class="org-src-container">
-<q>private/db.campus_vpn</q><pre class="src src-conf">;
+<a href="private/db.campus_vpn"><q>private/db.campus_vpn</q></a><pre class="src src-conf">;
 ; BIND reverse data file for a small institute<span class="org-string">'s campus VPN.</span>
 <span class="org-string">;</span>
 <span class="org-string">$TTL    604800</span>
@@ -3608,8 +3617,8 @@ craps up <q>/var/log/</q> and the Systemd journal.
 </div>
 </div>
 </div>
-<div id="outline-container-orgcd8e7d5" class="outline-3">
-<h3 id="orgcd8e7d5"><span class="section-number-3">7.8.</span> Add Administrator to System Groups</h3>
+<div id="outline-container-org6baad6a" class="outline-3">
+<h3 id="org6baad6a"><span class="section-number-3">7.8.</span> Add Administrator to System Groups</h3>
 <div class="outline-text-3" id="text-7-8">
 <p>
 The administrator often needs to read (directories of) log files owned
@@ -3618,7 +3627,7 @@ these groups speeds up debugging.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Add {{ ansible_user }} to system groups.
   become: yes
   user:
@@ -3629,8 +3638,8 @@ these groups speeds up debugging.
 </div>
 </div>
 </div>
-<div id="outline-container-org55c2979" class="outline-3">
-<h3 id="org55c2979"><span class="section-number-3">7.9.</span> Configure Monkey</h3>
+<div id="outline-container-org718cfbd" class="outline-3">
+<h3 id="org718cfbd"><span class="section-number-3">7.9.</span> Configure Monkey</h3>
 <div class="outline-text-3" id="text-7-9">
 <p>
 The small institute runs cron jobs and web scripts that generate
@@ -3641,7 +3650,7 @@ described in <a href="#org1ac6235">*Configure Apache2</a>).
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create monkey.
   become: yes
   user:
@@ -3705,7 +3714,7 @@ The institute prefers to install security updates as soon as possible.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install basic software.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=unattended-upgrades
@@ -3722,7 +3731,7 @@ with Nextcloud on the command line.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install expect.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=expect
@@ -3730,8 +3739,8 @@ with Nextcloud on the command line.
 </div>
 </div>
 </div>
-<div id="outline-container-org3283a63" class="outline-3">
-<h3 id="org3283a63"><span class="section-number-3">7.12.</span> Configure User Accounts</h3>
+<div id="outline-container-org55ba8e2" class="outline-3">
+<h3 id="org55ba8e2"><span class="section-number-3">7.12.</span> Configure User Accounts</h3>
 <div class="outline-text-3" id="text-7-12">
 <p>
 User accounts are created immediately so that backups can begin
@@ -3740,7 +3749,7 @@ describes the <code>members</code> and <code>usernames</code> variables.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create user accounts.
   become: yes
   user:
@@ -3773,8 +3782,8 @@ describes the <code>members</code> and <code>usernames</code> variables.
 </div>
 </div>
 </div>
-<div id="outline-container-orgeee8ad5" class="outline-3">
-<h3 id="orgeee8ad5"><span class="section-number-3">7.13.</span> Trust Institute Certificate Authority</h3>
+<div id="outline-container-org36bf9fc" class="outline-3">
+<h3 id="org36bf9fc"><span class="section-number-3">7.13.</span> Trust Institute Certificate Authority</h3>
 <div class="outline-text-3" id="text-7-13">
 <p>
 Core should recognize the institute's Certificate Authority as
@@ -3784,7 +3793,7 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Trust the institute CA.
   become: yes
   copy:
@@ -3798,7 +3807,7 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Update CAs.
   become: yes
   command: update-ca-certificates
@@ -3806,8 +3815,8 @@ X.509 certificates is available in <a href="#org6519b0c">Keys</a>.
 </div>
 </div>
 </div>
-<div id="outline-container-org47f3ff1" class="outline-3">
-<h3 id="org47f3ff1"><span class="section-number-3">7.14.</span> Install Server Certificate</h3>
+<div id="outline-container-org22d2cc7" class="outline-3">
+<h3 id="org22d2cc7"><span class="section-number-3">7.14.</span> Install Server Certificate</h3>
 <div class="outline-text-3" id="text-7-14">
 <p>
 The servers on Core use the same certificate (and key) to authenticate
@@ -3816,7 +3825,7 @@ themselves to institute clients.  They share the <q>/etc/server.crt</q> and
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install server certificate/key.
   become: yes
   copy:
@@ -3845,7 +3854,7 @@ The default daemon's default configuration is fine.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install NTP.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=ntp
@@ -3952,7 +3961,7 @@ enable the service.  Whenever <q>/etc/postfix/transport</q> is changed, the
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Postfix.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=postfix
@@ -4005,7 +4014,7 @@ enable the service.  Whenever <q>/etc/postfix/transport</q> is changed, the
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Postfix.
   become: yes
   systemd:
@@ -4035,7 +4044,7 @@ installed by more specialized roles.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install institute email aliases.
   become: yes
   blockinfile:
@@ -4052,7 +4061,7 @@ installed by more specialized roles.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: New aliases.
   become: yes
   command: newaliases
@@ -4060,8 +4069,8 @@ installed by more specialized roles.
 </div>
 </div>
 </div>
-<div id="outline-container-org47b61d3" class="outline-3">
-<h3 id="org47b61d3"><span class="section-number-3">7.18.</span> Configure Dovecot IMAPd</h3>
+<div id="outline-container-org49d8726" class="outline-3">
+<h3 id="org49d8726"><span class="section-number-3">7.18.</span> Configure Dovecot IMAPd</h3>
 <div class="outline-text-3" id="text-7-18">
 <p>
 Core uses Dovecot's IMAPd to store and serve member emails.  As on
@@ -4089,7 +4098,7 @@ and enables it to start at every reboot.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Dovecot IMAPd.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=dovecot-imapd
@@ -4116,7 +4125,7 @@ and enables it to start at every reboot.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Dovecot.
   become: yes
   systemd:
@@ -4191,7 +4200,7 @@ provided the Core service.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install fetchmail.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=fetchmail
@@ -4267,7 +4276,7 @@ stopped and disabled from restarting at boot, deleted even.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Stop former user fetchmail services.
   become: yes
   systemd:
@@ -4493,7 +4502,7 @@ interfere with mapping URLs to the correct virtual host.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Apache2.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=apache2
@@ -4523,7 +4532,7 @@ The <code>a2ensite</code> command enables them.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install live web site.
   become: yes
   copy:
@@ -4634,7 +4643,7 @@ The <code>a2ensite</code> command enables them.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Apache2.
   become: yes
   systemd:
@@ -4654,7 +4663,7 @@ Monkey on Core runs <q>/usr/local/sbin/webupdate</q> every 15 minutes via a
 </p>
 
 <div class="org-src-container">
-<q>private/webupdate</q><pre class="src src-sh" id="orgbb22232"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">bash</span><span class="org-comment"> -e</span>
+<a href="private/webupdate"><q>private/webupdate</q></a><pre class="src src-sh" id="orgbb22232"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">bash</span><span class="org-comment"> -e</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span><span class="org-comment">DO NOT EDIT.  This file was tangled from institute.org.</span>
 
@@ -4668,13 +4677,13 @@ rsync -avz --delete --chmod=g-w         <span class="org-sh-escaped-newline">\</
 </div>
 
 <p>
-The following tasks install the <q>webupdate</q> script from <q>private/</q>,
+The following tasks install the <q>webupdate</q> script from <a href="private/"><q>private/</q></a>,
 and create Monkey's <code>cron</code> job.  An example <q>webupdate</q> script is
 provided <a href="#orgbb22232">here</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: <span class="org-string">"Install Monkey's webupdate script."</span>
   become: yes
   copy:
@@ -4740,7 +4749,7 @@ for Core.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install OpenVPN.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=openvpn
@@ -4807,7 +4816,7 @@ for Core.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart OpenVPN.
   become: yes
   systemd:
@@ -4838,7 +4847,7 @@ Core and Campus (and thus Gate) machines.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install NAGIOS4.
   become: yes
   apt:
@@ -4890,7 +4899,7 @@ Core and Campus (and thus Gate) machines.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload NAGIOS4.
   become: yes
   systemd:
@@ -4910,7 +4919,7 @@ used here <i>may</i> specify plugin arguments.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf"><span class="org-type">define host</span> {
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf"><span class="org-type">define host</span> {
     use                     linux-server
     host_name               core
     address                 127.0.0.1
@@ -4986,7 +4995,7 @@ small institute substitutes a slightly modified version,
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/files/inst_sensors</q><pre class="src src-sh"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">sh</span>
+<a href="roles_t/core/files/inst_sensors"><q>roles_t/core/files/inst_sensors</q></a><pre class="src src-sh"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/</span><span class="org-keyword">sh</span>
 
 <span class="org-variable-name">PATH</span>=<span class="org-string">"/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"</span>
 <span class="org-builtin">export</span> PATH
@@ -5071,7 +5080,7 @@ Core.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define command</span> {
     command_name            inst_sensors
     command_line            /usr/local/sbin/inst_sensors
@@ -5118,19 +5127,12 @@ pings.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define host</span> {
     use                     linux-server
     host_name               gate
     address                 {{ gate_addr }}
 }
-
-<span class="org-type">define service</span> {
-    use                     local-service
-    host_name               gate
-    service_description     PING
-    check_command           check_ping!100.0,20%!500.0,60%
-}
 </pre>
 </div>
 
@@ -5140,7 +5142,7 @@ space on the root partition.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/files/nrpe.cfg</q><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_root</span>]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /
+<a href="roles_t/campus/files/nrpe.cfg"><q>roles_t/campus/files/nrpe.cfg</q></a><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_root</span>]=/usr/lib/nagios/plugins/check_disk -w 20% -c 10% -p /
 </pre>
 </div>
 
@@ -5149,7 +5151,7 @@ Monitor <code>inst_root</code> on Gate.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define service</span> {
     use                     generic-service
     host_name               gate
@@ -5164,7 +5166,7 @@ Monitor <code>check_load</code> on Gate.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define service</span> {
     use                     generic-service
     host_name               gate
@@ -5179,7 +5181,7 @@ Monitor <code>check_zombie_procs</code> and <code>check_total_procs</code> on Ga
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define service</span> {
     use                     generic-service
     host_name               gate
@@ -5202,7 +5204,7 @@ usage.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/files/nrpe.cfg</q><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_swap</span>]=/usr/lib/nagios/plugins/check_swap -w 20% -c 10%
+<a href="roles_t/campus/files/nrpe.cfg"><q>roles_t/campus/files/nrpe.cfg</q></a><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_swap</span>]=/usr/lib/nagios/plugins/check_swap -w 20% -c 10%
 </pre>
 </div>
 
@@ -5211,7 +5213,7 @@ Monitor <code>inst_swap</code> on Gate.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define service</span> {
     use                     generic-service
     host_name               gate
@@ -5221,28 +5223,13 @@ Monitor <code>inst_swap</code> on Gate.
 </pre>
 </div>
 
-<p>
-Monitor Gate's SSH service.
-</p>
-
-<div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
-<span class="org-type">define service</span> {
-    use                     generic-service
-    host_name               gate
-    service_description     SSH
-    check_command           check_ssh
-}
-</pre>
-</div>
-
 <p>
 For all campus NRPE servers: an <code>inst_sensors</code> command to report core
 CPU temperatures.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/files/nrpe.cfg</q><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_sensors</span>]=/usr/local/sbin/inst_sensors
+<a href="roles_t/campus/files/nrpe.cfg"><q>roles_t/campus/files/nrpe.cfg</q></a><pre class="src src-conf"><span class="org-variable-name">command</span>[<span class="org-constant">inst_sensors</span>]=/usr/local/sbin/inst_sensors
 </pre>
 </div>
 
@@ -5251,7 +5238,7 @@ Monitor <code>inst_sensors</code> on Gate.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/nagios.cfg</q><pre class="src src-conf">
+<a href="roles_t/core/templates/nagios.cfg"><q>roles_t/core/templates/nagios.cfg</q></a><pre class="src src-conf">
 <span class="org-type">define service</span> {
     use                     generic-service
     host_name               gate
@@ -5267,12 +5254,12 @@ Monitor <code>inst_sensors</code> on Gate.
 <h3 id="org04cc272"><span class="section-number-3">7.24.</span> Configure Backups</h3>
 <div class="outline-text-3" id="text-7-24">
 <p>
-The following task installs the <q>backup</q> script from <q>private/</q>.  An
+The following task installs the <q>backup</q> script from <a href="private/"><q>private/</q></a>.  An
 example script is provided in <a href="#org9d5954c">here</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install backup script.
   become: yes
   copy:
@@ -5305,7 +5292,7 @@ installing a cron job.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install packages required by Nextcloud.
   become: yes
   apt:
@@ -5321,7 +5308,7 @@ Next, a number of Apache2 modules are enabled.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Enable Apache2 modules for Nextcloud.
   become: yes
   apache2_module:
@@ -5339,7 +5326,7 @@ Administration Guide (sub-section <a href="https://docs.nextcloud.com/server/lat
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/files/nextcloud.conf</q><pre class="src src-conf">Alias /nextcloud <span class="org-string">"/var/www/nextcloud/"</span>
+<a href="roles_t/core/files/nextcloud.conf"><q>roles_t/core/files/nextcloud.conf</q></a><pre class="src src-conf">Alias /nextcloud <span class="org-string">"/var/www/nextcloud/"</span>
 
 &lt;Directory /var/www/nextcloud/&gt;
     Require all granted
@@ -5354,7 +5341,7 @@ Administration Guide (sub-section <a href="https://docs.nextcloud.com/server/lat
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Nextcloud web configuration.
   become: yes
   copy:
@@ -5379,7 +5366,7 @@ virtual host's document root.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/files/nextcloud.conf</q><pre class="src src-conf">
+<a href="roles_t/core/files/nextcloud.conf"><q>roles_t/core/files/nextcloud.conf</q></a><pre class="src src-conf">
 &lt;Directory /var/www/html/&gt;
     &lt;IfModule mod_rewrite.c&gt;
         RewriteEngine on
@@ -5405,7 +5392,7 @@ page.  The following portion of <q>nextcloud.conf</q> sets a
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/files/nextcloud.conf</q><pre class="src src-conf">
+<a href="roles_t/core/files/nextcloud.conf"><q>roles_t/core/files/nextcloud.conf</q></a><pre class="src src-conf">
 &lt;IfModule mod_headers.c&gt;
     Header always set \
         Strict-Transport-Security <span class="org-string">"max-age=15552000; includeSubDomains"</span>
@@ -5421,7 +5408,7 @@ cloud FUBARs.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Add {{ ansible_user }} to web server group.
   become: yes
   user:
@@ -5437,7 +5424,7 @@ jobs.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create Nextcloud cron job.
   become: yes
   cron:
@@ -5453,12 +5440,12 @@ jobs.
 <p>
 Nextcloud's MariaDB database (and user) are created by the following
 tasks.  The user's password is taken from the <code>nextcloud_dbpass</code>
-variable, kept in <q>private/vars.yml</q>, and generated e.g. with
+variable, kept in <a href="private/vars.yml"><q>private/vars.yml</q></a>, and generated e.g. with
 the <code>apg -n 1 -x 12 -m 12</code> command.
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">nextcloud_dbpass:           ippAgmaygyob
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">nextcloud_dbpass:           ippAgmaygyob
 </pre>
 </div>
 
@@ -5515,7 +5502,7 @@ its document root.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Link /var/www/nextcloud.
   become: yes
   file:
@@ -5537,7 +5524,7 @@ performance, as recommended by Nextcloud.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Set PHP memory_limit for Nextcloud.
   become: yes
   lineinfile:
@@ -5769,7 +5756,7 @@ afterwards tasks causes them to skip rather than fail.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Test for /Nextcloud/nextcloud/.
   stat:
     path: /Nextcloud/nextcloud
@@ -5800,7 +5787,7 @@ Pretty URLs (below).
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure Nextcloud trusted domains.
   become: yes
   replace:
@@ -5832,7 +5819,7 @@ enables it.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure Nextcloud memcache.
   become: yes
   lineinfile:
@@ -5854,7 +5841,7 @@ and <code>htaccess.RewriteBase</code>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure Nextcloud for Pretty URLs.
   become: yes
   lineinfile:
@@ -5880,12 +5867,12 @@ a complaint on the Settings &gt; Administration &gt; Overview web page.
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">nextcloud_region:           US
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">nextcloud_region:           US
 </pre>
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure Nextcloud phone region.
   become: yes
   lineinfile:
@@ -5908,7 +5895,7 @@ run before the next backup.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Create /Nextcloud/dbbackup.cnf.
   no_log: yes
   become: yes
@@ -5967,15 +5954,15 @@ applied first, by which Gate gets a campus machine's DNS and Postfix
 configurations, etc.
 </p>
 </div>
-<div id="outline-container-org7683327" class="outline-3">
-<h3 id="org7683327"><span class="section-number-3">8.1.</span> Include Particulars</h3>
+<div id="outline-container-org0fd1c05" class="outline-3">
+<h3 id="org0fd1c05"><span class="section-number-3">8.1.</span> Include Particulars</h3>
 <div class="outline-text-3" id="text-8-1">
 <p>
 The following should be familiar boilerplate by now.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">---
 - name: Include public variables.
   include_vars: ../public/vars.yml
   tags: accounts
@@ -6001,12 +5988,12 @@ be revised more frequently as the campus ISP changes.
 
 <p>
 Netplan is configured to identify the interfaces by their MAC
-addresses, which must be provided in <q>private/vars.yml</q>, as in the
+addresses, which must be provided in <a href="private/vars.yml"><q>private/vars.yml</q></a>, as in the
 example code here.
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">gate_lan_mac:               ff:ff:ff:ff:ff:ff
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">gate_lan_mac:               ff:ff:ff:ff:ff:ff
 gate_wifi_mac:              ff:ff:ff:ff:ff:ff
 gate_isp_mac:               ff:ff:ff:ff:ff:ff
 </pre>
@@ -6018,7 +6005,7 @@ new network plan.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install netplan (gate).
   become: yes
   <span class="org-variable-name">apt: pkg</span>=netplan.io
@@ -6072,7 +6059,7 @@ new network plan.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/gate/handlers/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/gate/handlers/main.yml"><q>roles_t/gate/handlers/main.yml</q></a><pre class="src src-conf">---
 - name: Apply netplan.
   become: yes
   command: netplan apply
@@ -6192,7 +6179,7 @@ sudo ufw enable
 
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install UFW.
   become:
   <span class="org-variable-name">apt: pkg</span>=ufw
@@ -6259,7 +6246,7 @@ AP's MAC address.
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">wifi_wan_mac:               94:83:c4:19:7d:57
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">wifi_wan_mac:               94:83:c4:19:7d:57
 wifi_wan_name:              campus-wifi-ap
 </pre>
 </div>
@@ -6287,7 +6274,7 @@ the daemon listens <i>only</i> on the Gate-WiFi network interface.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install DHCP server.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=isc-dhcp-server
@@ -6332,7 +6319,7 @@ the daemon listens <i>only</i> on the Gate-WiFi network interface.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/gate/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/handlers/main.yml"><q>roles_t/gate/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart DHCP server.
   become: yes
   systemd:
@@ -6342,8 +6329,8 @@ the daemon listens <i>only</i> on the Gate-WiFi network interface.
 </div>
 </div>
 </div>
-<div id="outline-container-orga5d4d07" class="outline-3">
-<h3 id="orga5d4d07"><span class="section-number-3">8.6.</span> Install Server Certificate</h3>
+<div id="outline-container-org203c172" class="outline-3">
+<h3 id="org203c172"><span class="section-number-3">8.6.</span> Install Server Certificate</h3>
 <div class="outline-text-3" id="text-8-6">
 <p>
 The (OpenVPN) server on Gate uses an institute certificate (and key)
@@ -6353,7 +6340,7 @@ and Front) do.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install server certificate/key.
   become: yes
   copy:
@@ -6370,8 +6357,8 @@ and Front) do.
 </div>
 </div>
 </div>
-<div id="outline-container-orga85e634" class="outline-3">
-<h3 id="orga85e634"><span class="section-number-3">8.7.</span> Configure OpenVPN</h3>
+<div id="outline-container-org760a95a" class="outline-3">
+<h3 id="org760a95a"><span class="section-number-3">8.7.</span> Configure OpenVPN</h3>
 <div class="outline-text-3" id="text-8-7">
 <p>
 Gate uses OpenVPN to provide the institute's campus VPN service.  Its
@@ -6429,7 +6416,7 @@ configure the OpenVPN server on Gate.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/gate/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/tasks/main.yml"><q>roles_t/gate/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install OpenVPN.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=openvpn
@@ -6505,7 +6492,7 @@ configure the OpenVPN server on Gate.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/gate/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/gate/handlers/main.yml"><q>roles_t/gate/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart OpenVPN.
   become: yes
   systemd:
@@ -6534,15 +6521,15 @@ Wireless campus devices can get a key to the campus VPN from the
 configured manually.
 </p>
 </div>
-<div id="outline-container-orgc2b5a03" class="outline-3">
-<h3 id="orgc2b5a03"><span class="section-number-3">9.1.</span> Include Particulars</h3>
+<div id="outline-container-org9d81c0f" class="outline-3">
+<h3 id="org9d81c0f"><span class="section-number-3">9.1.</span> Include Particulars</h3>
 <div class="outline-text-3" id="text-9-1">
 <p>
 The following should be familiar boilerplate by now.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">---
 - name: Include public variables.
   include_vars: ../public/vars.yml
 - name: Include private variables.
@@ -6551,15 +6538,15 @@ The following should be familiar boilerplate by now.
 </div>
 </div>
 </div>
-<div id="outline-container-org3acf8ab" class="outline-3">
-<h3 id="org3acf8ab"><span class="section-number-3">9.2.</span> Configure Hostname</h3>
+<div id="outline-container-orgcc676de" class="outline-3">
+<h3 id="orgcc676de"><span class="section-number-3">9.2.</span> Configure Hostname</h3>
 <div class="outline-text-3" id="text-9-2">
 <p>
 Clients should be using the expected host name.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure hostname.
   become: yes
   copy:
@@ -6577,7 +6564,7 @@ Clients should be using the expected host name.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">---
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">---
 - name: Update hostname.
   become: yes
   command: hostname -F /etc/hostname
@@ -6585,8 +6572,8 @@ Clients should be using the expected host name.
 </div>
 </div>
 </div>
-<div id="outline-container-orgfb12bf4" class="outline-3">
-<h3 id="orgfb12bf4"><span class="section-number-3">9.3.</span> Enable Systemd Resolved</h3>
+<div id="outline-container-orge776843" class="outline-3">
+<h3 id="orge776843"><span class="section-number-3">9.3.</span> Enable Systemd Resolved</h3>
 <div class="outline-text-3" id="text-9-3">
 <p>
 Campus machines start the <code>systemd-networkd</code> and <code>systemd-resolved</code>
@@ -6594,7 +6581,7 @@ service units on boot.  See <a href="#org5738867">Enable Systemd Resolved</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install systemd-resolved.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=systemd-resolved
@@ -6630,8 +6617,8 @@ service units on boot.  See <a href="#org5738867">Enable Systemd Resolved</a>.
 </div>
 </div>
 </div>
-<div id="outline-container-org4977a1c" class="outline-3">
-<h3 id="org4977a1c"><span class="section-number-3">9.4.</span> Configure Systemd Resolved</h3>
+<div id="outline-container-org85c46f2" class="outline-3">
+<h3 id="org85c46f2"><span class="section-number-3">9.4.</span> Configure Systemd Resolved</h3>
 <div class="outline-text-3" id="text-9-4">
 <p>
 Campus machines use the campus name server on Core (or <code>dns.google</code>),
@@ -6639,7 +6626,7 @@ and include the institute's private domain in their search lists.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure resolved.
   become: yes
   lineinfile:
@@ -6657,7 +6644,7 @@ and include the institute's private domain in their search lists.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload Systemd.
   become: yes
   command: systemctl daemon-reload
@@ -6681,7 +6668,7 @@ and file timestamps.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Configure timesyncd.
   become: yes
   lineinfile:
@@ -6692,7 +6679,7 @@ and file timestamps.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart systemd-timesyncd.
   become: yes
   systemd:
@@ -6702,8 +6689,8 @@ and file timestamps.
 </div>
 </div>
 </div>
-<div id="outline-container-orged16e9b" class="outline-3">
-<h3 id="orged16e9b"><span class="section-number-3">9.6.</span> Add Administrator to System Groups</h3>
+<div id="outline-container-orga3a919f" class="outline-3">
+<h3 id="orga3a919f"><span class="section-number-3">9.6.</span> Add Administrator to System Groups</h3>
 <div class="outline-text-3" id="text-9-6">
 <p>
 The administrator often needs to read (directories of) log files owned
@@ -6712,7 +6699,7 @@ these groups speeds up debugging.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Add {{ ansible_user }} to system groups.
   become: yes
   user:
@@ -6723,8 +6710,8 @@ these groups speeds up debugging.
 </div>
 </div>
 </div>
-<div id="outline-container-org3c2f09d" class="outline-3">
-<h3 id="org3c2f09d"><span class="section-number-3">9.7.</span> Trust Institute Certificate Authority</h3>
+<div id="outline-container-orgfab713c" class="outline-3">
+<h3 id="orgfab713c"><span class="section-number-3">9.7.</span> Trust Institute Certificate Authority</h3>
 <div class="outline-text-3" id="text-9-7">
 <p>
 Campus hosts should recognize the institute's Certificate Authority as
@@ -6734,7 +6721,7 @@ keys, certificates and passwords, see <a href="#org6519b0c">Keys</a>.)
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Trust the institute CA.
   become: yes
   copy:
@@ -6748,7 +6735,7 @@ keys, certificates and passwords, see <a href="#org6519b0c">Keys</a>.)
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Update CAs.
   become: yes
   command: update-ca-certificates
@@ -6756,15 +6743,15 @@ keys, certificates and passwords, see <a href="#org6519b0c">Keys</a>.)
 </div>
 </div>
 </div>
-<div id="outline-container-org0cf8be6" class="outline-3">
-<h3 id="org0cf8be6"><span class="section-number-3">9.8.</span> Install Unattended Upgrades</h3>
+<div id="outline-container-orgb504c59" class="outline-3">
+<h3 id="orgb504c59"><span class="section-number-3">9.8.</span> Install Unattended Upgrades</h3>
 <div class="outline-text-3" id="text-9-8">
 <p>
 The institute prefers to install security updates as soon as possible.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install basic software.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=unattended-upgrades
@@ -6790,7 +6777,7 @@ tasks below.
 </ul>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install Postfix.
   become: yes
   <span class="org-variable-name">apt: pkg</span>=postfix
@@ -6827,7 +6814,7 @@ tasks below.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Restart Postfix.
   become: yes
   systemd:
@@ -6847,7 +6834,7 @@ custom of translating the host name into <code>127.0.1.1</code> is also followed
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Hard-wire important IP addresses.
   become: yes
   lineinfile:
@@ -6877,7 +6864,7 @@ Role</a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/campus/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/tasks/main.yml"><q>roles_t/campus/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install NRPE.
   become: yes
   apt:
@@ -6915,7 +6902,7 @@ Role</a>.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/campus/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/campus/handlers/main.yml"><q>roles_t/campus/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Reload NRPE server.
   become: yes
   systemd:
@@ -6931,8 +6918,8 @@ Role</a>.
 <div class="outline-text-2" id="text-10">
 <p>
 The small institute uses Ansible to maintain the configuration of its
-servers.  The administrator keeps an Ansible inventory in <q>hosts</q>, and
-runs the playbook <q>site.yml</q> to apply the appropriate institutional
+servers.  The administrator keeps an Ansible inventory in <a href="hosts"><q>hosts</q></a>, and
+runs playbook <a href="playbook/site.yml"><q>site.yml</q></a> to apply the appropriate institutional
 role(s) to each host.  Examples of these files are included here, and
 are used to test the roles.  The example configuration applies the
 institutional roles to VirtualBox machines prepared according to
@@ -6941,19 +6928,19 @@ chapter <a href="#org74b454f">Testing</a>.
 
 <p>
 The <i>actual</i> Ansible configuration is kept in a Git "superproject"
-containing replacements for the example <q>hosts</q> inventory and
-<q>site.yml</q> playbook, as well as the <q>public/</q> and <q>private/</q>
+containing replacements for the example <a href="hosts"><q>hosts</q></a> inventory and
+<a href="playbooks/site.yml"><q>site.yml</q></a> playbook, as well as the <a href="public/"><q>public/</q></a> and <a href="private/"><q>private/</q></a>
 particulars.  Thus changes to this document and its tangle are easily
 merged with <code>git pull --recurse-submodules</code> or <code>git submodule update</code>,
 while changes to the institute's particulars are committed to a
 separate revision history.
 </p>
 </div>
-<div id="outline-container-orgc1588c7" class="outline-3">
-<h3 id="orgc1588c7"><span class="section-number-3">10.1.</span> <q>ansible.cfg</q></h3>
+<div id="outline-container-orgfefb674" class="outline-3">
+<h3 id="orgfefb674"><span class="section-number-3">10.1.</span> <q>ansible.cfg</q></h3>
 <div class="outline-text-3" id="text-10-1">
 <p>
-The Ansible configuration file <q>ansible.cfg</q> contains just a handful
+The Ansible configuration file <a href="ansible.cfg"><q>ansible.cfg</q></a> contains just a handful
 of settings, some included just to create a test jig as described in
 <a href="#org74b454f">Testing</a>.
 </p>
@@ -6963,16 +6950,16 @@ of settings, some included just to create a test jig as described in
 "automatic interpreter discovery" (described <a href="https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html">here</a>).  It declares
 that Python 3 can be expected on all institute hosts.</li>
 <li><code>vault_password_file</code> is set to suppress prompts for the vault
-password.  The institute keeps its vault password in <q>Secret/</q> (as
+password.  The institute keeps its vault password in <a href="Secret/"><q>Secret/</q></a> (as
 described in <a href="#org6519b0c">Keys</a>) and thus sets this parameter to
-<q>Secret/vault-password</q>.</li>
+<a href="Secret/vault-password"><q>Secret/vault-password</q></a>.</li>
 <li><code>inventory</code> is set to avoid specifying it on the command line.</li>
 <li><code>roles_path</code> is set to the recently tangled roles files in
-<q>roles_t/</q> which are preferred in the test configuration.</li>
+<a href="roles_t/"><q>roles_t/</q></a> which are preferred in the test configuration.</li>
 </ul>
 
 <div class="org-src-container">
-<q>ansible.cfg</q><pre class="src src-conf">[<span class="org-type">defaults</span>]
+<a href="ansible.cfg"><q>ansible.cfg</q></a><pre class="src src-conf">[<span class="org-type">defaults</span>]
 <span class="org-variable-name">interpreter_python</span>=/usr/bin/python3
 <span class="org-variable-name">vault_password_file</span>=Secret/vault-password
 <span class="org-variable-name">inventory</span>=hosts
@@ -6985,7 +6972,7 @@ described in <a href="#org6519b0c">Keys</a>) and thus sets this parameter to
 <h3 id="orgb932c38"><span class="section-number-3">10.2.</span> <q>hosts</q></h3>
 <div class="outline-text-3" id="text-10-2">
 <p>
-The Ansible inventory file <q>hosts</q> describes all of the institute's
+The Ansible inventory file <a href="hosts"><q>hosts</q></a> describes all of the institute's
 machines starting with the main servers Front, Core and Gate.  It
 provides the IP addresses, administrator account names and passwords
 for each machine.  The IP addresses are all private, campus network
@@ -6994,7 +6981,7 @@ describes three test servers named <code>front</code>, <code>core</code> and <co
 </p>
 
 <div class="org-src-container">
-<q>hosts</q><pre class="src src-conf" id="orgafeb78d">all:
+<a href="hosts"><q>hosts</q></a><pre class="src src-conf" id="orgafeb78d">all:
   vars:
     ansible_user: sysadm
     ansible_ssh_extra_args: -i Secret/ssh_admin/id_rsa
@@ -7017,13 +7004,13 @@ describes three test servers named <code>front</code>, <code>core</code> and <co
 
 <p>
 The values of the <code>ansible_become_password</code> key are references to
-variables defined in <q>Secret/become.yml</q>, which is loaded as
+variables defined in <a href="Secret/become.yml"><q>Secret/become.yml</q></a>, which is loaded as
 "extra" variables by a <code>-e</code> option on the <code>ansible-playbook</code> command
 line.
 </p>
 
 <div class="org-src-container">
-<q>Secret/become.yml</q><pre class="src src-conf">become_front: !vault |
+<a href="Secret/become.yml"><q>Secret/become.yml</q></a><pre class="src src-conf">become_front: !vault |
         $ANSIBLE_VAULT;1.1;AES256
         3563626131333733666466393166323135383838666338666131336335326
         3656437663032653333623461633866653462636664623938356563306264
@@ -7054,8 +7041,8 @@ become_gate: !vault |
 The passwords are individually encrypted just to make it difficult to
 acquire a list of all institute privileged account passwords in one
 glance.  The multi-line values are generated by the <code>ansible-vault
-encrypt_string</code> command, which uses the <q>ansible.cfg</q> file and thus
-the <q>Secret/vault-password</q> file.
+encrypt_string</code> command, which uses the <a href="ansible.cfg"><q>ansible.cfg</q></a> file and thus
+the <a href="Secret/vault-password"><q>Secret/vault-password</q></a> file.
 </p>
 </div>
 </div>
@@ -7063,13 +7050,13 @@ the <q>Secret/vault-password</q> file.
 <h3 id="org074c362"><span class="section-number-3">10.3.</span> <q>playbooks/site.yml</q></h3>
 <div class="outline-text-3" id="text-10-3">
 <p>
-The example <q>playbooks/site.yml</q> playbook (below) applies the
+The example <a href="playbooks/site.yml"><q>playbooks/site.yml</q></a> playbook (below) applies the
 appropriate institutional role(s) to the hosts and groups defined in
-the example inventory: <q>hosts</q>.
+the example inventory: <a href="hosts"><q>hosts</q></a>.
 </p>
 
 <div class="org-src-container">
-<q>playbooks/site.yml</q><pre class="src src-conf">---
+<a href="playbooks/site.yml"><q>playbooks/site.yml</q></a><pre class="src src-conf">---
 - name: Configure Front
   hosts: front
   roles: [ front ]
@@ -7095,14 +7082,14 @@ the example inventory: <q>hosts</q>.
 <p>
 As already mentioned, the small institute keeps its Ansible vault
 password, a "master secret", on the encrypted partition mounted at
-<q>Secret/</q> in a file named <q>vault-password</q>.  The administrator
+<a href="Secret/"><q>Secret/</q></a> in a file named <q>vault-password</q>.  The administrator
 generated a 16 character pronounceable password with <code>gpw 1 16</code> and
 saved it like so: <code>gpw 1 16 &gt;Secret/vault-password</code>.  The following
 example password matches the example encryptions above.
 </p>
 
 <div class="org-src-container">
-<q>Secret/vault-password</q><pre class="src src-conf" id="org3cd4611">alitysortstagess
+<a href="Secret/vault-password"><q>Secret/vault-password</q></a><pre class="src src-conf" id="org3cd4611">alitysortstagess
 </pre>
 </div>
 </div>
@@ -7195,9 +7182,9 @@ super-project's directory.
 <h3 id="orgb70ec0e"><span class="section-number-3">10.6.</span> Maintaining A Working Ansible Configuration</h3>
 <div class="outline-text-3" id="text-10-6">
 <p>
-The Ansible roles currently tangle into the <q>roles_t/</q> directory to
+The Ansible roles currently tangle into the <a href="roles_t/"><q>roles_t/</q></a> directory to
 ensure that debugged Ansible code in <q>roles/</q> is not clobbered by code
-tangled from this document.  Comparing <q>roles_t/</q> with <q>roles/</q> will
+tangled from this document.  Comparing <a href="roles_t/"><q>roles_t/</q></a> with <q>roles/</q> will
 reveal any changes made to <q>roles/</q> during debugging that need to be
 reconciled with this document <i>as well as</i> any policy changes in this
 document that require changes to the current <q>roles/</q>.
@@ -7226,7 +7213,7 @@ to get their defaults from <q>./ansible.cfg</q>.
 <h3 id="orgf00b9ce"><span class="section-number-3">11.1.</span> Sub-command Blocks</h3>
 <div class="outline-text-3" id="text-11-1">
 <p>
-The code blocks in this chapter tangle into the <q>inst</q> script.  Each
+The code blocks in this chapter tangle into the <a href="inst"><q>inst</q></a> script.  Each
 block examines the script's command line arguments to determine
 whether its sub-command was intended to run, and exits with an
 appropriate code when it is done.
@@ -7237,7 +7224,7 @@ The first code block is the header of the <code>./inst</code> script.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl"><span class="org-comment-delimiter">#</span><span class="org-comment">!/usr/bin/perl -w</span>
+<a href="inst"><q>inst</q></a><pre class="src src-perl"><span class="org-comment-delimiter">#</span><span class="org-comment">!/usr/bin/perl -w</span>
 <span class="org-comment-delimiter">#</span>
 <span class="org-comment-delimiter"># </span><span class="org-comment">DO NOT EDIT.  This file was tangled from an institute.org file.</span>
 
@@ -7254,13 +7241,13 @@ The first code block is the header of the <code>./inst</code> script.
 The next code block does not implement a sub-command; it implements
 part of <i>all</i> <code>./inst</code> sub-commands.  It performs a "sanity check" on
 the current directory, warning of missing files or directories, and
-especially checking that all files in <q>private/</q> have appropriate
-permissions.  It probes past the <q>Secret/</q> mount point (probing for
-<q>Secret/become.yml</q>) to ensure the volume is mounted.
+especially checking that all files in <a href="private/"><q>private/</q></a> have appropriate
+permissions.  It probes past the <a href="Secret/"><q>Secret/</q></a> mount point (probing for
+<a href="Secret/become.yml"><q>Secret/become.yml</q></a>) to ensure the volume is mounted.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">sub</span> <span class="org-function-name">note_missing_file_p</span> ($);
 <span class="org-keyword">sub</span> <span class="org-function-name">note_missing_directory_p</span> ($);
 
@@ -7314,14 +7301,14 @@ permissions.  It probes past the <q>Secret/</q> mount point (probing for
 <p>
 To ensure that Ansible and <code>./inst</code> are sympatico vis-a-vi certain
 variable values (esp. private values like network addresses), a
-<q>check-inst-vars.yml</q> playbook is used to update the Perl syntax file
-<q>private/vars.pl</q> before <code>./inst</code> loads it.  The Perl code in <q>inst</q>
-declares the necessary global variables and <q>private/vars.pl</q> sets
+<a href="playbooks/check-inst-vars.yml"><q>check-inst-vars.yml</q></a> playbook is used to update the Perl syntax file
+<a href="private/vars.pl"><q>private/vars.pl</q></a> before <code>./inst</code> loads it.  The Perl code in <a href="inst"><q>inst</q></a>
+declares the necessary global variables and <a href="private/vars.pl"><q>private/vars.pl</q></a> sets
 them.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-conf">
+<a href="inst"><q>inst</q></a><pre class="src src-conf">
 <span class="org-type">sub mysystem (@)</span> {
   <span class="org-variable-name">my $line</span> = join (<span class="org-string">" "</span>, @_);
   print <span class="org-string">"$line\n"</span>;
@@ -7337,11 +7324,11 @@ do <span class="org-string">"./private/vars.pl"</span>;
 </div>
 
 <p>
-The playbook that updates <q>private/vars.pl</q>:
+The playbook that updates <a href="private/vars.pl"><q>private/vars.pl</q></a>:
 </p>
 
 <div class="org-src-container">
-<q>playbooks/check-inst-vars.yml</q><pre class="src src-conf">- hosts: localhost
+<a href="playbooks/check-inst-vars.yml"><q>playbooks/check-inst-vars.yml</q></a><pre class="src src-conf">- hosts: localhost
   gather_facts: no
   tasks:
   - include_vars: ../public/vars.yml
@@ -7363,21 +7350,21 @@ The playbook that updates <q>private/vars.pl</q>:
 <div class="outline-text-3" id="text-11-4">
 <p>
 The next code block implements the <code>CA</code> sub-command, which creates a
-new CA (certificate authority) in <q>Secret/CA/</q> as well as SSH and PGP
+new CA (certificate authority) in <a href="Secret/CA/"><q>Secret/CA/</q></a> as well as SSH and PGP
 keys for the administrator, Monkey, Front and <code>root</code>, also in
-sub-directories of <q>Secret/</q>.  The CA is created with the "common
+sub-directories of <a href="Secret/"><q>Secret/</q></a>.  The CA is created with the "common
 name" provided by the <code>full_name</code> variable.  An example is given
 here.
 </p>
 
 <div class="org-src-container">
-<q>public/vars.yml</q><pre class="src src-conf">full_name: Small Institute LLC
+<a href="public/vars.yml"><q>public/vars.yml</q></a><pre class="src src-conf">full_name: Small Institute LLC
 </pre>
 </div>
 
 <p>
-The <q>Secret/</q> directory is on an off-line, encrypted volume plugged in
-just for the duration of <code>./inst</code> commands, so <q>Secret/</q> is actually a
+The <a href="Secret/"><q>Secret/</q></a> directory is on an off-line, encrypted volume plugged in
+just for the duration of <code>./inst</code> commands, so <a href="Secret/"><q>Secret/</q></a> is actually a
 symbolic link to a volume's automount location.
 </p>
 
@@ -7387,8 +7374,8 @@ ln -s /media/sysadm/ADE7-F866/ Secret
 
 
 <p>
-The <q>Secret/CA/</q> directory is prepared using Easy RSA's <code>make-cadir</code>
-command.  The <q>Secret/CA/vars</q> file thus created is edited to contain
+The <a href="Secret/CA/"><q>Secret/CA/</q></a> directory is prepared using Easy RSA's <code>make-cadir</code>
+command.  The <a href="Secret/CA/vars"><q>Secret/CA/vars</q></a> file thus created is edited to contain
 the appropriate names (or just to set <code>EASYRSA_DN</code> to <code>cn_only</code>).
 </p>
 
@@ -7409,12 +7396,14 @@ config</code>.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">if</span> (defined $<span class="org-variable-name">ARGV</span>[0] &amp;&amp; $<span class="org-variable-name">ARGV</span>[0] eq <span class="org-string">"CA"</span>) {
   <span class="org-keyword">die</span> <span class="org-string">"usage: $0 CA"</span> <span class="org-keyword">if</span> @<span class="org-underline"><span class="org-variable-name">ARGV</span></span> != 1;
   <span class="org-keyword">die</span> <span class="org-string">"Secret/CA/easyrsa: not an executable\n"</span>
     <span class="org-keyword">if</span> ! -x <span class="org-string">"Secret/CA/easyrsa"</span>;
   <span class="org-keyword">die</span> <span class="org-string">"Secret/CA/pki/: already exists\n"</span> <span class="org-keyword">if</span> -e <span class="org-string">"Secret/CA/pki"</span>;
+
+  umask 077;
   mysystem <span class="org-string">"cd Secret/CA; ./easyrsa init-pki"</span>;
   mysystem <span class="org-string">"cd Secret/CA; ./easyrsa build-ca nopass"</span>;
   <span class="org-comment"># Common Name: small.example.org</span>
@@ -7426,8 +7415,8 @@ config</code>.
   mysystem <span class="org-string">"cd Secret/CA; ./easyrsa build-server-full core.$pvt nopass"</span>;
   mysystem <span class="org-string">"cd Secret/CA; ./easyrsa build-client-full core nopass"</span>;
   umask 077;
-  mysystem <span class="org-string">"openvpn --genkey --secret Secret/front-ta.key"</span>;
-  mysystem <span class="org-string">"openvpn --genkey --secret Secret/gate-ta.key"</span>;
+  mysystem <span class="org-string">"openvpn --genkey secret Secret/front-ta.key"</span>;
+  mysystem <span class="org-string">"openvpn --genkey secret Secret/gate-ta.key"</span>;
   mysystem <span class="org-string">"openssl dhparam -out Secret/front-dh2048.pem 2048"</span>;
   mysystem <span class="org-string">"openssl dhparam -out Secret/gate-dh2048.pem 2048"</span>;
 
@@ -7436,11 +7425,11 @@ config</code>.
             <span class="org-string">" --batch --quick-generate-key --passphrase ''"</span>,
             <span class="org-string">" root\@core.$pvt"</span>);
   mysystem (<span class="org-string">"gpg --homedir Secret/root.gnupg"</span>,
-            <span class="org-string">" --export --armor --output root-pub.pem"</span>,
+            <span class="org-string">" --export --armor --output Secret/root-pub.pem"</span>,
             <span class="org-string">" root\@core.$pvt"</span>);
   chmod 0440, <span class="org-string">"root-pub.pem"</span>;
   mysystem (<span class="org-string">"gpg --homedir Secret/root.gnupg"</span>,
-            <span class="org-string">" --export-secret-key --armor --output root-sec.pem"</span>,
+            <span class="org-string">" --export-secret-key --armor --output Secret/root-sec.pem"</span>,
             <span class="org-string">" root\@core.$pvt"</span>);
   chmod 0400, <span class="org-string">"root-sec.pem"</span>;
 
@@ -7489,7 +7478,7 @@ Example command lines:
 
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">if</span> (defined $<span class="org-variable-name">ARGV</span>[0] &amp;&amp; $<span class="org-variable-name">ARGV</span>[0] eq <span class="org-string">"config"</span>) {
   <span class="org-keyword">die</span> <span class="org-string">"Secret/CA/easyrsa: not executable\n"</span>
     <span class="org-keyword">if</span> ! -x <span class="org-string">"Secret/CA/easyrsa"</span>;
@@ -7575,14 +7564,14 @@ revoked:
 
 <p>
 The test campus starts with the empty membership roll found in
-<q>private/members-empty.yml</q> and saved in <q>private/members.yml</q>
+<a href="private/members-empty.yml"><q>private/members-empty.yml</q></a> and saved in <q>private/members.yml</q>
 (which is <i>not</i> tangled from this document, thus <i>not</i> over-written
 during testing).  If <q>members.yml</q> is not found, <q>members-empty.yml</q>
 is used instead.
 </p>
 
 <div class="org-src-container">
-<q>private/members-empty.yml</q><pre class="src src-conf">---
+<a href="private/members-empty.yml"><q>private/members-empty.yml</q></a><pre class="src src-conf">---
 members:
 usernames: []
 revoked: []
@@ -7595,7 +7584,7 @@ Both locations go on the <code>membership_rolls</code> variable used by the
 </p>
 
 <div class="org-src-container">
-<q>private/vars.yml</q><pre class="src src-conf">membership_rolls:
+<a href="private/vars.yml"><q>private/vars.yml</q></a><pre class="src src-conf">membership_rolls:
 - <span class="org-string">"../private/members.yml"</span>
 - <span class="org-string">"../private/members-empty.yml"</span>
 </pre>
@@ -7608,7 +7597,7 @@ read from the file.  The dump subroutine is another story (below).
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-constant">use</span> YAML::XS qw<span class="org-string">(LoadFile DumpFile)</span>;
 
 <span class="org-keyword">sub</span> <span class="org-function-name">read_members_yaml</span> () {
@@ -7684,7 +7673,7 @@ each record.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">sub</span> <span class="org-function-name">print_member</span> ($$) {
   <span class="org-type">my</span> ($<span class="org-variable-name">out</span>, $<span class="org-variable-name">member</span>) = @<span class="org-underline"><span class="org-variable-name">_</span></span>;
   print $<span class="org-variable-name">out</span> <span class="org-string">"  "</span>, $<span class="org-variable-name">member</span>-&gt;{<span class="org-string">"username"</span>}, <span class="org-string">":\n"</span>;
@@ -7728,7 +7717,7 @@ each record.
 The next code block implements the <code>new</code> sub-command.  It adds a new
 member to the institute's membership roll.  It runs an Ansible
 playbook to create the member's Nextcloud user, updates
-<q>private/members.yml</q>, and runs the <q>site.yml</q> playbook.  The site
+<q>private/members.yml</q>, and runs the <a href="playbooks/site.yml"><q>site.yml</q></a> playbook.  The site
 playbook (re)creates the member's accounts on Core and Front,
 (re)installs the member's personal homepage on Front, and the member's
 Fetchmail service on Core.  All services are configured with an
@@ -7736,7 +7725,7 @@ initial, generated password.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">sub</span> <span class="org-function-name">valid_username</span> (@);
 <span class="org-keyword">sub</span> <span class="org-function-name">shell_escape</span> ($);
 <span class="org-keyword">sub</span> <span class="org-function-name">strip_vault</span> ($);
@@ -7799,7 +7788,7 @@ initial, generated password.
 </div>
 
 <div class="org-src-container">
-<q>playbooks/nextcloud-new.yml</q><pre class="src src-conf">- hosts: core
+<a href="playbooks/nextcloud-new.yml"><q>playbooks/nextcloud-new.yml</q></a><pre class="src src-conf">- hosts: core
   no_log: yes
   tasks:
   - name: Run occ user:add.
@@ -7837,7 +7826,7 @@ pass</code> command.  In either case, the administrator needs to update the
 membership roll, and so receives an encrypted email, which gets piped
 into <code>./inst pass</code>.  This command decrypts the message, parses the
 (YAML) content, updates <q>private/members.yml</q>, and runs the full
-Ansible <q>site.yml</q> playbook to update the servers.  If all goes well a
+Ansible <a href="playbooks/site.yml"><q>site.yml</q></a> playbook to update the servers.  If all goes well a
 message is sent to <code>member@core</code>.
 </p>
 </div>
@@ -7852,11 +7841,11 @@ update the servers, so it does not need an SSH key and password to
 (nor equivalent) on Core.  It <i>is</i> a set-UID <code>shadow</code> script so it can
 read <q>/etc/shadow</q>.  The member will need to wait for confirmation
 from the administrator, but <i>all</i> keys to <code>root</code> at the institute stay
-in <q>Secret/</q>.
+in <a href="Secret/"><q>Secret/</q></a>.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/templates/passwd</q><pre class="src src-perl"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/perl -wT</span>
+<a href="roles_t/core/templates/passwd"><q>roles_t/core/templates/passwd</q></a><pre class="src src-perl"><span class="org-comment-delimiter">#</span><span class="org-comment">!/bin/perl -wT</span>
 
 <span class="org-constant">use</span> strict;
 
@@ -7944,11 +7933,11 @@ print <span class="org-string">"</span>
 <p>
 The following code block implements the <code>./inst pass</code> command, used by
 the administrator to update <q>private/members.yml</q> before running
-<q>playbooks/site.yml</q> and emailing the concerned member.
+<a href="playbooks/site.yml"><q>playbooks/site.yml</q></a> and emailing the concerned member.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-constant">use</span> MIME::Base64;
 
 <span class="org-keyword">if</span> (defined $<span class="org-variable-name">ARGV</span>[0] &amp;&amp; $<span class="org-variable-name">ARGV</span>[0] eq <span class="org-string">"pass"</span>) {
@@ -8007,7 +7996,7 @@ users:resetpassword</code> command using <code>expect(1)</code>.
 </p>
 
 <div class="org-src-container">
-<q>playbooks/nextcloud-pass.yml</q><pre class="src src-conf">- hosts: core
+<a href="playbooks/nextcloud-pass.yml"><q>playbooks/nextcloud-pass.yml</q></a><pre class="src src-conf">- hosts: core
   no_log: yes
   tasks:
   - name: Run occ user:resetpassword.
@@ -8050,7 +8039,7 @@ configuration so that the email to root can be encrypted.
 </p>
 
 <div class="org-src-container">
-<q>roles_t/core/tasks/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/tasks/main.yml"><q>roles_t/core/tasks/main.yml</q></a><pre class="src src-conf">
 - name: Install institute passwd command.
   become: yes
   template:
@@ -8096,7 +8085,7 @@ configuration so that the email to root can be encrypted.
 </div>
 
 <div class="org-src-container">
-<q>roles_t/core/handlers/main.yml</q><pre class="src src-conf">
+<a href="roles_t/core/handlers/main.yml"><q>roles_t/core/handlers/main.yml</q></a><pre class="src src-conf">
 - name: Import root PGP key.
   become: no
   command: gpg --import ~/.gnupg-root-pub.pem
@@ -8113,7 +8102,7 @@ The <code>old</code> command disables a member's accounts and clients.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">if</span> (defined $<span class="org-variable-name">ARGV</span>[0] &amp;&amp; $<span class="org-variable-name">ARGV</span>[0] eq <span class="org-string">"old"</span>) {
   <span class="org-type">my</span> $<span class="org-variable-name">user</span> = valid_username (@<span class="org-underline"><span class="org-variable-name">ARGV</span></span>);
   <span class="org-type">my</span> $<span class="org-variable-name">yaml</span> = read_members_yaml ();
@@ -8135,7 +8124,7 @@ The <code>old</code> command disables a member's accounts and clients.
 </div>
 
 <div class="org-src-container">
-<q>playbooks/nextcloud-old.yml</q><pre class="src src-conf">- hosts: core
+<a href="playbooks/nextcloud-old.yml"><q>playbooks/nextcloud-old.yml</q></a><pre class="src src-conf">- hosts: core
   tasks:
   - name: Run occ user:disable.
     shell: |
@@ -8157,7 +8146,7 @@ The <code>old</code> command disables a member's accounts and clients.
 <p>
 The <code>client</code> command creates an OpenVPN configuration (<q>.ovpn</q>) file
 authorizing wireless devices to connect to the institute's VPNs.  The
-command uses the EasyRSA CA in <q>Secret/</q>.  The generated configuration
+command uses the EasyRSA CA in <a href="Secret/"><q>Secret/</q></a>.  The generated configuration
 is slightly different depending on the type of host, given as the
 first argument to the command.
 </p>
@@ -8192,7 +8181,7 @@ copies the <q>campus.ovpn</q> file to <q>/etc/openvpn/campus.conf</q>.
 
 <p>
 The OpenVPN configurations generated for Debian hosts specify an <code>up</code>
-script, <q>update-systemd-resolved</q>, installed in <q>/etc/openvpn/</q> by the
+script, <code>update-systemd-resolved</code>, installed in <q>/etc/openvpn/</q> by the
 <code>openvpn-systemd-resolved</code> package.  The following configuration lines
 instruct the OpenVPN clients to run this script whenever the
 connection is restarted.
@@ -8206,7 +8195,7 @@ up-restart
 </div>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl"><span class="org-keyword">sub</span> <span class="org-function-name">write_template</span> ($$$$$$$$$);
+<a href="inst"><q>inst</q></a><pre class="src src-perl"><span class="org-keyword">sub</span> <span class="org-function-name">write_template</span> ($$$$$$$$$);
 <span class="org-keyword">sub</span> <span class="org-function-name">read_file</span> ($);
 <span class="org-keyword">sub</span> <span class="org-function-name">add_client</span> ($$$);
 
@@ -8327,13 +8316,13 @@ up-restart
 <h3 id="org875755b"><span class="section-number-3">11.11.</span> Institute Command Help</h3>
 <div class="outline-text-3" id="text-11-11">
 <p>
-This should be the last block tangled into the <q>inst</q> script.  It
+This should be the last block tangled into the <a href="inst"><q>inst</q></a> script.  It
 catches any command lines that were not handled by a sub-command
 above.
 </p>
 
 <div class="org-src-container">
-<q>inst</q><pre class="src src-perl">
+<a href="inst"><q>inst</q></a><pre class="src src-perl">
 <span class="org-keyword">die</span> <span class="org-string">"usage: $0 [CA|config|new|pass|old|client] ...\n"</span>;
 </pre>
 </div>
@@ -8344,10 +8333,10 @@ above.
 <h2 id="org74b454f"><span class="section-number-2">12.</span> Testing</h2>
 <div class="outline-text-2" id="text-12">
 <p>
-The example files in this document, <q>ansible.cfg</q> and <q>hosts</q> as
-well as those in <q>public/</q> and <q>private/</q>, along with the
+The example files in this document, <a href="ansible.cfg"><q>ansible.cfg</q></a> and <a href="hosts"><q>hosts</q></a> as
+well as those in <a href="public/"><q>public/</q></a> and <a href="private/"><q>private/</q></a>, along with the
 matching EasyRSA certificate authority and GnuPG key-ring in
-<q>Secret/</q> (included in the distribution), can be used to configure
+<a href="Secret/"><q>Secret/</q></a> (included in the distribution), can be used to configure
 three VirtualBox VMs simulating Core, Gate and Front in a test network
 simulating a campus Ethernet, campus ISP, and commercial cloud.  With
 the test network up and running, a simulated member's notebook can be
@@ -8729,7 +8718,7 @@ VBoxManage modifyvm gate --hostonlyadapter3 vboxnet1
 
 <p>
 Before rebooting, the MAC addresses of the three network interfaces
-should be compared to the example variable settings in <q>hosts</q>.  The
+should be compared to the example variable settings in <a href="hosts"><q>hosts</q></a>.  The
 values of the <code>gate_lan_mac</code>, <code>gate_wifi_mac</code>, and <code>gate_isp_mac</code>
 variables <i>must</i> agree with the MAC addresses assigned to the virtual
 machine's network interfaces.  The following table assumes device
@@ -8999,9 +8988,9 @@ or update its configuration files.
 The administrator will need a desktop system in the test campus
 networks (using the campus name server).  The test Nextcloud
 configuration requires that it be accessed with the domain name
-<q>core.small.private</q>.  The following sections describe how a client
+<code>core.small.private</code>.  The following sections describe how a client
 desktop is simulated and connected to the test VPNs (and test campus
-name server).  Its browser can then connect to <q>core.small.private</q> to
+name server).  Its browser can then connect to <code>core.small.private</code> to
 exercise the test Nextcloud.
 </p>
 
@@ -9138,7 +9127,7 @@ host www
 <h3 id="org861e789"><span class="section-number-3">12.11.</span> Test Web Pages</h3>
 <div class="outline-text-3" id="text-12-11">
 <p>
-Next, the administrator copies <q>Backup/WWW/</q> (included in the
+Next, the administrator copies <a href="Backup/WWW/"><q>Backup/WWW/</q></a> (included in the
 distribution) to <q>/WWW/</q> on <code>core</code> and sets the file permissions
 appropriately.
 </p>
@@ -9520,7 +9509,7 @@ complete.  Additional tests are needed.
 <p>
 The <code>backup</code> command has not been tested.  It needs an encrypted
 partition with which to sync?  And then some way to compare that to
-<q>Backup/</q>?
+<a href="Backup/"><q>Backup/</q></a>?
 </p>
 </div>
 </div>
@@ -9528,7 +9517,7 @@ partition with which to sync?  And then some way to compare that to
 <h4 id="org2053b4a"><span class="section-number-4">13.2.2.</span> Restore</h4>
 <div class="outline-text-4" id="text-13-2-2">
 <p>
-The restore process has not been tested.  It might just copy <q>Backup/</q>
+The restore process has not been tested.  It might just copy <a href="Backup/"><q>Backup/</q></a>
 to <code>core:/</code>, but then it probably needs to fix up file ownerships,
 perhaps permissions too.  It could also use an example
 <q>Backup/Nextcloud/20220622.bak</q>.
@@ -9698,7 +9687,7 @@ routes on Front and Gate, making the simulation less&#x2026; similar.
 </div></div>
 <div id="postamble" class="status">
 <p class="author">Author: Matt Birkholz</p>
-<p class="date">Created: 2023-12-17 Sun 16:05</p>
+<p class="date">Created: 2023-12-28 Thu 16:07</p>
 <p class="validation"><a href="https://validator.w3.org/check?uri=referer">Validate</a></p>
 </div>
 </body>