diff options
-rw-r--r-- | content/articles/site-backend.md | 178 | ||||
-rw-r--r-- | static/files/articles/site-backend/pablotron.org.conf.txt | 76 |
2 files changed, 254 insertions, 0 deletions
diff --git a/content/articles/site-backend.md b/content/articles/site-backend.md new file mode 100644 index 0000000..6bfa592 --- /dev/null +++ b/content/articles/site-backend.md @@ -0,0 +1,178 @@ +--- +slug: "site-backend" +title: "Site Backend" + +# date (optional for articles) +date: "2023-09-08T05:07:47-04:00" + +# draft articles are not visible on live site +draft: true + +# show on articles page +show: true + +# uncomment to show table of contents +toc: true +--- +## Overview + +This site is statically generated by [Hugo][] and themed with a +stripped-down version of [Bulma][]. Both have been heavily customized; +see the [Configuration](#configuration) section for details. + +The goals of this setup are: + +- Size +- Speed +- Security +- Mobile Support +- Accessibility +- Simplicity (for me) + +## History + +From 1998 to 2019 this site was generated by a custom [PHP][] backend, +written by me. In 2019 I resurrected the site after a several year +hiatus and migrated the site from the custom [PHP][] backend to +[Jekyll][]. In 2021 I switched from [Jekyll][] to [Hugo][]. + +## Content + +### HTML + +I create and edit site content with [vim][] in [Markdown][] format and +preview the results locally with `hugo serve -D ...`. Articles and blog +posts are saved as drafts and committed to the [Git][] repository so I +can work on them as time permits. + +The content and site layout is designed with accessibility and mobile in +mind. This means: + +- links, and table components have `title`, `aria-label` attributes +- images have captions, fallback formats, `title` and `alt` attributes. +- images scale gracefully to thumbnails on mobile +- the site honors users' [color scheme preference][] and has a manual + theme override +- The page menu bar collapes to a hamburger menu on mobile. + +### Images + +Images are created as follows: + +- Mathematical content is created using [Mathy][], saved as [SVG][], + and minified using [minify][]. +- Charts are created with [Matplotlib][], saved as [SVG][], and minified + using [minify][]. +- Lossless images (e.g. screenshots) are scaled and cropped with + [GraphicsMagick][] and served as a lossless [WebP][] + with a [PNG][] fallback. The fallback is compressed with + [pngquant][]. +- Lossy images are [GraphicsMagick][] and served as a lossy [WebP][] + with a [JPEG][] fallback. +- Menubar icons are borrowed from [Bootstrap Icons][]. +- The animated site logo is generated by [this Ruby script][logo-script]. + +### JavaScript + +There is almost no [JavaScript][], by design. The one script that is +used is minimal, [deferred][], used for two things: + +1. to handle the [theme toggle][]. +2. to toggle the mobile site menu. + +## Deployment + +Once I am ready to apply any outstanding changes to the public web site, +I push the outstanding commits to a remote [Git][] repository. This +triggers a [`post-receive` hook][], which sends an authenticated `POST` +request to a [web hook][] exposed on a TLS endpoint on the web server. + +The [web hook][] runs a [deployment script (`deploy.rb`)][] which does +the following: + +1. Verifies the authenticated timestamp (to prevent replay attacks). +2. Clones the upstream repository. +3. Executes [Hugo][] (`hugo --minify -d ...`) to build the site minified + in a unique output directory. +4. Updates the `htdocs` symlink for the public web site to point at + the output directory from the previous step. +5. Removes any stale builds. + +## Configuration + +This section discusses the configuration for [Hugo][], [Bulma][] and +[Apache][]. + +### Hugo Configuration + +[Hugo][] is configured to use [Chroma syntax higlighting][] with inline +styles disabled (e.g., `class` attributes only, no `style`) in order to +support the restrictive `Content-Security-Policy` header (see "HTTP +Headers"). + +The formatted tables in the pages site are generated via [my +`hugo-shortcode-table` shortcode][], because the native table generator +for [Hugo][] uses inline styles. + +I have also written a couple of custom [shortcodes][] to generate +`<picture>` and `<figure>` elements in order to support [progressive +enhancement][]. + +The generated [HTML][] has been modified to: + +- add support `go-import` +- add a [Mastodon][] `<link rel='me' ...>` tag. +- remove all unnecessary tags +- to combine and [minify][] and [JavaScript][] and [CSS][] assets. +- to add `integrity` attributes to `<link>` and `<script>` tags. + +### Bulma Configuration + +**TODO:** + +- bulma modified to remove all unnecessary components + - show `style.css` +- added chroma styles +- added dark mode + +### Apache Configuration + +**TODO:** + +- security headers (see next section) +- `static/files/articles/site-backend/pablotron.org.conf.txt` (config w/ garbage removed) +- mod deflate +- mod rewrite for old links +- aggressive caching +- http2 +- letsencrypt +- tls config (1.2 or newer, remove garbage algos) + +## HTTP Security Headers + +TODO + +## Validation + +I periodically verify the following manually: + +- Developer console: Page load time, cached and uncached page size. +- [Lighthouse][]: Accessibility, desktop score, and mobile score. +- security headers +- tls configuration +- manual verification in the desktop and mobile versions of chrome and + firefox + +## Other + +- content served minified, cached, and compressed. +(more stuff from `TODO.md`) + +```apache +# TODO: include annotated files/articles/site-backend/pablotron.org.conf.txt +``` + +[hugo]: https://gohugo.io/ + "Hugo static site generator." +[bulma]: https://bulma.io/ + "Bulma minimal CSS framework." diff --git a/static/files/articles/site-backend/pablotron.org.conf.txt b/static/files/articles/site-backend/pablotron.org.conf.txt new file mode 100644 index 0000000..8934bad --- /dev/null +++ b/static/files/articles/site-backend/pablotron.org.conf.txt @@ -0,0 +1,76 @@ +<VirtualHost *:80> + Use BASIC_SITE pablotron.org www-admin@pablotron.org + Use BASIC_LOGS pablotron.org + Use STRIP_WWW https://pablotron.org + Use MOD_DEFLATE + + # unconditionally rewrite to https://pablotron.org + RewriteEngine On + RewriteRule ^/(.*)$ https://pablotron.org/$1 [R,L] +</VirtualHost> + +<VirtualHost *:443> + Use BASIC_SITE pablotron.org www-admin@pablotron.org + Use BASIC_LOGS pablotron.org + Use STRIP_WWW https://pablotron.org + Use MOD_DEFLATE + + SSLEngine on + SSLCertificateFile /etc/letsencrypt/live/pablotron.org/cert.pem + SSLCertificateKeyFile /etc/letsencrypt/live/pablotron.org/privkey.pem + SSLCertificateChainFile /etc/letsencrypt/live/pablotron.org/fullchain.pem + + # redirect old rss feed to new one + RewriteCond %{QUERY_STRING} theme=rss + RewriteCond %{REQUEST_URI} ^/$ + RewriteRule (.*) /index.xml [R=301,L] + + # enable http2 (added 2022-01-29) + Protocols h2 http/1.1 + + # set security headers + # (added on 2021-10-17) + # + # refs: + # - https://web.dev/security-headers/#xfo + # - https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP + # - https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS + # - https://scotthelme.co.uk/a-new-security-header-referrer-policy/ + # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy + # - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin + # + # permissions-policy docs (seems poorly thought out): + # * https://scotthelme.co.uk/goodbye-feature-policy-and-hello-permissions-policy/ + # * feature list (for old feature-policy header, but a good reference): https://source.chromium.org/chromium/chromium/src/+/master:third_party/blink/renderer/platform/feature_policy/feature_policy.cc;drc=ab90b51c5b60de15054a32b0bd18e4839536a1c9;l=138 + # https://github.com/w3c/webappsec-permissions-policy/blob/main/permissions-policy-explainer.md + # + Header append "Strict-Transport-Security" "max-age=31536000" + Header append "X-Frame-Options" "SAMEORIGIN" + Header append "X-Content-Type-Options" "nosniff" + Header append "Cross-Origin-Opener-Policy" "same-origin" + Header append "Cross-Origin-Resource-Policy" "same-origin" + Header append "Access-Control-Allow-Origin" "https://pablotron.org" + Header append "Referrer-Policy" "strict-origin-when-cross-origin" + + # not sure about these yet + Header append "Permissions-Policy" "camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), usb=()" + + # POST needed for /hooks + Header append "Access-Control-Allow-Methods" "POST, GET, HEAD, OPTIONS" + + # 'unsafe-inline' is needed for goldmark table cell alignment + # Header append "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org; style-src 'self' 'unsafe-inline'" + # removed all tables w/ alignment, so i nuked unsafe-inline (2021-10-21) + Header append "Content-Security-Policy" "default-src 'self'; img-src 'self' https://pmdn.org" + + # cache images, stylesheets, and javascript for 1 year + # (added 2022-01-29, i may regret this...) + <FilesMatch "\.(ico|jpg|jpeg|png|gif|webp|svg|js|json|css)$"> + Header set Cache-Control "max-age=31536000, public" + </FilesMatch> + + <Location /hooks/> + ProxyPass "http://localhost:9000/" + ProxyPassReverse "http://localhost:9000/" + </Location> +</VirtualHost> |