Web Server and DNS on Apple using Homebrew

I
N
D
E
X

T
O
O
L
S

Online Internet Test Tools to check Servers, Internet Protocols and Implementations

INTERNET
DNS(SEC)
DANE/DKIM/SPF/MTA-STS
Certs/TLS
REST
internet.nl www.dnsinspect.com www.huque.com/bin/danecheck crt.sh delaat.net/setup
IPv6-test.com dnschecker.org aykevl.nl/apps/mta-sts
ssllabs.com
test-ipv6.com intodns.com www.dmarcanalyzer.com/dkim/dkim-checker
www.sslshopper.com http2.pro
ip6.nl zonemaster.net check-auth@verifier.port25.com
www.hardenize.com
w3dt.net
6-test.com dnsviz.net
immuniweb.com
stat.ripe.net
test-6.com dnssec-debugger.verisignlabs.com


observatory.mozilla.org



B
A
S
I
C

BREW, XCODE and BBEdit command line tools

Installation:

Setup of package manager brew, see for latest https://brew.sh:

  • /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Don't forget to do the commands that are indicated and the end of the installation process. Here reproduced with "$USER":

On Intel architecture:
  • echo >> /Users/"$USER"/.zprofile
  • echo 'eval "$(/usr/local/bin/brew shellenv)"' >> /Users/"$USER"/.zprofile
  • eval "$(/usr/local/bin/brew shellenv)"
On Apple M architecture:
  • echo >> /Users/"$USER"/.zprofile
  • echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/"$USER"/.zprofile
  • eval "$(/opt/homebrew/bin/brew shellenv)"

Some in newer MacOS missing libs:

  • brew install openssl

Install BBEdit from https://www.barebones.com/products/bbedit/index.html

Start BBEdit and set up its command line tools under the BBEdit menu. For more information see: https://docs.brew.sh/FAQ

For multi user HomeBrew see:
Rather than keep switching the owner to whomever I’m logged in as, or just having one user take care of all brew update/upgrades, you just have to ‘tweak’ the instructions and grant ownership to the `admin` group. A quick sudo chgrp -R admin $(brew --prefix) will switch all Brew folders to the admin group. You will get an error trying to update /usr/local/, this is fine and doesn’t cause issues. Then a sudo chmod -R g+rwX $(brew --prefix) to update the permissions on the same folders and you’re done. Obviously this now means that any admin can use Homebrew but they are admins after all.:

Be careful, if there are certificates (certbot) or other installations like mailserver, this ownership/privilege change may interrupt those services.
  • sudo chgrp -R admin $(brew --prefix)
  • sudo chmod -R g+rwX $(brew --prefix)

Debugging:

Check version and installation:

  • brew doctor
  • brew --version

Apples command line tools. If not automatically installed  then:

  • xcode-select --install

If needed to re-install command tools do this command first to remove previous tools:

  • sudo rm -rf /Library/Developer/CommandLineTools
If needed to correct permissions (Be careful, if there are certificates (certbot) or other installations like mailserver, this ownership/privilege change may interrupt those services.):
  • sudo chown -R "$USER":admin /usr/local
  • sudo chown -R "$USER":admin /Library/Caches/Homebrew

You may get an error warning: homebrew-core is a shallow clone. Explanation: This restriction has been made on GitHub's request because updating shallow clones is an extremely expensive operation due to the tree layout and traffic of Homebrew/homebrew-core and Homebrew/homebrew-cask. We don't do this for you automatically to avoid repeatedly performing an expensive unshallow operation in CI systems (which should instead be fixed to not use shallow clones). Sorry for the inconvenience! Therefore, to `brew update`, first run:

  • git -C /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core fetch --unshallow

To remove brew alltogether:

  • sudo brew services stop --all
  • /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/uninstall/master/install.sh)"

Maintenance:

To upgrade all installed programs to newest version:

  • brew update
  • brew upgrade
  • brew cleanup
  • brew services list
  • sudo brew services restart --all

W
W
W

Apache

Installation:

  • brew install httpd
  • sudo brew services start httpd
  • sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add $(readlink -f $(which httpd)) --unblockapp $(readlink -f $(which httpd))

Debugging:

In a separate window show dynamically the tail of the error and access logfiles:

  • tail -n 1000 -f /usr/local/var/log/httpd/error_log
  • tail -n 1000 -f /usr/local/var/log/httpd/access_log
If install has problems because of previous versions:
  • sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist
  • sudo apachectl stop
  • sudo brew services restart httpd

To check what a site is running, if not installed install lynx first:

  • brew install lynx
  • lynx -dump -head <website> | grep ^Server

Check if deamon is running:

  • ps -aef | grep httpd
To get setup paths:
  • sudo apachectl -S
Test conf files, must be with sudo to test certificates:
  • sudo apachectl configtest

Maintenance:

To restart httpd:

  • sudo brew services restart httpd
  • sudo apachectl stop
  • sudo apachectl -k restart

References:

HTTPD config edits HTTP2, headers, userdirs, proxy

Installation:

HTTPD config basic edits:

Note, we assume the web site directories to be in public_html in the users home directories and abandon the Apple Sites approach.

  • bbedit /usr/local/etc/httpd/httpd.conf
  1. Listen 8080 => Listen 80
  2. enable ===> LoadModule mpm_event_module lib/httpd/modules/mod_mpm_event.so
  3. disable ===> #LoadModule mpm_prefork_module lib/httpd/modules/mod_mpm_prefork.so
  4. enable ==> LoadModule deflate_module lib/httpd/modules/mod_deflate.so
  5. enable ===> LoadModule http2_module lib/httpd/modules/mod_http2.so
  6. enable ==> LoadModule rewrite_module lib/httpd/modules/mod_rewrite.so
  7. ServerAdmin root@localhost
  8. #ServerName www.example.net:8080 ==> ServerName localhost:80
  9. enable ==> Include /usr/local/etc/httpd/extra/httpd-autoindex.conf
  10. add ===> Protocols h2 h2c http/1.1

      Enable full filename display in case of directory index:

      • bbedit /usr/local/etc/httpd/extra/httpd-autoindex.conf

      add NameWidth=* to the line IndexOptions FancyIndexing HTMLTable VersionSort

      1. ===> IndexOptions FancyIndexing HTMLTable VersionSort NameWidth=*

      Enable example.net/~user.

      In httpd.conf:
      • bbedit /usr/local/etc/httpd/httpd.conf
      1. enable ==> LoadModule userdir_module lib/httpd/modules/mod_userdir.so
      2. enable ==> Include /usr/local/etc/httpd/extra/httpd-userdir.conf

      Optionally to enable (reverse) proxies.

      See:

      In httpd.conf:

      • bbedit /usr/local/etc/httpd/httpd.conf
      1. enable ==> LoadModule proxy_module lib/httpd/modules/mod_proxy.so
      2. enable ==> LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
      Then for port based in case of http:
      • bbedit /usr/local/etc/httpd/extra/httpd-vhosts.conf
      • Listen 12345
        <VirtualHost *:12345>
            ProxyPass "/" "http://127.0.0.1:12344/"
            ProxyPassReverse "/" "http://127.0.0.1:12344/"
        </VirtualHost>

      • Or for https:// in the ssl vhost file below to embed traffic in ssl:
        Listen 12345
        <VirtualHost *:12345>
            ProxyPass "/" "http://127.0.0.1:12346/" retry=1 acquire=3000 timeout=10 Keepalive=On
            ProxyPassReverse "/" "http://127.0.0.1:12346/"
            SSLEngine on
            SSLCertificateFile /etc/letsencrypt/live/example.net/fullchain.pem
            SSLCertificateKeyFile /etc/letsencrypt/live/example.net/privkey.pem
        </VirtualHost>

      Debugging:

      Maintenance:

      HTTPD config edits for vhosts

      Installation:

      HTTPD config edits enable vhosts:

      • bbedit /usr/local/etc/httpd/httpd.conf
      1. enable ==> LoadModule vhost_alias_module lib/httpd/modules/mod_vhost_alias.so
      2. enable ==> Include /usr/local/etc/httpd/extra/httpd-vhosts.conf
      and for vhosts including a default directory. The default directory is the webroot where all requests go to if there is not a specific webroot for that (sub)domain defined. Therefore, it must be the first in the list. Here an example for example.net edit:
      • bbedit /usr/local/etc/httpd/extra/httpd-vhosts.conf
      <VirtualHost *:80>
          DocumentRoot "/usr/local/var/www"
      </VirtualHost>
      <Directory "/usr/local/var/www">
          Options Indexes FollowSymLinks
          AllowOverride All
          Require all granted
      </Directory>

      <VirtualHost *:80>
          DocumentRoot "/Users/example/public_html"
          ServerName example.net
          ServerAlias www.example.net
      </VirtualHost>
      <Directory "/Users/example/public_html">
          Options Indexes FollowSymLinks
          AllowOverride All
          Require all granted
      </Directory>

      Debugging:

      If you hit permission errors:

      • chmod -R 755 on each public_html directory.
      • chmod +x /Users/$(whoami)

      Maintenance:

      certbot - Let's Encrypt

      Installation:

      • brew install certbot

      NOTE: there are several ways in setting up certbot operations. One way is to use the --apache flag to find and select the (sub)domains and use a running apache server to perform the required letsencrypt challenge. The procedure using --apache fails on some versions of big sur! It seems that on big sur the "sudo brew services start httpd" and "sudo certbot certonly --apache ..." have different effects than previously. The certbot apache module seems unable to find the correct httpd setup information and fails consistently with remarks: "no vhost on port 80" and "no servernames found...". The standalone build-in server also has drawbacks. It requires to stop the webserver as the standalone server also needs to listen to the same ports for the challenge. Another problem is the build in firewall from MacOS. It requires the app to be used in the challenge to be in the list of allowed apps to open and listen on ports. This needs to be correct at renewal or the automatic renewals will fail. It turns out Certbot uses Python for the standalone server, which means that Python must be in the list. That can be a big security risk, and every time brew installs a newer version of the python framework, the firewall needs to be updated. Normally for httpd the system will ask that immediately when the daemon is restarted. In case of the standalone server that message will only (maybe) pop up during the cert renewal when nobody is watching. For completeness here are both procedures.

      The procedure using the apache plugin. Note that we give the certificate a constant name "le-cert":

      To request the certificates:
      • sudo certbot certonly --apache  --cert-name le-cert
      or if one first wants to do a number of test runs for debugging:
      • sudo certbot certonly --apache --cert-name le-cert --staging
      for after successful testing forcing a full new certificate:
      • sudo certbot certonly --apache --cert-name le-cert --force-renewal

      If pre, post or deploy scripts are needed, those go here:

      • /private/etc/letsencrypt/renewal-hooks

      The procedure using the build-in standalone server:

      To get the certificate we use the build-in standalone server in certbot and we use certonly to avoid any meddling of the configuration by the certbot plugins. Therefore, we need to stop the apache server, request cert, start server again:
      • sudo certbot certonly --standalone --pre-hook "apachectl stop" --post-hook "apachectl start" --cert-name le-cert -d example.net -d sub1.example.net -d sub2.example.net -d example2.net ...

      or if one first wants to do a number of test runs for debugging:

      • sudo certbot certonly --standalone --pre-hook "apachectl stop" --post-hook "apachectl start" --cert-name le-cert -d example.net -d sub1.example.net -d sub2.example.net -d example2.net ... --staging
      for after successful testing forcing a full new certificate:
      • sudo certbot certonly --standalone --pre-hook "apachectl stop" --post-hook "apachectl start" --cert-name le-cert -d example.net -d sub1.example.net -d sub2.example.net -d example2.net ... --force-renewal

      If pre, post or deploy scripts are needed, those go here:

      • /private/etc/letsencrypt/renewal-hooks

      For setup of renewal which is identical in both case:
      • sudo certbot renew

      We have to make a launchd plist, see:

      However, the plist in the above solutions don't not work because the PATH variable of the running deamon is not correct. Therefore, we add an environment variable in the plist that sets the path.

      Create plist:

      cat >com.letsencrypt.renew.plist <<EOF
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
          <dict>
              <key>Label</key>
              <string>com.letsencrypt.renew</string>
              <key>RunAtLoad</key>
              <true/>
              <key>EnvironmentVariables</key>
              <dict>
                   <key>PATH</key>
                    <string>/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin</string>
              </dict>
              <key>ProgramArguments</key>
              <array>
                  <string>/usr/local/bin/certbot</string>
                  <string>renew</string>
              </array>
              <key>StartCalendarInterval</key>
              <dict>
                  <key>Hour</key>
                  <integer>4</integer>
                  <key>Minute</key>
                  <integer>56</integer>
              </dict>
              <key>StandardErrorPath</key>
                <string>/tmp/local.certbot.renew.log</string>
              <key>StandardOutPath</key>
              <string>/tmp/local.certbot.renew.log</string>
          </dict>
      </plist>
      EOF
      • sudo mv com.letsencrypt.renew.plist /Library/LaunchDaemons/com.letsencrypt.renew.plist
      • sudo chmod 644 /Library/LaunchDaemons/com.letsencrypt.renew.plist
      • sudo chown root:admin /Library/LaunchDaemons/com.letsencrypt.renew.plist
      • sudo launchctl load -w /Library/LaunchDaemons/com.letsencrypt.renew.plist
      • sudo launchctl list | grep -i letsencrypt

      If test runs are needed:

      • sudo certbot renew --dry-run


      HTTPD edits:

      • bbedit /usr/local/etc/httpd/httpd.conf

      Uncomment:

      LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
      LoadModule ssl_module modules/mod_ssl.so
      Include /usr/local/etc/httpd/extra/httpd-ssl.conf

      For best security see: https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configuration

      Edit in httpd-ssl.conf:
      • bbedit /usr/local/etc/httpd/extra/httpd-ssl.conf
      1. Make sure these parameters have following values:
        • SSLCipherSuite
        • SSLProxyCipherSuite TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256
        • SSLProtocol             -all +TLSv1.2 +TLSv1.3
        • SSLProxyProtocol        -all +TLSv1.2 +TLSv1.3
        • SSLHonorCipherOrder   on
        • SSLSessionTickets       off
        • SSLCompression          off
        • SSLOptions +StrictRequire
        • # Add vhost name to log entries:
        • LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
        • LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
      2. point the certs at the correct places
        • SSLCertificateFile /etc/letsencrypt/live/le-cert/fullchain.pem
        • SSLCertificateKeyFile /etc/letsencrypt/live/le-cert/privkey.pem
      3. change listen 8443 ==> listen 443
      4. replace everything in the virtual host block including #<VirtualHost _default_:8443> and #</VirtualHost> by:

        <VirtualHost *:443>
            DocumentRoot "/usr/local/var/www"
            SSLEngine on
        </VirtualHost>

        <VirtualHost *:443>
            DocumentRoot "/Users/example/public_html "
            ServerName example.net
            ServerAlias www.example.net
            SSLEngine on
        </VirtualHost>
        <Directory "/Users/example/public_html ">
            Options Indexes FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>


      The vhost edits:

      The idea is that all requests that get through on port 80 or with incorrect url's/domain names end up in: "/usr/local/var/www"
      and all requests that come in via https and correct domain names go to the correct webroots of those domains. For that purpose a rewrite rule takes care of redirection. This is in httpd-vhosts.conf
      I use the following domain construction for example.net:

      *                  catches all (sub)domains for which no other webroot is defined and points to "/usr/local/var/www"
      example.net        this goes to the normal webroot of the domain example.net
      www.example.net    also goes to the normal webroot of the domain example.net
      sub1.example.net   a subdomain of example.net with its own webroot


      in httpd-vhosts.conf:

      • bbedit /usr/local/etc/httpd/extra/httpd-vhosts.conf
      <VirtualHost *:80>
          DocumentRoot "/usr/local/var/www"
      </VirtualHost>
      <Directory "/usr/local/var/www">
          Options Indexes FollowSymLinks
          AllowOverride All
          Require all granted
      </Directory>

      <VirtualHost *:80>
          DocumentRoot "/usr/local/var/www"
          ServerName example.net
          ServerAlias www.example.net
          ServerAlias sub1.example.net
         RewriteEngine on
         RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
      </VirtualHost>

      Note that the Directory directive for example and sub1 is moved to the httpd-ssl.conf file. The documentroot is pointing at "/usr/local/var/www", so that if anything gets through, it points at the default webroot. This ensures that if the http-ssl.conf file does not get processed, the secure webroots are not exposed.

      Debugging:

      • sudo tail -f -n 1000 /var/log/letsencrypt/letsencrypt.log

      To list the certificates:

      • sudo certbot certificates

      If test runs are needed:

      • sudo certbot renew --dry-run

      Some more debugging:

      The configuration file is at: /etc/letsencrypt/renewal/

      Maintenance:

      • sudo certbot renew
      • sudo certbot certificates

      HTTP Headers for Security Hardening

      Installation:

      NOTE: only after the certs and https are stable! In httpd.conf:
      • bbedit /usr/local/etc/httpd/httpd.conf
      1. enable ==> LoadModule headers_module lib/httpd/modules/mod_headers.so
      2. add at the end of the conf file:

        <IfModule headers_module>
          header set Strict-Transport-Security "max-age=31536000; preload"
          header set X-XSS-Protection "1; mode=block"
          header set X-Frame-Options "SAMEORIGIN"
          header set X-Content-Type-Options "nosniff"
          header set Referrer-Policy "same-origin"
          header set Content-Security-Policy "form-action 'self' https:; object-src 'self' https:; frame-ancestors 'self' https:; require-trusted-types-for 'script';"
        </IfModule>

      Some experimental:
      #  header set Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
      #  header set Content-Security-Policy "script-src 'self' 'unsafe-inline' 'unsafe-eval'; object-src 'none'; frame-ancestors 'self'; require-trusted-types-for 'script';"

      References:

      Debugging:

      Maintenance:

      HTML default header

      Installation:

      A good web pages header for .html files: for UTF-8:

      <!DOCTYPE html>
      <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.25, maximum-scale=4.0, user-scalable=yes">
        <style>
        body {color: white; background-color: black; font-family: Helvetica, Arial, sans-serif;}
        a:link {color: lightskyblue; background-color: transparent; text-decoration: underline;}
        a:visited {color: orange; background-color: transparent; text-decoration: underline;;}
        a:hover {color: yellow; background-color: transparent; text-decoration: underline;}
        a:active {color: red; background-color: transparent; text-decoration: underline;}
        </style>
        <title> </title>
      </head>
      <body>

      or for windows-1252:

      <!DOCTYPE html>
      <html>
      <head>
        <meta http-equiv="content-type" content="text/html; charset=windows-1252">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.25, maximum-scale=4.0, user-scalable=yes">
        <style>
        body {color: white; background-color: black; font-family: Helvetica, Arial, sans-serif;}
        a:link {color: lightskyblue; background-color: transparent; text-decoration: underline;}
        a:visited {color: orange; background-color: transparent; text-decoration: underline;;}
        a:hover {color: yellow; background-color: transparent; text-decoration: underline;}
        a:active {color: red; background-color: transparent; text-decoration: underline;}
        </style>
        <title> </title>
      </head>
      <body>

      for no cache (hardly ever works :-( , see: https://cristian.sulea.net/blog/disable-browser-caching-with-meta-html-tags/ :

      in style:

      Cache-Control: no-cache, no-store, must-revalidate
      Pragma: no-cache
      Expires: 0

      <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
      <meta http-equiv="Pragma" content="no-cache" />
      <meta http-equiv="Expires" content="0" />

      Debugging:

      Maintenance:

      D
      N
      S

      Bind, named and rndc

      Installation:

      • brew install bind
      • rndc-confgen -a

      Edit the conf file:

      • bbedit /usr/local/etc/bind/named.conf
      Add in the Options section the directory location of zone files, hiding version for security and rate limiting to prevent ddos amplification:

      directory "/usr/local/var/named";
      version "unknown";
      rate-limit {
                 responses-per-second 10;
      };

      And create the zone files in:

      • /usr/local/var/named/
      Start bind:
      • sudo brew services start bind
      • sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add $(readlink -f $(which named)) --unblockapp $(readlink -f $(which named))

      Debugging:

      First set up a separate window with tail of logging:

      • tail -f -n 1000 /usr/local/var/log/named/named.log

      Some checks:

      • rndc status
      • named-checkconf -z /usr/local/etc/bind/named.conf
      • host -t ns example.net

      Maintenance:

      • rndc sync -clean
      • rndc reload
      • sudo brew services restart bind
      • sudo brew services stop bind

      If the server for the domain gets a new ip address:

      • on the primary server in /usr/local/etc/named.conf
        • change ip address if needed for primary or secondary server entries
        • change ip address in reverse pointer record entry
      • on the primary server in /usr/local/var/named
        • in all relevant zone files change the ip addresses
        • also in those zone files increase the SOA serial numbers
        • refresh the bind server with a bind restart or rndc reload
      • at the dns registrar update the glue records
      • at each of the secondary name servers in /usr/local/etc/named.conf
        • change the appropriate ip addresses to the new values
        • refresh the bind server with a bind restart or rndc reload
      • request your ISP to update the reverse pointer for the ip addresses.

      DNSSEC

      Installation:

      Based on: The location and naming structure used for the zone files is:
      • The primary zone files: edit those to change records, etc.
        • /usr/local/var/named/example.net.zone
      • The keys:
        • /usr/local/var/named/keys/
      • Bind can automatically sign and will produce intermediate files in the same directory as the zone files.
      • mkdir /usr/local/var/named/keys

      Then we need to once generate the key for each zone file on the primary DNS server. That can be done with the following commands:

      • dnssec-keygen -3 -a ECDSAP256SHA256 -K /usr/local/var/named/keys/ example.net
      • dnssec-keygen -3 -a ECDSAP256SHA256 -f KSK -K /usr/local/var/named/keys/ example.net

      Enable DNSSEC in named.conf by adding the following configuration directives inside options{ }:

      • bbedit  /usr/local/etc/named.conf
      in the main options add:

      key-directory "/usr/local/var/named/keys";

      in each of the to be signed signed zones add:

          dnssec-policy default;
          inline-signing yes;

      Restart bind to sign the zones and load them in primary and secondaries:
      • sudo brew services restart bind

      Now we need the Delegation Signing records to supply to the parent zone manager. Note, some parent zone managers require the public key and generate the DS themselves. For the DS use dig and dnssec-dsfromkey using a SHA-256 algorithm:

      • dig @127.0.0.1 dnskey example.net | dnssec-dsfromkey -2 -f - example.net

      For the key alone:

      • dig @127.0.0.1 dnskey +multiline example.net

      Debugging:

      Check if for the DNSKEY record using dig on the same server.
      • dig DNSKEY example.net @localhost +multiline
      Check for the presence of RRSIG records.
      • dig A example.net @localhost +noadditional +dnssec +multiline
      Check DS records:
      • dig +trace +noadditional DS example.net @8.8.8.8 | grep DS
      Check DNSSEC:
      • http://dnssec-debugger.verisignlabs.com
      • http://dnsviz.net/

      Maintenance:

      MX, SPF, DMARC and CAA

      Installation:

      Zone file specials examples on MX, DMARC, SPF, CAA

      This are essential additions to zonefiles to express policy on mail handling and security.
      If your domain does not handle mail, a Null MX" No Service Resource Record for Domains That Accept No Mail expresses that in DNS. See https://tools.ietf.org/html/rfc7505

      MX

      •  @              IN MX      10 smtp.example.net.

      SPF

      SPF (Sender Policy framework) record to indicate where email from this domain is approved to come from:

      • @              IN TXT     "v=spf1 a mx -all"
      SPF record to indicate where no email senders approved:
      • @              IN TXT     "v=spf1 -all"

      DMARC

      r=relaxed, s=strict

      • _dmarc      IN TXT     "v=DMARC1; p=none; pct=100; aspf=r; adkim=r; rua=mailto:sysadmin@example.net"

      Strict with spf and dkim:

      • _dmarc      IN TXT     "v=DMARC1; p=quarantine; pct=100; aspf=s; adkim=s; rua=mailto:sysadmin@example.net"

      CAA

      CAA (Certificate Authority Authorized) advertises via DNS what CA is used by the domain. For LetsEncrypt:
      • @              IN CAA     128 issue "letsencrypt.org"

      Debugging:

      Maintenance:

      DANE

      Installation:

      Work in progress. Let's Encrypt makes that it needs to be renewed every 3 months, or needs an adapted server certificate. Based on:

      1. https://blog.apnic.net/2017/01/06/lets-encrypt-dane/
      2. https://www.internetsociety.org/blog/2016/01/lets-encrypt-certificates-for-mail-servers-and-dane-part-1-of-2/
      3. https://stats.dnssec-tools.org/
      4. https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html
      5. Van Kruyt: https://kruyt.org/postfix-and-tls-encryption/
      6. https://joscor.com/blog/dane-tlsa-tutorial/
      7. Randy's method:
        • https://community.letsencrypt.org/t/making-a-dane-tlsa-to-work-with-le/2129
        • openssl x509 -in stuff5.pem -noout -pubkey | openssl rsa -pubin -outform DER | openssl dgst -sha256 -hex | awk '{print "le-ca TLSA 2 1 1", $NF}'
        • wget -q -O - https://letsencrypt.org/certs/2024/e5.pem | openssl x509 -noout -pubkey | openssl rsa -pubin -outform DER | openssl dgst -sha256 -hex | awk '{print "le-ca TLSA 2 1 1", $NF}' 
      The steps using [1]:

      First check if the intermediate certificate of your cert provider changed recently. If so, you may want to have several hashed signatures in your DANE RRSET.
      • https://crt.sh/?q=example.net
      • study the current and recent issuer names, CN=<name>.

      The current intermediate certificates from LetsEncrypt (see: https://letsencrypt.org/certs/) are:
      Active: e5, e6, r10, r11

      • https://letsencrypt.org/certs/2024/e5.pem
      • https://letsencrypt.org/certs/2024/e6.pem
      • https://letsencrypt.org/certs/2024/r10.pem
      • https://letsencrypt.org/certs/2024/r11.pem

      And their der formats:

      • https://letsencrypt.org/certs/2024/e5.der
      • https://letsencrypt.org/certs/2024/e6.der
      • https://letsencrypt.org/certs/2024/r10.der
      • https://letsencrypt.org/certs/2024/r11.der

      le-ca IN TLSA 2 1 1 2bbad93ab5c79279ec121507f272cbe0c6647a3aae52e22f388afab426b4adba
      le-ca IN TLSA 2 1 1 6ddac18698f7f1f7e1c69b9bce420d974ac6f94ca8b2c761701623f99c767dc7
      le-ca IN TLSA 2 1 1 3586d4ecf070578cbd27aedce20b964e48bc149faeb9dad72f46b857869172b8
      le-ca IN TLSA 2 1 1 d016e1fe311948aca64f2de44ce86c9a51ca041df6103bb52a88eb3f761f57d7

      Backup: e7, e8, e9, r12, r13, r14

      • https://letsencrypt.org/certs/2024/e7.der
      • https://letsencrypt.org/certs/2024/r12.der
      Download the Let’s Encrypt Authority current and backup .der files and feed it into openssl to hash the lets-encrypt certs into 2 0 1 TLS records:
      • wget -q -O - https://letsencrypt.org/certs/lets-encrypt-e5.der | openssl dgst -sha256 -hex | awk '{print "le-ca IN TLSA 2 1 1", $NF}'
      • wget -q -O - https://letsencrypt.org/certs/2024/r10.der | openssl dgst -sha256 -hex | awk '{print "le-ca IN TLSA 2 1 1", $NF}'
      • wget -q -O - https://letsencrypt.org/certs/2024/r11.der | openssl dgst -sha256 -hex | awk '{print "le-ca IN TLSA 2 1 1", $NF}'
      producing NOT YET!!!!!!!!

      Current list according to https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html:
      le-ca IN TLSA 2 1 1 2bbad93ab5c79279ec121507f272cbe0c6647a3aae52e22f388afab426b4adba
      le-ca IN TLSA 2 1 1 6ddac18698f7f1f7e1c69b9bce420d974ac6f94ca8b2c761701623f99c767dc7
      le-ca IN TLSA 2 1 1 919c0df7a787b597ed056ace654b1de9c0387acf349f73734a4fd7b58cf612a4
      le-ca IN TLSA 2 1 1 025490860b498ab73c6a12f27a49ad5fe230fafe3ac8f6112c9b7d0aad46941d
      le-ca IN TLSA 2 1 1 f1647a5ee3efac54c892e930584fe47979b7acd1c76c1271bca1c5076d869888
      le-ca IN TLSA 2 1 1 3586d4ecf070578cbd27aedce20b964e48bc149faeb9dad72f46b857869172b8
      le-ca IN TLSA 2 1 1 d016e1fe311948aca64f2de44ce86c9a51ca041df6103bb52a88eb3f761f57d7
      le-ca IN TLSA 2 1 1 cbbc559b44d524d6a132bdac672744da3407f12aae5d5f722c5f6c7913871c75
      le-ca IN TLSA 2 1 1 885bf0572252c6741dc9a52f5044487fef2a93b811cdedfad7624cc283b7cdd5
      le-ca IN TLSA 2 1 1 f1440a9b76e1e41e53a4cb461329bf6337b419726be513e42e19f1c691c5d4b2
      le-ca IN TLSA 2 1 1 8d02536c887482bc34ff54e41d2ba659bf85b341a0a20afadb5813dcfbcf286d
      le-ca IN TLSA 2 1 1 e5545e211347241891c554a03934cde9b749664a59d26d615fe58f77990f2d03
      le-ca IN TLSA 2 1 1 276fe8a8c4ec7611565bf9fce6dcace9be320c1b5bea27596b2204071ed04f10
      le-ca IN TLSA 2 1 1 bd936e72b212ef6f773102c6b77d38f94297322efc25396bc3279422e0c89270

      Then put that in the zone file and add cname records for the different protocols and sub domain names:

      _587._tcp.smtp IN CNAME le-ca
      _465._tcp.smtp IN CNAME le-ca
      _25._tcp.smtp IN CNAME le-ca
      _25._tcp IN CNAME le-ca
      _443._tcp IN CNAME le-ca
      _993._tcp IN CNAME le-ca
      _995._tcp IN CNAME le-ca

      Possible rndc commands:
      • rndc reload
      • rndc reconfig

      Debugging:

      Maintenance:

      DKIM

      Installation:

      Some thoughts about key management and key rotation:

      If one goes for one key pair for several domains, one primary domain and several additional domains, all handled by the same mail server:

      Assume a scheme of aliases to the prime domain. Do a number of aliases in each additional domain looking like:

      $ORIGIN    additional.top.
      ...
      key1._domainkey    IN CNAME key1._domainkey.prime.top.
      key2._domainkey    IN CNAME key2._domainkey.prime.top.
      key3._domainkey    IN CNAME key3._domainkey.prime.top.
      key4._domainkey    IN CNAME key4._domainkey.prime.top.

      In the prime domain each of them can point to either a retired or previous or current or a potential next key and rotate through those. so:

      $ORIGIN    prime.top.
      ...
      key1._domainkey IN TXT     "v=DKIM1;k=rsa;p="
      key2._domainkey IN TXT     "v=DKIM1;k=rsa;p=MIIBIjANB etc etc etc"
      key3._domainkey IN TXT     "v=DKIM1;k=rsa;p=HnYukyhgl etc etc etc"
      ; key4._domainkey IN TXT ==> to be used next time

      Assume 4 key entries like this is enough (one previous retired, one old, one current and one to use next).
      The to use next is commented out at the prime domain, so that when it gets used it is filled with key, uncommented  and can populate dns without cache issues. The scheme should be enough but can be expanded, and the scheme can still support individual keys per domain later with more editing.

      Based on:

      Debugging:

      Check for the DKIM record using dig on the same server.

      • dig

      Maintenance:

      MTA-STS

      Installation:

      For explanation see: https://www.uriports.com/blog/mta-sts-explained/
      See also RFC 8461

      In DNS zone file:

      Debugging:

      Maintenance:

      M
      A
      I
      L

      Postfix and Dovecot

      Installation:

      Email server

      Here some options to get a higher internet.nl score:

      Based on:
      smtp_tls_security_level = encrypt
      smtpd_tls_security_level = encrypt

      smtpd_tls_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
      smtp_tls_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
      smtp_tls_ciphers = medium
      smtpd_tls_ciphers = medium
      smtpd_tls_mandatory_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
      smtp_tls_mandatory_protocols = TLSv1.3, TLSv1.2, !TLSv1.1, !TLSv1, !SSLv2, !SSLv3
      smtp_tls_mandatory_ciphers = high
      smtpd_tls_mandatory_ciphers = high

      smtpd_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
      smtpd_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
      smtp_tls_mandatory_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
      smtp_tls_exclude_ciphers = MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL
      tls_preempt_cipherlist = yes
      tls_ssl_options = NO_RENEGOTIATION

      smtpd_tls_dh2048_param_file = <PATH TO>/dh2048.pem
      smtpd_tls_dh1024_param_file = <PATH TO>/dh1024.pem
      smtpd_tls_dh512_param_file = <PATH TO>/dh512.pem

      Debugging:

      Maintenance:

      S
      S
      H

      SSH and VNC on a different port number

      Installation:

      This procedure and port numbers come from:

      See also:

      Note, we do not change the client side! Procedure using sed to change port 22 in 12345 on server side in file /etc/services in the lines:
      • ssh 22/udp # SSH Remote Login Protocol
      • ssh 22/tcp # SSH Remote Login Protocol

      and

      • rfb             5900/tcp    vnc-server # VNC Server
      • rfb             5900/udp    vnc-server # VNC Server

      using the commandline sed commands for server side:

      sudo sed -i -e 's+ 22/udp + 12322/udp +g' /etc/services
      sudo sed -i -e 's+ 22/tcp + 12322/tcp +g' /etc/services
      sudo sed -i -e 's+ 5900/tcp + 12359/tcp +g' /etc/services
      sudo sed -i -e 's+ 5900/udp + 12359/udp +g' /etc/services
      sudo launchctl unload -w /System/Library/LaunchDaemons/ssh.plist && sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist
      sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.screensharing.plist && sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.screensharing.plist

      SSH tunnel for e.g. VNC where the vnc port number is not changed on the server side. Here we assume ssh over port 12345. After this tunnel setup one can use vnc to 127.0.0.1:5901 to reach the other machine:

      • ssh -p 12345 -v -L 5901:127.0.0.1:5900 destination
      • vnc://127.0.0.1:5901/

      Debugging:

      Maintenance:

      SSH tunnel for SMB for timemachine

      Installation:

      Purpose is to tunnel port 445 (SMB) through a ssh tunnel to get past port filtering of some ISP's to allow Apple Timemachine to work to remote servers. This is implemented by creating a network alias to loopback interface in order to have a local tunnel endpoint on port 445 (SMB). Then create keys for ssh if not already there, copy the key(s) to the timemachine server for password-less login. Then create a ssh tunnel from the local alias address to the remote server. The remote disk for backup can then be mounted as a normal smb disk by addressing the local alias address. The procedure:

      Create an alias to be able to bind port 445 locally to a tunnel:

      • sudo ifconfig lo0 alias 127.0.0.2/32
      If not done before: create ssh key to authenticate to remote host, login in the remote host to get the fingerprint added to known hosts, and move public key to remote server:
      • ssh-keygen
      • ssh -p <port> remoteuser@example.net
      • ssh-copy-id -p <port> -i /Users/localuser/.ssh/id_rsa remoteuser@example.net
      Test the ssh for both user and root. Need to test root since we want to forward the privileged port 445 later. This also ensures that the server is in the list of known hosts.
      • ssh -p <port> remoteuser@example.net
      • sudo ssh -p <port> -i /Users/localuser/.ssh/id_rsa remoteuser@example.net
      Then set up the tunnel in a way that (hopefully) keeps the tunnel open:
      • sudo ssh -f -C -N -p <port> -i /Users/localuser/.ssh/id_rsa -L 127.0.0.2:445:127.0.0.1:445 -o ServerAliveCountMax=3 -o ServerAliveInterval=15 -o ExitOnForwardFailure=yes remoteuser@example.net
      One can also try to use autossh for more tunnel robustness. If not already installed, install autossh and ssh to have the matching version:
      • brew install ssh
      • brew install autossh

      Start the tunnel:

      • sudo autossh -M 0 -f -C -N -p <port> -i /Users/localuser/.ssh/id_rsa -L 127.0.0.2:445:127.0.0.1:445 -o ServerAliveCountMax=3 -o ServerAliveInterval=15 -o ExitOnForwardFailure=yes remoteuser@example.net

      Debugging:

      Check if alias is up:

      • ifconfig | grep 127
      Check if tunnel is present:
      • ps aux | grep tunnel

      Unload deamon:

      • ifconfig | grep 127
      • ps aux | grep ssh

      Maintenance:

      NOTE: this all works but is not persistent. After a reboot the following needs to be redone:

      • sudo ifconfig lo0 alias 127.0.0.2/32
      • sudo ssh -f -C -N -p <port> -i /Users/localuser/.ssh/id_rsa -L 127.0.0.2:445:127.0.0.1:445 -o ServerAliveCountMax=3 -o ServerAliveInterval=15 -o ExitOnForwardFailure=yes remoteuser@example.net

      Startup script for ssh tunnel for timemachine

      Installation:

      To create the loopback alias address and the autossh each time the machine is booted, create a startup.sh script at /usr/local/var and Launch Daemon property list file located at /Library/LaunchDaemons/localhost.startup.plist.

      Copy next  piece of text into your terminal to create the to be executed file at startup:

      cat > startup-ssh.sh <<EOF
      #!/bin/zsh
      ifconfig lo0 alias 127.0.0.2/32
      autossh -M 0 -f -C -N -p <port> -i /Users/localuser/.ssh/id_rsa -L 127.0.0.2:445:127.0.0.1:445 -o ServerAliveCountMax=3 -o ServerAliveInterval=15 -o ExitOnForwardFailure=yes remoteuser@example.net
      EOF

      • sudo mv startup-ssh.sh /usr/local/var/startup-ssh.sh
      • sudo chmod +x /usr/local/var/startup-ssh.sh
      And copy next  piece of text into your terminal to create the launchctl plist file:

      cat >localhost.startup-ssh.plist<<EOF
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
          <dict>
              <key>Label</key>
              <string>localhost.startup-ssh</string>
              <key>RunAtLoad</key>
              <true/>
              <key>EnvironmentVariables</key>
              <dict>
                   <key>PATH</key>
                    <string>/opt/homebrew/sbin:/opt/homebrew/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin</string>
              </dict>
              <key>ProgramArguments</key>
              <array>
                  <string>/usr/local/var/startup-ssh.sh</string>
              </array>
          </dict>
      </plist>
      EOF

      Then set attributes of the files and copy the plist to the correct place
      • sudo mv localhost.startup-ssh.plist /Library/LaunchDaemons/localhost.startup-ssh.plist
      • sudo chmod 644 /Library/LaunchDaemons/localhost.startup-ssh.plist
      • sudo chown root:admin /Library/LaunchDaemons/localhost.startup-ssh.plist
      • sudo launchctl load -w /Library/LaunchDaemons/localhost.startup-ssh.plist

      Debugging:

      Unload/load and check for deamon:

      • sudo launchctl list | grep -i startup-ssh
      • ps aux | grep ssh
      • sudo launchctl unload -w /Library/LaunchDaemons/localhost.startup-ssh.plist
      • sudo launchctl load -w /Library/LaunchDaemons/localhost.startup-ssh.plist

      Maintenance:

      P
      O
      W
      E
      R

      Startup script for server related power settings

      Installation:

      There are multiple ways to handle sleep and power settings. One way is pmset, but also systemsetup can set a number of parameters. Here pmset configuration is handled.

      To create a startup script to ensure power settings suitable for server operation:

      Copy next two pieces of text into your terminal to create the files:

      cat>startup-power.sh <<EOF
      #!/bin/zsh
      pmset restoredefaults
      pmset -a autopoweroff 0
      pmset -a standby 0
      pmset -a hibernatemode 0
      pmset -a sleep 0
      pmset -a displaysleep 10
      pmset -a disksleep 10
      pmset -a womp 1
      pmset -a autorestart 1
      pmset repeat wakeorpoweron MTWRFSU "08:00:00"
      caffeinate -i &
      EOF

      cat>localhost.startup-power.plist<<EOF
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
      <plist version="1.0">
          <dict>
              <key>Label</key>
              <string>localhost.startup-power</string>
              <key>RunAtLoad</key>
              <true/>
              <key>EnvironmentVariables</key>
              <dict>
                   <key>PATH</key>
                    <string>/opt/homebrew/sbin:/opt/homebrew/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin</string>
              </dict>
              <key>ProgramArguments</key>
              <array>
                  <string>/usr/local/var/startup-power.sh</string>
              </array>
          </dict>
      </plist>
      EOF

      Then set attributes of the files and copy the plist to the correct place
      • sudo mv startup-power.sh /usr/local/var/startup-power.sh
      • sudo chmod +x /usr/local/var/startup-power.sh
      • sudo chmod 644 localhost.startup-power.plist
      • sudo mv localhost.startup-power.plist /Library/LaunchDaemons/localhost.startup-power.plist
      • sudo chown root:admin /Library/LaunchDaemons/localhost.startup-power.plist
      • sudo launchctl load -w /Library/LaunchDaemons/localhost.startup-power.plist

      Debugging:

      Unload/load and check for deamon:

      • sudo launchctl list | grep -i startup-power
      • sudo launchctl unload -w /Library/LaunchDaemons/localhost.startup-power.plist
      • sudo launchctl load -w /Library/LaunchDaemons/localhost.startup-power.plist

      Restore to defaults:

      • sudo pmset restoredefaults

      Maintenance:

      Alternative, to be checked:

      • sudo systemsetup -setcomputersleep Never
      • man systemsetup

      B
      A
      C
      K
      U
      P


      TimeMachine

      Installation:

      Here are TimeMachine cli commands to start up, stop, get info, etc. The info comes from:

      The basics of the tmutil command can be found by typing
      • man tmutil
      The man page tells you what you can do with this command. For example, to turn Time Machine on or off, you can run these commands:
      • sudo tmutil enable
      • sudo tmutil disable

      To get the status of anything going on or progressing:

      • tmutil status
      If you want to run a Time Machine backup right away, on a Mac that either has Time Machine disabled, or, say, just before updating to a new version of OS X, you can run this command:
      • tmutil startbackup
      This is the same as choosing Back Up Now from the Time Machine menu in the menu bar at the top of your screen. And if you ever want to stop a backup, just run this:
      • tmutil stopbackup
      Save disk space on your laptop Since your laptop isn’t always connected to its backup disk, Time Machine retains "local snapshots," or files that it will copy to your backup disk the next time it is available. However, these local snapshots take up space, and you may want to turn this feature off if you don’t have much room on your hard disk. You can turn off (Running this command will also delete any local snapshots.) and on with the following commands:
      • sudo tmutil disablelocal
      • sudo tmutil enablelocal
      You can exclude certain files and folders from your Time Machine backups from the Time Machine pane in System Preferences. Naturally, you can also do this from the command line, too. Run this command:
      • sudo tmutil addexclusion <path of folder/file to exclude>
      The tmutil addexclusion command has an interesting property: it's sticky. When you use this command, the item you exclude remains in the Time Machine exclusion list even if you move it, which is not the case when you exclude items from the Time Machine preference pane. If you use the above command with the -p flag, then it will not be sticky, and will be the same as an exclusion you add from the Time Machine preference pane.

      If you’re managing a remote Mac, such as a server, you may want to change Time Machine settings for that computer. You can start by finding where Time Machine backups are stored. Run this command:
      • tmutil destinationinfo
      To change the destination, you can use two commands. First, remove the current destination like this:
      • tmutil removedestination ......
      In place of ..... , type in the text string returned by the destinationinfo command. Then run this command to set up a new destination disk:
      • tmutil setdestination volume_name
      Replace volume_name with the name of the disk or volume you want to use. You can add multiple destinations as well, since Time Machine can rotate its backups on several disks or volumes. See man tmutil for more on setting up multiple backup destinations. (You can now do this without the command line too, see "How to create redundant Time Machine backups.")

      Time Machine saves a lot of backups: one per hour for the past 24 hours; one a day for the past week; and one a week before that. You can get a list of all the backups on your Time Machine disk with this command:
      • tmutil listbackups
      The tmutil command offers many other options, such as the ability to inherit destinations, perform detailed comparisons of backups, restore items and much more. See man tmutil to find out all that you can do.

      Debugging:

      This procedure is to correct errors like: "Time Machine completed a verification of your backups. To improve reliability, Time Machine must create a new backup for you.". It may or may not work. The procedures come from:

      The steps:
      • sudo chflags -R nouchg   <the backup bundle>
      • sudo hdiutil attach -nomount -noverify -noautofsck <the backup bundle>

      If you have apfs:

      • sudo fsck_apfs -o -v -s   /dev/diskXs2
      • if you get the “Operation not permitted” Error, give the terminal.app full disk access in the preferences privacy panel.

      if you have hfs:

      • sudo fsck_hfs -c 2g -drfy /dev/diskXs2
      • if you get the “Operation not permitted” Error, give the terminal.app full disk access in the preferences privacy panel.
      If you get a message in the fsck_hfs.log along the lines of " RebuildBTree - record x in node y is not r" then try:
      • sudo fsck_hfs -c 2g -p /dev/diskXs2
      • sudo fsck_hfs -c 2g -drfy /dev/diskXs2

      To scan for bad blocks:

      • sudo fsck_hfs -S /dev/diskXs2
      When succeeded:
      • sudo hdiutil detach /dev/diskXs2
      When complete, you need to edit an plist file within the sparsebundle that records the state of the backup. On the top level of the sparsebundle find a file called "com.apple.TimeMachine.MachineID.plist".
      • bbedit <the backup bundle>/com.apple.TimeMachine.MachineID.plist
      Remove these two nodes:

      <key>RecoveryBackupDeclinedDate</key>
      <date>{whatever-the-date}</date>

      Finally you want to change:

      <key>VerificationState</key><integer>2</integer>
      to
      <key>VerificationState</key><integer>0</integer>

      Now Time Machine can give it another go. After the (long) verification step, backups should proceed once again.

      To find log file entries:
      • sudo tail -f -n 1000 /var/log/fsck_hfs.log
      • log show --predicate 'subsystem == "com.apple.TimeMachine"' --info | grep 'upd: (' | cut -c 1-19,140-999

      Sometimes a lock on the sparse bundle seems to block mounting the image. Disabling and re-enabling sharing on the server also seems to fail, even after reboot. What worked was stopping and starting the smbd plist:
      Quote: Today I've been really logging everything and watching the system constantly and found that if I kill SMB and restart it then everything works again, including unlocking the sharing pane. I use:

      • sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.smbd.plist
      • sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.smbd.plist

      Maintenance:

      S
      Y
      S
      T
      E
      M

      Opencore Legacy Patcher

      Installation:

      See:


      Debugging:

      If GUI is not possible:

      sudo /Applications/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher --patch_sys_vol

      sudo /Applications/OpenCore-Patcher.app/Contents/MacOS/OpenCore-Patcher -h

      usage: OpenCore-Patcher [-h] [--build] [--verbose] [--debug_oc] [--debug_kext] [--hide_picker]
                              [--disable_sip] [--disable_smb] [--vault] [--support_all] [--firewire]
                              [--disable_tb] [--force_surplus] [--model MODEL] [--disk DISK]
                              [--smbios_spoof SMBIOS_SPOOF] [--nvme] [--wlan] [--moderate_smbios]
                              [--patch_sys_vol] [--unpatch_sys_vol] [--validate] [--gui_patch]
                              [--gui_unpatch] [--auto_patch] [--update_installed]

      options:
        -h, --help            show this help message and exit
        --build               Build OpenCore
        --verbose             Enable verbose boot
        --debug_oc            Enable OpenCore DEBUG
        --debug_kext          Enable kext DEBUG
        --hide_picker         Hide OpenCore picker
        --disable_sip         Disable SIP
        --disable_smb         Disable SecureBootModel
        --vault               Enable OpenCore Vaulting
        --support_all         Allow OpenCore on natively supported Models
        --firewire            Enable FireWire Booting
        --nvme                Enable NVMe Booting
        --wlan                Enable Wake on WLAN support
        --moderate_smbios     Moderate SMBIOS Patching
        --disable_tb          Disable Thunderbolt on 2013-2014 MacBook Pros
        --force_surplus       Force SurPlus in all newer OSes
        --model MODEL         Set custom model
        --disk DISK           Specifies disk to install to
        --smbios_spoof SMBIOS_SPOOF
                              Set SMBIOS patching mode
        --patch_sys_vol       Patches root volume
        --unpatch_sys_vol     Unpatches root volume, EXPERIMENTAL
        --validate            Runs Validation Tests for CI
        --gui_patch           Starts GUI in Root Patcher
        --gui_unpatch         Starts GUI in Root Unpatcher
        --auto_patch          Check if patches are needed and prompt user
        --update_installed    Prompt user to finish updating via GUI

      Maintenance:

      Firewall problems

      Installation:

      Resolving Trusted Execution Problems

      see: https://developer.apple.com/forums/thread/706442

      see: https://www.reddit.com/r/mac/comments/11hiuyl/firewall_options_macos_not_saving_after_closing/

      Debugging:

      sudo /usr/libexec/ApplicationFirewall/socketfilterfw -help

      usage: /usr/libexec/ApplicationFirewall/socketfilterfw [-d] [-l] [-k] [--getglobalstate] [--setglobalstate on | off] [--getblockall] [--setblockall on | off] [--listapps] [--getappblocked <path>] [--blockapp <path>] [--unblockapp <path>] [--add <path>] [--remove <path>] [--getallowsigned] [--setallowsigned] [--setallowsignedapp] [--getstealthmode] [--setstealthmode on | off] [--getloggingmode] [--setloggingmode on | off] [--getloggingopt] [--setloggingopt throttled | brief | detail]
      firewallapp is used to control Application Firewall socket filter.

      The command takes the following options that are evaluated in order, and several options may be combined:
       -h        display this help and exit
       -d        turn on debugging
       -l        do logging and run in daemon mode
       -k        kill daemon
       --getglobalstate                display if the firewall is enabled or not
       --setglobalstate on | off       turn the firewall on or off
       --getblockall                   show whether block all is enabled or not
       --setblockall on | off          enable or disable block all option
       --listapps                      display a list of paths of added applications
       --getappblocked <path>          show whether connections are blocked or not for the application at <path>
       --blockapp <path>               block the application at <path>
       --unblockapp <path>             unblock the application at <path>
       --add <path>                    add the application at <path> to the firewall
       --remove <path>                 remove the application at <path> from the firewall
       --getallowsigned                show whether built-in and downloaded signed applications are to automatically receive incoming connections
       --setallowsigned on | off       set whether built-in signed applications are to automatically receive incoming connections or not
       --setallowsignedapp on | off    set whether downloaded signed applications are to automatically receive incoming connections or not
       --getstealthmode                show whether stealth mode is on or not
       --setstealthmode on | off       set stealth mode on or off
       --getloggingmode                show whether logging is on or not
       --setloggingmode on | off       set logging to on or off
       --getloggingopt                 show logging option
       --setloggingopt throttled |     set logging option
                           brief |
                          detail


      sudo /usr/libexec/ApplicationFirewall/socketfilterfw --getglobalstate --getblockall --getallowsigned --getstealthmode --listapps
      sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add $(readlink -f $(which named)) --unblockapp $(readlink -f $(which named))
      sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add $(readlink -f $(which httpd)) --unblockapp $(readlink -f $(which httpd))
      sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on
      sudo /usr/libexec/ApplicationFirewall/socketfilterfw --remove

      Also:
      Check: /Library/Preferences/com.apple.alf.plist
      sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.alf.agent.plist
      sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.alf.agent.plist 


      Maintenance:

      Calendar problems

      Installation:

      Debugging:

      How to solve the error: "Apple Calendar Can’t Save Event to Exchange":

      See: https://michaelkummer.com/tech/apple/macos-calendar-exchange/

      • Quit Calendar application (Command + Q)
      • Quit Apple Mail
      • Open Activity Monitor (through Spotlight or Launchpad)
      • Search for "Calendar" and quit all the relevant processes
      • Open Finder and navigate to ~/Library/Calendars
      • Double-check Activity Monitor to make sure no Calendar-related processes are running
      • Delete cache files
      • Relaunch Calendar

      How to solve sync errors with O365:

      sudo launchctl stop com.apple.CalendarAgent
      sudo launchctl start com.apple.CalendarAgent

      sudo pkill -9 -i calendar

      Maintenance:

      Network Performance tools

      Installation:

      See:

      brew install iperf iperf3 nuttcp owamp

      Debugging:

      iperf

      Server:

      • iperf -s -i 4 -w 3M
      Client:
      • iperf -i 4 -t 1000 -N -w 3M -l 1M -c [servername]

      iperf3

      Server:

      • iperf3 -s -i 5
      Client:
      • iperf3 -i 4 -t 1000 -N -w 3M -l 1M -c [servername]

      nuttcp

      On the server:

      • nuttcp -S
      Client:
      • nuttcp [servername]
      This runs a 10 second test, only on ipv4

      Maintenance:

      S
      M
      A
      R
      T

      Smart Home - Homebridge

      Installation:

      See:

      We install node.js using brew:
      • brew install node.js
      Check version of node and npm (node package manager):
      • node -v
      • npm -v
      Install homebridge:
      • sudo npm install -g --unsafe-perm homebridge homebridge-config-ui-x
      Fix remaing errors automattically and install hb-service:
      • npm audit fix
      • npm i --package-lock-only
      • sudo hb-service install
      Manage Homebridge by going to one of the following in your browser:

      http://localhost:1234 - Default Username: admin - Default Password: admin
      Advice is to change the user/pw immediately, and I recommend to set up a https proxy to access homebridge.

      To stop/start hombridge:
      • sudo launchctl unload -w /Library/LaunchDaemons/com.homebridge.server.plist
      • sudo launchctl load -w /Library/LaunchDaemons/com.homebridge.server.plist
      If you need to remove it:
      • npm uninstall -g homebridge

      Debugging:

      If the underlying node.js software is upgraded by brew, the homebridge will fail after restart. The correct procedure:

      • sudo hb-service stop
      • sudo launchctl unload -w /Library/LaunchDaemons/com.homebridge.server.plist
      • sudo launchctl load -w /Library/LaunchDaemons/com.homebridge.server.plist
      • sudo hb-service start

      Oter usefull commands:

      • Restart Command         sudo hb-service restart
      • Stop Command             sudo hb-service stop
      • Start Command             sudo hb-service start
      • View Logs Command    hb-service logs
      File Locations:
      Config File Path ~/.homebridge/config.json
      Storage Path
      ~/.homebridge
      Launchctl Service File /Library/LaunchDaemons/com.homebridge.server.plist

      Maintenance:

      T
      I
      P
      S

      Common pitfalls, problems, useful commands

      Installation:

      • After a brew upgrade some services may not work. One difficult to diagnose problem may be the firewall settings in MacOSX. It blocks by default incoming connections on unsigned bin's and executables need to be added in the list in the System Preferences Firewall settings. Also note that just putting there the /usr/local/bin/executable will not work since brew puts aliasses (links) there. Follow the link to the real bin. Same for /usr/local/sbin .
      • Somehow launchd has a different or incomplete PATH environment. Caused certbot renew to initially fail.
      • System upgrade using cli:
        • to get a list of available updates:
          • softwareupdate -l
        • to update a specific package:
          • softwareupdate -i NAME
        • to update all:
          • softwareupdate -i -a
        • for hlep:
          • softwareupdate -h
        • for configuration data
          • softwareupdate -l --include-config-data
        • and
          • softwareupdate -i --include-config-data NAME
      • System version info:
        • Show Apple hardware and software configuration:
          • system_profiler
        • Show Mac OS X operating system version:
          • sw_vers
        • Print just the value of the ProductName property:
          • sw_vers -productName
        • Display the value of the ProductVersion property
          • sw_vers -productVersion
        • Display the build version:
          • sw_vers -buildVersion
      • If the mac is using lots of processes to index for SpotLight, to turn indexing off:
        • sudo mdutil -a -i off
      • and on:
        • sudo mdutil -a -i on
      • If you use screensharing and end the session, the target screen typically goes dark and locks. If you want the screen to stay on, then <see https://discussions.apple.com/thread/7345064>:
        • sudo defaults write /Library/Preferences/com.apple.RemoteManagement RestoreMachineState -bool NO
      • A mac that is protected with filevault may not reboot gracefully because a password is needed to access the startup disc. A way to do a reboot is:
        • sudo fdesetup authrestart
      • if you need to log out another user:
        • ps awwwwux | grep loginwindow
        • kill the pid of that user with:
        • sudo kill -9 [pid]
      • Support files can be found HERE.
      • SSH plus Screensharing
        • ssh -p 22 -N -L 5999:localhost:5900 user@example.net
        • vnc://localhost:5999
      • If you have screensharing on a different port number to reload screensharing with the new port number:
        • sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.screensharing.plist &&  sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.screensharing.plist
      • Starting/stopping remote desktop. The commands in this article https://support.apple.com/en-us/HT201710  work with Apple Remote Desktop 3.2 and later. Here are commands that you can use:
        • Restart the ARD Agent and helper:
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -restart -agent
        • Turn on Remote Desktop Sharing, allow access for all users, and enable the menu extra:
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -allowAccessFor -allUsers -privs -all -clientopts -setmenuextra -menuextra yes
        • Turn on Remote Desktop Sharing, allow access for specified users:
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -activate -configure -allowAccessFor -specifiedUsers
        • You must use the -configure, -access, and -privs options in a separate command to specify the set of users and their access privileges. For example, this command is for users with the short names "teacher" and "student." It gives them access to observe (but not control) the computer, and to send text messages:
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -users teacher,student -access -on -privs -ControlObserve -ObserveOnly -TextMessages
        • Unlike other kickstart options, you can’t combine the allowAccessFor options with other kickstart options. You must use it as in the last two samples above. You might have to call kickstart more than once to finish a computer’s setup. Remove access privileges for specified users ("student" in this example):
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -users student -access -off
        • Disable ARD Agent and remove access privileges for all users:
          • sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -deactivate -configure -access -off
      • Shell need to change from bash to zsh now:
        • The default interactive shell is now zsh. To update your account to use zsh, please run `chsh -s /bin/zsh`. For more details, please visit https://support.apple.com/kb/HT208050.
          • cp .bash_profile .zshrc
          • chsh -s /bin/zsh
        • restart terminal
          • brew doctor
      • How to get into a home router management interface:
        • TP-Link
          • http://tplinkwifi.net
        • NetGear
          • http://routerlogin.net
      • Routing
        • lsof -i -P
        • netstat -rn
        • The principles/info/utilities here:
          • http://www.sustworks.com/site/prod_ipnrx_help/html/AlternateRouteHelp.html
          • http://www.macosxhints.com/article.php?story=20050214200529336&query=setup
          • http://developer.apple.com/documentation/Darwin/Reference/ManPages/man8/routed.8.html

      Debugging:

      Maintenance:

      N
      E
      W

      New info & scratch space

      How to set and change different names of the server via CLI.

      https://knowledge.autodesk.com/support/smoke/learn-explore/caas/sfdcarticles/sfdcarticles/Setting-the-Mac-hostname-or-computer-name-from-the-terminal.html

      Solution:
      This information can be useful when configuring your workstation remotely through ssh, or when you need to change the fully qualified hostname of the workstation (which can't be done from the UI).

      Note: The following procedure is for informational purposes only and is not an Autodesk certified or supported workflow. Should issues arise with this procedure, they will not be addressed by Autodesk Customer Support.

      Perform the following tasks to change the workstation hostname using the scutil command.

      Open a terminal.
      Type the following command to change the primary hostname of your Mac:
      This is your fully qualified hostname, for example myMac.domain.com
      sudo scutil --set HostName <new host name>
      so for example:

      sudo scutil --set HostName flame01.domain.com
      Type the following command to change the Bonjour hostname of your Mac:
      This is the name usable on the local network, for example myMac.local.
      sudo scutil --set LocalHostName <new host name>
      so for example:

      sudo scutil --set LocalHostName flame01.local
      Type the following command to change the computer name:
      This is the user-friendly computer name you see in Finder, for example myMac.
      sudo scutil --set ComputerName <new name>
      so for example:

      sudo scutil --set ComputerName flame01
      Flush the DNS cache by typing:
      dscacheutil -flushcache

      Restart Mac.
      Additional Resources
      Type scutil --help for the complete list of parameters.



      When ip address of primary server changes because of ISP, to be updated:
      • dns:
        • named.config
        • zone files
        • reverse dns records
        • reverse ptr at ISP
        • glue records at registrar
        • named.conf at slaves
      • Web:
        • status page




      Open Terminal application
      Enter and press return:

      sudo fdesetup removerecovery -institutional
      Enter the administrator password
      Enter and press return:

      sudo fdesetup changerecovery -personal
      Enter the administrator password
      A recovery key is generated.



      I
      N
      F
      O

      How this page is made