Commit e4fc1f14a2

e4fc1f14a255d0bcb961c056357ca7eff5467a13

parent: 0117af85bc

Verified · cmc

cmc <hello@cleberg.net> · 2026-03-11 08:00 UTC

add tag support

Layout: unified · split

build.py +137
@@ -381,6 +381,141 @@ def inject_blog_year_separators(blog_index_path="./.build/blog/index.html"):
381381 print(f"Blog year separators injected into {blog_index_path}")
382382
383383
384def generate_tags_page(content_dir="./content/blog", build_dir="./.build"):
385 """
386 Scans all blog org files for #+filetags, then writes .build/tags/index.html
387 with one section per tag, each post listed under its tags, sorted newest first.
388 Tags link to anchor IDs on the same page.
389 """
390 TAG_ORDER = ["audit", "emacs", "linux", "personal", "privacy", "security", "self-hosting", "web"]
391
392 header_patterns = {
393 "title": re.compile(r"^#\+title:\s*(.+)$", re.IGNORECASE),
394 "date": re.compile(r"^#\+date:\s*[\[<](\d{4}-\d{2}-\d{2})"),
395 "slug": re.compile(r"^#\+slug:\s*(.+)$", re.IGNORECASE),
396 "tags": re.compile(r"^#\+filetags:\s*(.+)$", re.IGNORECASE),
397 "draft": re.compile(r"^#\+draft:\s*(.+)$", re.IGNORECASE),
398 }
399
400 tag_map = {tag: [] for tag in TAG_ORDER}
401
402 for org_path in Path(content_dir).glob("*.org"):
403 title = date_str = slug = None
404 tags = []
405 is_draft = False
406
407 with org_path.open("r", encoding="utf-8") as f:
408 for line in f:
409 if not title:
410 m = header_patterns["title"].match(line)
411 if m: title = m.group(1).strip(); continue
412 if not date_str:
413 m = header_patterns["date"].match(line)
414 if m: date_str = m.group(1); continue
415 if not slug:
416 m = header_patterns["slug"].match(line)
417 if m: slug = m.group(1).strip(); continue
418 if not tags:
419 m = header_patterns["tags"].match(line)
420 if m:
421 raw = m.group(1).strip().strip(":")
422 tags = [t.strip() for t in raw.split(":") if t.strip()]
423 continue
424 m = header_patterns["draft"].match(line)
425 if m and m.group(1).strip().lower() != "nil":
426 is_draft = True; break
427 if title and date_str and slug and tags:
428 break
429
430 if is_draft or not (title and date_str and slug):
431 continue
432
433 try:
434 date_obj = datetime.strptime(date_str, "%Y-%m-%d")
435 except ValueError:
436 continue
437
438 for tag in tags:
439 if tag in tag_map:
440 tag_map[tag].append({"title": title, "slug": slug, "date_obj": date_obj, "date_str": date_str})
441
442 for tag in tag_map:
443 tag_map[tag].sort(key=lambda x: x["date_obj"], reverse=True)
444
445 # Build TOC
446 toc_items = "".join(
447 f'<li><a href="#{tag}">{tag}</a> <span class="tag-count">({len(tag_map[tag])})</span></li>'
448 for tag in TAG_ORDER
449 )
450
451 # Build sections
452 sections = []
453 for tag in TAG_ORDER:
454 posts = tag_map[tag]
455 items = "\n".join(
456 f'<li class="post-list-item">'
457 f'<a href="/blog/{p["slug"]}.html">{p["title"]}</a>'
458 f'<time datetime="{p["date_str"]}">{p["date_str"]}</time>'
459 f'</li>'
460 for p in posts
461 )
462 sections.append(f'<h2 id="{tag}">{tag}</h2>\n<ul class="post-list">\n{items}\n</ul>')
463
464 html = f"""<!doctype html>
465<html lang="en-us">
466<head>
467<meta charset="utf-8">
468<title>tags - seijaku</title>
469<meta name="viewport" content="width=device-width, initial-scale=1">
470<link rel="stylesheet" href="/styles.min.css" type="text/css">
471<link rel="icon" href="/favicon.svg" type="image/svg+xml">
472</head>
473<body>
474<a href="#main-content" class="skip-link">Skip to content</a>
475<header class="masthead">
476<a href="/" class="masthead-title">seijaku</a>
477<p class="masthead-subtitle"><i>stillness amidst the chaos</i></p>
478<nav aria-label="Site Navigation">
479<ul>
480<li><a href="/blog/">Blog</a></li>
481<li><a href="/guides/index.html">Guides</a></li>
482<li><a href="/apps/">Apps</a></li>
483<li><a href="/garden/">Garden</a></li>
484<li><a href="/salary/">Salary</a></li>
485</ul>
486</nav>
487</header>
488<main id="main-content">
489<h1>Tags</h1>
490<ul class="tag-toc">{toc_items}</ul>
491{"".join(f"<section>{s}</section>" for s in sections)}
492</main>
493<hr>
494<footer>
495<div>
496<a href="https://github.com/ccleberg/cleberg.net">Source</a> &middot;
497<a href="/feed.xml">RSS</a> &middot;
498<a href="http://paske4urhs6nttrtlkuwa5cowum3fjkc6yv6kl4ncx3mjxcd77764nqd.onion/">Onion</a> &middot;
499<a href="/now/">Now</a> &middot;
500<a href="/uses/">Uses</a> &middot;
501<a href="/tips/">Tips</a> &middot;
502<a href="https://cv.cleberg.net">CV</a>
503</div>
504<div>
505<a href="mailto:hello@cleberg.net">hello@cleberg.net</a> [<a href="/gpg.txt">PGP</a>] &middot;
506Signal: @cmc.01
507</div>
508</footer>
509</body>
510</html>"""
511
512 out_dir = Path(build_dir) / "tags"
513 out_dir.mkdir(parents=True, exist_ok=True)
514 out_path = out_dir / "index.html"
515 out_path.write_text(html, encoding="utf-8")
516 print(f"Tags page written to {out_path}")
517
518
384519def deploy_to_server(build_dir, server):
385520 remote_path = f"{server}:/var/www/cleberg.net/"
386521 print(f"Deploying .build/ → {remote_path}")
@@ -430,6 +565,7 @@ def main():
430565 copy_org_sources()
431566 update_index_html(html_snippet)
432567 inject_blog_year_separators()
568 generate_tags_page()
433569 minify_html("./.build/index.html", "./.build/index.html")
434570 generate_sitemap()
435571 if deploy:
@@ -445,6 +581,7 @@ def main():
445581 copy_org_sources()
446582 update_index_html(html_snippet)
447583 inject_blog_year_separators()
584 generate_tags_page()
448585 minify_html("./.build/index.html", "./.build/index.html")
449586 generate_sitemap()
450587 if deploy:
content/blog/2018-11-28-aes-encryption.org +1
@@ -2,6 +2,7 @@
22#+title: How AES Encryption Works
33#+description: Detailed explanation of AES encryption, including key handling, encryption modes, algorithm structure, and implementation considerations for secure data protection.
44#+slug: aes-encryption
5#+filetags: :security:
56
67* Basic AES
78
content/blog/2018-11-28-cpp-compiler.org +1
@@ -2,6 +2,7 @@
22#+title: Inside the C++ Compiler
33#+description: Systematic presentation of the C++ compilation phases including preprocessing, compilation, assembly, and linking, with technical insights into each stage's function.
44#+slug: cpp-compiler
5#+filetags: :linux:
56
67* A Brief Introduction
78
content/blog/2019-01-07-useful-css.org +1
@@ -2,6 +2,7 @@
22#+title: Real‑World CSS Techniques: Flexbox, Shadows, and Variables
33#+description: Practical guide on applying CSS rules and constructs such as flexbox, box shadows, and variable usage to achieve standard web styling and layout objectives.
44#+slug: useful-css
5#+filetags: :web:
56
67* Introduction to CSS
78
content/blog/2019-09-09-audit-analytics.org +1
@@ -2,6 +2,7 @@
22#+title: Bringing Data Analytics Into Internal Audit
33#+description: Examination of data analytical approaches applied within internal audit functions to improve risk evaluation, process efficiency, and decision support.
44#+slug: audit-analytics
5#+filetags: :audit:
56
67* What Are Data Analytics?
78
content/blog/2019-12-03-the-ansoff-matrix.org +1
@@ -2,6 +2,7 @@
22#+title: How the Ansoff Matrix Guides Business Growth
33#+description: Analytical description of the Ansoff Matrix, detailing market and product development strategies for measured business expansion and competitive positioning.
44#+slug: the-ansoff-matrix
5#+filetags: :audit:
56
67* Overview
78
content/blog/2019-12-16-password-security.org +1
@@ -2,6 +2,7 @@
22#+title: How to Secure Passwords: Best Practices and NIST Guidelines
33#+description: Compilation of guidelines for password generation, storage, protection, and compliance with established standards such as NIST for maintaining digital security.
44#+slug: password-security
5#+filetags: :security:
56
67* Users
78
content/blog/2020-01-25-linux-software.org +1
@@ -2,6 +2,7 @@
22#+title: Linux Essentials: Top Tools and Easy Setup Tips
33#+description: Inventory and description of key Linux applications including graphical and command-line tools, with installation instructions for various distributions.
44#+slug: linux-software
5#+filetags: :linux:
56
67* Graphical Applications
78
content/blog/2020-01-26-steam-on-ntfs.org +1
@@ -2,6 +2,7 @@
22#+title: How to Get Steam Running Smoothly on NTFS Drives in Linux
33#+description: Procedures for mounting NTFS drives using ntfs-3g to enable reliable execution of Steam gaming software on Linux environments.
44#+slug: steam-on-ntfs
5#+filetags: :linux:
56
67* Auto-Mount Steam Drives
78
content/blog/2020-02-09-cryptography-basics.org +1
@@ -2,6 +2,7 @@
22#+title: A Practical Guide to Encryption, Keys, and Secure Communication
33#+description: Systematic overview of encryption methodologies, key categories, algorithmic frameworks, and their applications in data confidentiality and integrity.
44#+slug: cryptography
5#+filetags: :security:
56
67* Similar Article Available
78
content/blog/2020-03-25-session-messenger.org +1
@@ -2,6 +2,7 @@
22#+title: Session Messenger: Is It Secure?
33#+description: Technical description of the Session messaging protocol, including end-to-end encryption, metadata minimization, multi-device synchronization, and privacy-centric design.
44#+slug: session-messenger
5#+filetags: :privacy:
56
67* Privacy Warning
78
content/blog/2020-05-03-homelab.org +1
@@ -2,6 +2,7 @@
22#+title: My Homelab Setup: Gear, Network, and Lessons Learned
33#+description: Comprehensive instructions on assembling and configuring a homelab environment, emphasizing hardware selection, software deployment, and network setup for operational efficiency.
44#+slug: homelab
5#+filetags: :self-hosting:
56
67* What is a Homelab?
78
content/blog/2020-05-19-customizing-ubuntu.org +1
@@ -2,6 +2,7 @@
22#+title: Tweak Your Ubuntu Look: A Beginner’s Guide to GNOME Customization
33#+description: Detailed instructions for modifying system appearance and interface elements in Ubuntu 20.04, including setting themes, icon packs, font adjustments, terminal configurations, and related customization parameters.
44#+slug: customizing-ubuntu
5#+filetags: :linux:
56
67* More Information
78
content/blog/2020-07-20-video-game-sales.org +1
@@ -2,6 +2,7 @@
22#+title: A Data-Driven Look at Video Game Sales (1980–2020)
33#+description: Presentation of analyzed data regarding global video game sales, covering platform distributions, genre classifications, and geographic market performance metrics.
44#+slug: video-game-sales
5#+filetags: :personal:
56
67* Background Information
78
content/blog/2020-07-26-business-analysis.org +1
@@ -2,6 +2,7 @@
22#+title: A Location Intelligence Framework: Mapping Urban Business Clusters with Python
33#+description: Methodology for utilizing data science techniques and Foursquare API data to analyze and select promising business sites within urban environments.
44#+slug: business-analysis
5#+filetags: :audit:
56
67* Background Information
78
content/blog/2020-08-22-redirect-github-pages.org +1
@@ -2,6 +2,7 @@
22#+title: Configure GitHub Pages to Use Your Root Domain Instead of WWW
33#+description: Stepwise instructions for configuring redirection of GitHub Pages sites from the www subdomain to the apex domain to improve domain resolution and access consistency.
44#+slug: redirect-github-pages
5#+filetags: :web:
56
67* Short answer
78
content/blog/2020-08-29-php-auth-flow.org +1
@@ -2,6 +2,7 @@
22#+title: PHP User Authentication: Create, Validate, and Manage Sessions
33#+description: Comprehensive guide to developing a secure user login system in PHP, including account creation, session management, and logout procedures.
44#+slug: php-auth-flow
5#+filetags: :web:
56
67* Introduction
78
content/blog/2020-09-01-visual-recognition.org +1
@@ -2,6 +2,7 @@
22#+title: How to Use IBM Watson Visual Recognition API for Image Analysis
33#+description: Technical overview and application instructions for using IBM Watson Visual Recognition service, with focus on API configuration, image input processing, and classification output handling.
44#+slug: visual-recognition
5#+filetags: :linux:
56
67* What is IBM Watson?
78
content/blog/2020-09-22-internal-audit.org +1
@@ -2,6 +2,7 @@
22#+title: The Strategic Role of Internal Audit in Risk, Governance, and Compliance
33#+description: Analysis of internal audit processes, their contribution to risk management, governance frameworks, and compliance monitoring within corporate structures.
44#+slug: internal-audit
5#+filetags: :audit:
56
67* Definitions
78
content/blog/2020-09-25-happiness-map.org +1
@@ -2,6 +2,7 @@
22#+title: Visualizing Global Happiness: A Choropleth Map with Python and Folium
33#+description: Instructions for creating an interactive choropleth map visualizing international happiness data based on metrics such as GDP, social support, health indicators, freedom indices, generosity, and corruption levels.
44#+slug: happiness-map
5#+filetags: :personal:
56
67* Background Information
78
content/blog/2020-10-12-mediocrity.org +1
@@ -2,6 +2,7 @@
22#+title: When Good Is Good Enough—And When It Isn't
33#+description: Examination of decision-making principles relating to achieving sufficient quality levels, including trade-offs between perfection and adequacy in professional and operational contexts.
44#+slug: mediocrity
5#+filetags: :personal:
56
67* Perfect is the Enemy of Good
78
content/blog/2020-12-27-website-redesign.org +1
@@ -2,6 +2,7 @@
22#+title: Designing for Speed: A 5KB Site That Scores 100s on Lighthouse
33#+description: Detailed process outlining methods for reducing website page size to approximately 5 kilobytes, enhancing loading speed, search engine indexing efficiency, and user interface responsiveness.
44#+slug: website-redesign
5#+filetags: :web:
56
67* A Brief History
78
content/blog/2020-12-28-neon-drive.org +1
@@ -2,6 +2,7 @@
22#+title: Outrun the Future: A Review of Neon Drive's Gameplay and Style
33#+description: Description of game mechanics, graphical style, and level design in Neon Drive, an arcade racing game inspired by 1980s synthwave aesthetics.
44#+slug: neon-drive
5#+filetags: :personal:
56
67* Game Description
78
content/blog/2020-12-29-zork.org +1
@@ -2,6 +2,7 @@
22#+title: Your First Grue: Getting Started with Zork, the Iconic Text Adventure
33#+description: Detailed operational guide for navigating Zork, a text-based interactive fiction game from the 1980s. Includes instructions for exploration, puzzle resolution, and item collection.
44#+slug: zork
5#+filetags: :personal:
56
67* Download (Free)
78
content/blog/2021-01-01-seum.org +1
@@ -2,6 +2,7 @@
22#+title: SEUM: Speedrunners from Hell
33#+description: Technical overview for utilizing the game SEUM, focusing on speedrunning techniques, gravity manipulation, teleportation functions, and level completion criteria.
44#+slug: seum
5#+filetags: :personal:
56
67* Game Description
78
content/blog/2021-01-04-fediverse.org +1
@@ -2,6 +2,7 @@
22#+title: Navigating the Fediverse: User Manual for Decentralized Social Media
33#+description: Detailed introduction to the Fediverse network architecture, user registration procedures, platform navigation, and protocols ensuring content decentralization and censorship resistance.
44#+slug: fediverse
5#+filetags: :privacy:
56
67* What is the Fediverse?
78
content/blog/2021-01-07-ufw.org +1
@@ -2,6 +2,7 @@
22#+title: Hardening Ubuntu Servers with UFW: A Step-by-Step Firewall Guide
33#+description: Stepwise instructions for installation, configuration, enabling, and management of the Uncomplicated Firewall utility to secure network interfaces on Ubuntu server environments.
44#+slug: ufw
5#+filetags: :linux:security:
56
67* Uncomplicated Firewall
78
content/blog/2021-02-19-macos.org +1
@@ -2,6 +2,7 @@
22#+title: macOS for Linux Users: Initial Setup and CLI Customization
33#+description: Comprehensive overview for first-time macOS users transitioning from other OS platforms, including system setup, terminal usage, and user interface customization.
44#+slug: macos
5#+filetags: :linux:
56
67* Diving into macOS
78
content/blog/2021-03-19-clone-github-repos.org +1
@@ -2,6 +2,7 @@
22#+title: GitHub and Sourcehut: Scripting Mass Clones and Remote Updates
33#+description: Script-based methodology for cloning multiple repositories from GitHub and Sourcehut accounts. Includes automation techniques to streamline repository management and backups.
44#+slug: clone-github-repos
5#+filetags: :personal:
56
67* Cloning from GitHub
78
content/blog/2021-03-28-gemini-capsule.org +1
@@ -2,6 +2,7 @@
22#+title: Getting Started with Gemini: Deploy Your First Capsule
33#+description: Incremental procedural guide to initiate and maintain a Gemini capsule server. Covers installation, deployment, and operational best practices for beginners.
44#+slug: gemini-capsule
5#+filetags: :linux:web:
56
67* What is Gemini?
78
content/blog/2021-03-28-vaporwave-vs-outrun.org +1
@@ -2,6 +2,7 @@
22#+title: Exploring Vaporwave and Outrun: Color, Culture, and Sound
33#+description: Systematic examination of Vaporwave and Outrun aesthetic frameworks, focusing on graphical elements, chromatic schemes, musical associations, and period-specific cultural influences.
44#+slug: vaporwave-vs-outrun
5#+filetags: :personal:
56
67* Overview
78
content/blog/2021-03-30-vps-web-server.org +1
@@ -2,6 +2,7 @@
22#+title: From Shared Hosting to VPS: Web Server Setup Made Easy
33#+description: Instructional outline for setting up and maintaining a VPS environment configured for secure and scalable web hosting applications.
44#+slug: vps-web-server
5#+filetags: :linux:self-hosting:
56
67* Shared Hosting vs. VPS (Virtual Private Server)
78
content/blog/2021-04-17-gemini-server.org +1
@@ -2,6 +2,7 @@
22#+title: Agate Gemini Server Installation and Firewall Configuration
33#+description: Detailed directives for installation and configuration of a Gemini protocol server on Ubuntu, including network security and firewall setup.
44#+slug: gemini-server
5#+filetags: :linux:web:
56
67* Similar Article Available
78
content/blog/2021-04-23-php-comment-system.org +1
@@ -2,6 +2,7 @@
22#+title: Building a Lightweight PHP Static Commenting System Without JavaScript
33#+description: Technical walkthrough for constructing a lightweight, privacy-oriented static comment system using PHP, with no client-side scripting or external dependencies.
44#+slug: php-comment-system
5#+filetags: :linux:web:
56
67* The Terrible-ness of Commenting Systems
78
content/blog/2021-04-28-photography.org +1
@@ -2,6 +2,7 @@
22#+title: Getting Started with Photography: Gear and Best Practices
33#+description: Instructional document covering basic techniques in photography, including equipment selection, operational best practices, and methods for capturing high-quality images.
44#+slug: photography
5#+filetags: :personal:
56
67* Why Photography?
78
content/blog/2021-05-30-changing-git-authors.org +1
@@ -2,6 +2,7 @@
22#+title: Automated Script for Correcting Git Author Details in Multiple Projects
33#+description: Detailed instructions for systematically updating the Git author name and email information in multiple repositories using command-line tools and scripts.
44#+slug: changing-git-authors
5#+filetags: :personal:
56
67* Changing Git Author/Email Based on Previously Committed Email
78
content/blog/2021-07-15-delete-gitlab-repos.org +1
@@ -2,6 +2,7 @@
22#+title: Automated Deletion of All GitLab Repositories Using Python
33#+description: Stepwise instructions for executing a Python script to delete all repositories associated with a GitLab account. Includes authentication and error handling procedures.
44#+slug: delete-gitlab-repos
5#+filetags: :personal:
56
67* Background
78
content/blog/2021-08-25-audit-sampling.org +1
@@ -2,6 +2,7 @@
22#+title: Audit Sampling Made Easy: Using Pandas for Random and Stratified Samples
33#+description: Presentation of methods for implementing audit sampling techniques including simple random, stratified, and systematic sampling using Python's Pandas library for precise audit outcomes.
44#+slug: audit-sampling
5#+filetags: :audit:
56
67* Introduction
78
content/blog/2021-10-09-apache-redirect.org +1
@@ -2,6 +2,7 @@
22#+title: Setting Up Apache Rewrite Rules for Extensionless URLs
33#+description: Technical guide to applying Apache mod_rewrite directives for transforming .html file requests into clean directory-style URL structures to enhance website navigation and indexing.
44#+slug: apache-redirect
5#+filetags: :web:
56
67* The Problem
78
content/blog/2021-12-04-cisa.org +1
@@ -2,6 +2,7 @@
22#+title: How I Prepared for and Passed the CISA Exam: A Practical Study Guide
33#+description: Comprehensive outline of study materials, preparation strategies, and procedural advice for passing the CISA examination on the initial attempt.
44#+slug: cisa
5#+filetags: :audit:
56
67* What is the CISA?
78
content/blog/2022-02-10-leaving-the-office.org +1
@@ -2,6 +2,7 @@
22#+title: From Cubicles to Home Offices: My Journey Through Changing Workspaces
33#+description: Examination of factors influencing the shift from traditional office environments to remote work, including benefits, constraints, and implementation recommendations.
44#+slug: leaving-the-office
5#+filetags: :personal:
56
67* The Working World is Changing
78
content/blog/2022-02-10-njalla-dns-api.org +1
@@ -2,6 +2,7 @@
22#+title: Automating Dynamic DNS Record Updates via Njalla API Using Python
33#+description: Instructional material detailing automation of DNS record updates by interfacing with Njalla's API, suitable for environments with frequently changing IP addresses.
44#+slug: njalla-dns-api
5#+filetags: :security:
56
67* Njalla's API
78
content/blog/2022-02-16-debian-and-nginx.org +1
@@ -2,6 +2,7 @@
22#+title: Switching to Debian and Nginx: A Modern Web and Gemini Server Migration Walkthrough
33#+description: Step-by-step protocol for transitioning web server infrastructure to Debian operating system, including installation, configuration, and security hardening of Nginx and Agate services.
44#+slug: debian-and-nginx
5#+filetags: :linux:web:
56
67* Server Operating System (OS): Debian
78
content/blog/2022-02-17-exiftool.org +1
@@ -2,6 +2,7 @@
22#+title: Protect Your Privacy: Automating Image Metadata Removal Using Exiftool
33#+description: Technical instructions for utilizing Exiftool to systematically strip metadata from image files to ensure privacy and reduce file size.
44#+slug: exiftool
5#+filetags: :linux:privacy:
56
67** Why Strip Metadata?
78
content/blog/2022-02-20-nginx-caching.org +1
@@ -2,6 +2,7 @@
22#+title: How to Configure Nginx for Efficient Static Content Caching
33#+description: Detailed methods for configuring Nginx to cache static resources such as CSS, JavaScript, and images to improve website loading times and resource efficiency.
44#+slug: nginx-caching
5#+filetags: :linux:web:
56
67* Update Your Nginx Config to Cache Static Files
78
content/blog/2022-02-22-tuesday.org +1
@@ -2,6 +2,7 @@
22#+title: Twosday: Exploring the Unique Palindromic Date of 2-22-22
33#+description: Examination of the date Tuesday, February 22, 2022, highlighting the palindromic properties and expected observations on this specific calendar occurrence.
44#+slug: tuesday
5#+filetags: :personal:
56
67* Tuesday, Twosday
78
content/blog/2022-03-02-reliable-notes.org +1
@@ -2,6 +2,7 @@
22#+title: Reliable Note-Taking with Markdown: Methods for Efficient and Portable Notes
33#+description: Instructions on applying standardized note-taking procedures with Markdown format, including synchronization and cross-platform compatibility considerations.
44#+slug: reliable-notes
5#+filetags: :personal:
56
67* Choosing Durable File Formats
78
content/blog/2022-03-03-financial-database.org +1
@@ -2,6 +2,7 @@
22#+title: From Spreadsheets to Databases: Creating a Custom Financial Tracker with Python
33#+description: Procedures for creating and maintaining a personal financial database utilizing SQLite, Python programming language, and Jupyter Notebook interface.
44#+slug: financial-database
5#+filetags: :self-hosting:
56
67* Personal Financial Tracking
78
content/blog/2022-03-08-plex-migration.org +1
@@ -2,6 +2,7 @@
22#+title: Migrating Plex Media Server to New Hardware with Nvidia GPU Setup
33#+description: Stepwise instructions for transferring Plex Media Server to new hardware and enabling Nvidia GPU transcoding to optimize media processing performance.
44#+slug: plex-migration
5#+filetags: :self-hosting:
56
67* Migration Phases
78
content/blog/2022-03-23-cloudflare-dns-api.org +1
@@ -2,6 +2,7 @@
22#+title: Dynamic DNS Record Updates via Cloudflare API
33#+description: Command-line procedures to automate updating of DNS A and AAAA records by interfacing with the Cloudflare API, suitable for environments with variable IP addresses.
44#+slug: cloudflare-dns-api
5#+filetags: :security:
56
67* DDNS: Dynamic DNS
78:PROPERTIES:
content/blog/2022-03-23-nextcloud-on-ubuntu.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Nextcloud
33#+description: Comprehensive guide for implementing Nextcloud as a self-hosted solution on an Ubuntu server, including installation steps, configuration parameters, and basic security measures.
44#+slug: nextcloud-on-ubuntu
5#+filetags: :linux:self-hosting:
56
67* What is Nextcloud?
78:PROPERTIES:
content/blog/2022-03-24-server-hardening.org +1
@@ -2,6 +2,7 @@
22#+title: Step-by-Step Guide to Securing Your Home Server with Firewalls, SSH, and VLANs
33#+description: Detailed instructions to enhance the security posture of home servers exposed to public networks, including firewall setup, secure SSH configuration, fail2ban deployment, and network segmentation.
44#+slug: server-hardening
5#+filetags: :linux:security:
56
67* Planning Data Flows & Security
78
content/blog/2022-03-26-ssh-mfa.org +1
@@ -2,6 +2,7 @@
22#+title: Secure Your SSH Access: Deploying Time-Based One-Time Password Authentication
33#+description: Step-by-step deployment guide for enabling TOTP multi-factor authentication on SSH services using Google Authenticator and Pluggable Authentication Module (PAM) integration.
44#+slug: ssh-mfa
5#+filetags: :security:
56
67* Why Do I Need Multi-Factor Authentication (MFA) for SSH (Secure Shell Protocol)?
78
content/blog/2022-04-02-nginx-reverse-proxy.org +1
@@ -2,6 +2,7 @@
22#+title: How to Configure Nginx as a Reverse Proxy on Ubuntu Server
33#+description: Technical guide for setting up Nginx server to operate as a reverse proxy on Ubuntu systems, including configuration files setup and operational parameters.
44#+slug: nginx-reverse-proxy
5#+filetags: :linux:web:
56
67* What is a Reverse Proxy?
78
content/blog/2022-04-09-pinetime.org +1
@@ -2,6 +2,7 @@
22#+title: PineTime Smartwatch: An Open-Source Hardware & Software Overview
33#+description: Technical description of PineTime smartwatch capabilities, including heart rate measurement, step counting, sleep monitoring, and smartphone connectivity functions.
44#+slug: pinetime
5#+filetags: :linux:
56
67* PineTime Product Information
78
content/blog/2022-06-01-ditching-cloudflare.org +1
@@ -2,6 +2,7 @@
22#+title: Migrating from Cloudflare to Njalla: A Privacy-Focused DNS and Domain Management Transition
33#+description: Evaluation and procedural explanation for migrating DNS management services from Cloudflare to Njalla, with emphasis on privacy controls and domain registration mechanics.
44#+slug: ditching-cloudflare
5#+filetags: :privacy:security:
56
67* Registrar
78
content/blog/2022-06-07-self-hosting-freshrss.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: FreshRSS
33#+description: Stepwise instructions for installing FreshRSS using Docker and configuring Nginx as a reverse proxy to enable secure and synchronized RSS feed access.
44#+slug: self-hosting-freshrss
5#+filetags: :linux:self-hosting:
56
67* Why Use Really Simple Syndication (RSS)?
78
content/blog/2022-06-16-terminal-lifestyle.org +1
@@ -2,6 +2,7 @@
22#+title: Living the Terminal Lifestyle: Efficient Workflows for Focused Computing
33#+description: Detailed procedures for reducing digital interruptions and increasing efficiency through terminal-based utilities for web browsing, communication, electronic mail, RSS feeds, and programming tasks.
44#+slug: terminal-lifestyle
5#+filetags: :linux:
56
67* Text-Based Simplicity
78
content/blog/2022-06-22-daily-poetry.org +1
@@ -2,6 +2,7 @@
22#+title: How to Receive a Daily Dose of Poetry via Automated Email
33#+description: Instructional guide for scheduling and automating the distribution of classic and contemporary poetry in plaintext format to an electronic mail inbox using Python scripting and SMTP protocol.
44#+slug: daily-poetry
5#+filetags: :personal:
56
67* Source Code
78
content/blog/2022-06-24-fedora-i3.org +1
@@ -2,6 +2,7 @@
22#+title: My Journey Back to Linux: Setting Up Fedora with i3 Window Manager
33#+description: Examination of the transition from macOS to Linux, including a detailed description of Fedora operating system installation and i3 window manager configuration.
44#+slug: fedora-i3
5#+filetags: :linux:
56
67* Leaving macOS
78
content/blog/2022-07-01-git-server.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Git & cGit
33#+description: Comprehensive instructions for secure and efficient setup, hosting, and management of personal Git repositories to facilitate collaborative development and remote access.
44#+slug: git-server
5#+filetags: :linux:self-hosting:
56
67* My Approach to Self-Hosting Git
78
content/blog/2022-07-14-gnupg.org +1
@@ -2,6 +2,7 @@
22#+title: Getting Started with GPG: Secure Encryption, Signing, and Key Usage
33#+description: Technical manual covering the architecture, cryptographic algorithms, vulnerability considerations, key management, and typical applications of GNU Privacy Guard for secure data and email encryption.
44#+slug: gnupg
5#+filetags: :linux:security:
56
67* The History of GPG
78
content/blog/2022-07-25-curseradio.org +1
@@ -2,6 +2,7 @@
22#+title: Curseradio: A Lightweight Command-Line Internet Radio Player for Linux
33#+description: Stepwise instructions for installing and utilizing Curseradio, a lightweight command-line program for streaming radio stations within Linux environments.
44#+slug: curseradio
5#+filetags: :linux:
56
67* Overview
78
content/blog/2022-07-30-flac-to-opus.org +1
@@ -2,6 +2,7 @@
22#+title: Automating Recursive FLAC to Opus Conversion with a Bash Script
33#+description: Instructions for automating the conversion of audio files from FLAC to Opus format recursively within directory structures, including performance considerations and script usage.
44#+slug: flac-to-opus
5#+filetags: :linux:
56
67* Converting FLAC to OPUS
78
content/blog/2022-07-31-bash-it.org +1
@@ -2,6 +2,7 @@
22#+title: Boosting Bash Productivity: Using Bash-it and ble.sh for Plugins and Autosuggestions
33#+description: Guide to augmenting Bash shell features by integrating Bash-It framework along with ble.sh for input autosuggestions, improving command-line efficiency on Linux systems.
44#+slug: bash-it
5#+filetags: :linux:
56
67* Bash
78
content/blog/2022-08-31-privacy-com-changes.org +1
@@ -2,6 +2,7 @@
22#+title: Privacy.com Shifts From Prepaid Debit to Charge Card: What Users Need to Know
33#+description: Detailed examination of modifications to Privacy.com service terms and their implications on user privacy and payment security protocols.
44#+slug: privacy-com-changes
5#+filetags: :privacy:
56
67* Privacy.com Changes Their Terms
78
content/blog/2022-09-17-serenity-os.org +1
@@ -2,6 +2,7 @@
22#+title: Building and Exploring SerenityOS: A Retro-Inspired Unix-Like Desktop
33#+description: Technical overview of Serenity OS including system architecture, building procedures, and operational instructions for this Unix-like operating system with a 1990s user interface style.
44#+slug: serenity-os
5#+filetags: :linux:
56
67* Overview
78
content/blog/2022-09-21-graphene-os.org +1
@@ -2,6 +2,7 @@
22#+title: Installing GrapheneOS on Pixel 6 Pro
33#+description: Step-by-step instructions to perform secure installation of the GrapheneOS operating system on Google Pixel 6 Pro hardware platform.
44#+slug: graphene-os
5#+filetags: :linux:privacy:
56
67* Introduction
78
content/blog/2022-10-04-mtp-linux.org +1
@@ -2,6 +2,7 @@
22#+title: How to Mount MTP Mobile Devices on Fedora Linux Using jmtpfs
33#+description: Instructions for mounting and accessing Media Transfer Protocol (MTP) compatible mobile devices on Fedora Linux using jmtpfs for file transfer and management.
44#+slug: mtp-linux
5#+filetags: :linux:
56
67I recently ran into trouble attempting to mount my GrapheneOS phone to my laptop
78running Fedora Linux via the [[https://en.wikipedia.org/wiki/Media_transfer_protocol][Media Transfer Protocol]] (MTP) and discovered a
content/blog/2022-10-04-syncthing.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Syncthing
33#+description: Technical instructions for setting up Syncthing as a peer-to-peer self-hosted file synchronization system that preserves data privacy by eliminating third-party intermediaries.
44#+slug: syncthing
5#+filetags: :linux:self-hosting:
56
67* An Overview of Syncthing
78
content/blog/2022-10-22-alpine-linux.org +1
@@ -2,6 +2,7 @@
22#+title: Alpine Linux Essentials: Installing and Setting Up a Secure Minimal Server
33#+description: Detailed procedure for deploying Alpine Linux to achieve a secure, lightweight server environment optimized for web hosting and containerization.
44#+slug: alpine-linux
5#+filetags: :linux:
56
67* Alpine Linux
78
content/blog/2022-10-30-linux-display-manager.org +1
@@ -2,6 +2,7 @@
22#+title: Managing Display Managers in Void Linux: Disable, Enable, and Configure
33#+description: Stepwise instructions to manage and replace the display manager on a Void Linux installation, including service control and configuration editing.
44#+slug: linux-display-manager
5#+filetags: :linux:
56
67* Display Manager Services
78
content/blog/2022-11-07-self-hosting-matrix.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Matrix Synapse
33#+description: Systematic guide for deploying Matrix Synapse on Alpine Linux, covering dependency installation, reverse proxy setup, TLS certificate application, and user account management.
44#+slug: self-hosting-matrix
5#+filetags: :linux:self-hosting:
56
67* Synapse
78
content/blog/2022-11-11-nginx-tmp-errors.org +1
@@ -2,6 +2,7 @@
22#+title: Troubleshooting and Fixing Nginx Permission Denied Errors on /var/lib/nginx
33#+description: Step-by-step remediation for addressing permission denied errors encountered by Nginx in the /var/lib/nginx directory to restore temporary file caching functionality.
44#+slug: nginx-tmp-errors
5#+filetags: :web:
56
67/This is a brief post so that I personally remember the solution as it
78has occurred multiple times for me./
content/blog/2022-11-27-server-build.org +1
@@ -2,6 +2,7 @@
22#+title: Building a High-Performance Rack-Mounted Server with Consumer PC Components
33#+description: Detailed instructions on selecting components, assembling, and configuring a rack-mounted server suitable for advanced computing tasks in a professional or laboratory setting.
44#+slug: server-build
5#+filetags: :linux:
56
67* The Dilemma
78
content/blog/2022-11-29-nginx-referrer-ban-list.org +1
@@ -2,6 +2,7 @@
22#+title: How to Block Unwanted HTTP Referrers in Nginx Using a Ban List
33#+description: Technical guide to implementing a referrer ban list in Nginx configurations to prevent access from undesired domains and improve web server security.
44#+slug: nginx-referrer-ban-list
5#+filetags: :linux:web:
56
67* Creating the Ban List
78
content/blog/2022-12-01-nginx-compression.org +1
@@ -2,6 +2,7 @@
22#+title: Optimizing Nginx with GZIP: A Step-by-Step Guide to Text Compression
33#+description: Procedures for activating and configuring GZIP compression in Nginx to decrease data transmission size, reduce bandwidth consumption, and accelerate page load times.
44#+slug: nginx-compression
5#+filetags: :linux:web:
56
67* Text Compression
78
content/blog/2022-12-07-nginx-wildcard-redirect.org +1
@@ -2,6 +2,7 @@
22#+title: Nginx Wildcard Redirects: Seamlessly Redirecting Domains and Subdomains with Trailing Paths
33#+description: Instructional steps for applying regex-based redirects in Nginx to manage subdomain routing and trailing path modifications effectively.
44#+slug: nginx-wildcard-redirect
5#+filetags: :web:
56
67* Problem
78
content/blog/2022-12-17-st.org +1
@@ -2,6 +2,7 @@
22#+title: Installing and Customizing the suckless Simple Terminal (st) on Fedora Linux
33#+description: Comprehensive instructions to obtain source code, compile, apply patches, and install the Simple Terminal application on Fedora Linux systems.
44#+slug: st
5#+filetags: :linux:
56
67* st
78
content/blog/2022-12-23-alpine-desktop.org +1
@@ -2,6 +2,7 @@
22#+title: How to Set Up Alpine Linux as a Desktop OS with Sway
33#+description: Stepwise procedures for installing and setting up Alpine Linux as a desktop operating system, including window manager setup and relevant system adjustments.
44#+slug: alpine-desktop
5#+filetags: :linux:
56
67* Isn't Alpine Linux for Servers?
78
content/blog/2023-01-03-recent-website-changes.org +1
@@ -2,6 +2,7 @@
22#+title: 2023 Website Updates: Minimalist Style, Accessibility Improvements, and Content Prioritization
33#+description: Documentation of significant changes applied to site design, layout, and accessibility features to enhance navigability and content clarity.
44#+slug: recent-website-changes
5#+filetags: :personal:web:
56
67* The State of This Website
78
content/blog/2023-01-05-mass-unlike-tumblr-posts.org +1
@@ -2,6 +2,7 @@
22#+title: How to Quickly Remove All Likes on Tumblr Desktop
33#+description: Instructions for executing a JavaScript script to automate the mass unlike operation for Tumblr posts without requiring additional software.
44#+slug: mass-unlike-tumblr-posts
5#+filetags: :linux:personal:
56
67* The Dilemma
78
content/blog/2023-01-08-fedora-login-manager.org +1
@@ -2,6 +2,7 @@
22#+title: How to Remove Fedora i3's Login Manager and Start i3 Manually
33#+description: Step-by-step guide for uninstalling the default Fedora i3 login manager and configuring system to launch i3 window manager manually.
44#+slug: fedora-login-manager
5#+filetags: :linux:
56
67* Fedora i3's Login Manager
78
content/blog/2023-01-21-flatpak-symlinks.org +1
@@ -2,6 +2,7 @@
22#+title: Simplify Flatpak Commands: Making Symlinks for Easier App Launching
33#+description: Detailed instructions for establishing symbolic links for Flatpak applications to facilitate faster execution from terminal or application launcher environments.
44#+slug: flatpak-symlinks
5#+filetags: :linux:
56
67* Running Flatpak Apps Should Be Faster
78
content/blog/2023-01-23-random-wireguard.org +1
@@ -2,6 +2,7 @@
22#+title: Automate Random Mullvad Wireguard VPN Connection on Startup
33#+description: Stepwise method to configure system startup scripts for automatic connection to a randomly chosen Mullvad Wireguard VPN server to maintain privacy.
44#+slug: random-wireguard
5#+filetags: :linux:security:self-hosting:
56
67* Mullvad Wireguard
78
content/blog/2023-01-28-self-hosting-wger.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Wger
33#+description: Comprehensive steps for installing, configuring, and operating the Wger workout management application on a dedicated server platform.
44#+slug: self-hosting-wger
5#+filetags: :linux:self-hosting:
56
67* Wger: The Self-Hosted Workout Manager
78
content/blog/2023-02-02-exploring-hare.org +1
@@ -2,6 +2,7 @@
22#+title: Getting Started with the Hare Language
33#+description: Overview of the Hare programming language features, installation procedure, and elementary programming examples targeting system-level development.
44#+slug: exploring-hare
5#+filetags: :linux:
56
67* A Quick Note
78
content/blog/2023-05-22-burnout.org +1
@@ -2,6 +2,7 @@
22#+title: Navigating Burnout in Audit and Consulting: A Season Without Rest
33#+description: Examination of burnout phenomena accompanied by strategies and practical approaches for workload management and restoration of optimal functioning.
44#+slug: burnout
5#+filetags: :personal:
56
67* RE: Burnout
78
content/blog/2023-06-08-goaccess-geoip.org +1
@@ -2,6 +2,7 @@
22#+title: Real-Time Traffic Insights from Nginx Logs Using GoAccess + GeoIP
33#+description: Step-by-step instructions to utilize GoAccess tool incorporating MaxMind GeoIP integration for real-time geographic and traffic analysis of Nginx log files.
44#+slug: goaccess-geoip
5#+filetags: :self-hosting:web:
56
67* Overview
78
content/blog/2023-06-08-self-hosting-baikal.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Baikal
33#+description: Detailed procedure for deploying the Baikal server software to provide CalDAV and CardDAV services, including security considerations and Docker deployment.
44#+slug: self-hosting-baikal
5#+filetags: :linux:self-hosting:
56
67* What is Baikal?
78
content/blog/2023-06-18-unifi-ip-blocklist.org +1
@@ -2,6 +2,7 @@
22#+title: Blocking Malicious IPs on Unifi: Manual Firewall Rule Setup
33#+description: Instructions to identify and block harmful IP addresses and subnets through Unifi firewall settings to improve network security posture.
44#+slug: unifi-ip-blocklist
5#+filetags: :linux:self-hosting:
56
67* Identifying Abusive IPs
78
content/blog/2023-06-20-audit-review-template.org +1
@@ -2,6 +2,7 @@
22#+title: Audit Testing Review Checklist
33#+description: Practical audit testing review template with detailed steps to support comprehensive evaluation of financial audits and SOC reports.
44#+slug: audit-review-template
5#+filetags: :audit:
56
67* Overview
78
content/blog/2023-06-23-byobu.org +1
@@ -2,6 +2,7 @@
22#+title: Using Byobu for Efficient Terminal Multiplexing
33#+description: Detailed overview of Byobu terminal multiplexer features, configuration settings, session management, and keybindings to enhance command-line efficiency.
44#+slug: byobu
5#+filetags: :linux:self-hosting:
56
67* Byobu
78
content/blog/2023-06-23-self-hosting-convos.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Convos
33#+description: Stepwise instructions for installation, Docker Compose configuration, Nginx reverse proxy setup, and IRC nickname registration for Convos web client hosting.
44#+slug: self-hosting-convos
5#+filetags: :linux:self-hosting:
56
67* Convos
78
content/blog/2023-06-28-backblaze-b2.org +1
@@ -2,6 +2,7 @@
22#+title: Automating Secure Backups with Backblaze B2 and b2 CLI
33#+description: Methodical guide for configuring and utilizing Backblaze B2 cloud storage services to perform reliable and secure offsite data backups.
44#+slug: backblaze-b2
5#+filetags: :self-hosting:
56
67* Overview
78
content/blog/2023-06-30-self-hosting-voyager.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Voyager for Lemmy
33#+description: Instructions for building, running, and reverse proxying Voyager, a Lemmy web client, on a server environment utilizing Docker and Nginx components.
44#+slug: self-hosting-voyager
5#+filetags: :linux:self-hosting:
56
67* Installation Guide
78
content/blog/2023-07-12-wireguard-lan.org +1
@@ -2,6 +2,7 @@
22#+title: Enabling Local Network Access with Mullvad WireGuard Configs
33#+description: Detailed procedure to modify Mullvad Wireguard VPN configuration files and iptables rules to allow Local Area Network access while maintaining VPN connectivity.
44#+slug: wireguard-lan
5#+filetags: :security:self-hosting:
56
67* Download Configuration Files from Mullvad
78
content/blog/2023-07-19-plex-transcoder-errors.org +1
@@ -2,6 +2,7 @@
22#+title: Plex Subtitle Error: Transcoder Fails to Start
33#+description: Technical procedures to identify and correct Plex transcoder failures at startup to maintain uninterrupted media conversion and playback.
44#+slug: plex-transcoder-errors
5#+filetags: :linux:self-hosting:
56
67* Plex Transcoder Error
78
content/blog/2023-08-18-agile-auditing.org +1
@@ -2,6 +2,7 @@
22#+title: Agile Auditing Framework: Using Scrum and Kanban in Audit Projects
33#+description: Detailed examination of Agile auditing methodologies, including Scrum and Kanban frameworks, with practical steps for application in audit processes.
44#+slug: agile-auditing
5#+filetags: :audit:
56
67* What is Agile Auditing?
78
content/blog/2023-09-15-self-hosting-gitweb.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: GitWeb
33#+description: Stepwise instructions for deploying GitWeb on Linux servers using Nginx, configuring fastcgi, and managing git repositories effectively.
44#+slug: self-hosting-gitweb
5#+filetags: :linux:self-hosting:
56
67* Overview
78
content/blog/2023-09-19-audit-sql-scripts.org +1
@@ -2,6 +2,7 @@
22#+title: Auditing User Privileges in Oracle, SQL Server, and MySQL
33#+description: Collection of SQL queries designed for auditing user access parameters on Oracle, Microsoft SQL Server, and MySQL database systems.
44#+slug: audit-sql-scripts
5#+filetags: :audit:
56
67* Overview
78
content/blog/2023-10-04-digital-minimalism.org +1
@@ -2,6 +2,7 @@
22#+title: Digital Minimalism: Reducing Distractions
33#+description: Practical guide for minimizing digital clutter and optimizing work focus by applying digital minimalism tactics.
44#+slug: digital-minimalism
5#+filetags: :linux:privacy:
56
67I've written [[https://cleberg.net/wiki/#digital-garden][a note about minimalism]]
78before, but I wanted to dedicate some time to reflect on digital
content/blog/2023-10-11-self-hosting-authelia.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Authelia
33#+description: Instructional guide for setting up Authelia to provide secure two-factor authentication and access control in self-hosted environments.
44#+slug: self-hosting-authelia
5#+filetags: :linux:security:self-hosting:
56
67* Overview
78
content/blog/2023-10-15-alpine-ssh-hardening.org +1
@@ -2,6 +2,7 @@
22#+title: Alpine Linux SSH Hardening Guide
33#+description: Detailed guide to enhance Alpine Linux SSH server security through configuration adjustments and vulnerability mitigation.
44#+slug: alpine-ssh-hardening
5#+filetags: :linux:security:
56
67* Overview
78
content/blog/2023-10-17-self-hosting-anonymousoverflow.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: AnonymousOverflow
33#+description: Detailed installation and setup instructions for the AnonymousOverflow application using Docker Compose and Nginx reverse proxy.
44#+slug: self-hosting-anonymousoverflow
5#+filetags: :linux:self-hosting:
56
67* Overview
78
content/blog/2023-11-08-scli.org +1
@@ -2,6 +2,7 @@
22#+title: Signal CLI (scli) Installation on Alpine
33#+description: Step-by-step instructions for installing the Signal messenger command-line client scli on Alpine Linux with musl libc, including dependencies and configuration.
44#+slug: scli
5#+filetags: :linux:
56
67[[https://github.com/isamert/scli][scli]] is a command-line tool that
78allows you to connect to your Signal messenger account. This program
content/blog/2023-12-03-unifi-nextdns.org +1
@@ -2,6 +2,7 @@
22#+title: Installing and Configuring NextDNS on Unifi Dream Machine Routers
33#+description: Procedural guide for installation and configuration of NextDNS on Unifi Dream Machine devices for network DNS filtering.
44#+slug: unifi-nextdns
5#+filetags: :linux:self-hosting:
56
67* Overview
78
content/blog/2024-01-08-dont-say-hello.org +1
@@ -2,6 +2,7 @@
22#+title: Don't Say Hello
33#+description: Technical recommendations for improving professional communication by eliminating non-essential introductory phrases to enhance message clarity.
44#+slug: dont-say-hello
5#+filetags: :privacy:
56
67I recently came back from a winter break and have started working again... only
78to immediately run into the dilemma of people sending me cliffhanger messages
content/blog/2024-01-09-macos-customization.org +1
@@ -2,6 +2,7 @@
22#+title: A Guide to Customizing macOS with Terminal, Window Managers, and Widgets
33#+description: Detailed overview of methods and tools for modifying macOS system settings, including terminal usage, window management, and interface customization.
44#+slug: macos-customization
5#+filetags: :linux:
56
67I have been using macOS more than Linux lately, so I wrote this post to describe
78some simple options to customize macOS beyond the normal built-in settings menu.
content/blog/2024-01-13-local-llm.org +1
@@ -2,6 +2,7 @@
22#+title: Running Local Large Language Models on macOS and iOS: A Practical Guide
33#+description: Technical guide to deploying and running local large language models on macOS and iOS devices focusing on open-source implementations and privacy considerations.
44#+slug: local-llm
5#+filetags: :linux:privacy:
56
67* Requirements
78
content/blog/2024-01-26-audit-dashboard.org +1
@@ -2,6 +2,7 @@
22#+title: Building an Interactive Audit Dashboard with Alteryx and Power BI
33#+description: Instructions for transforming audit data into dynamic dashboards via data preparation with Alteryx and visualization using Microsoft Power BI.
44#+slug: audit-dashboard
5#+filetags: :audit:
56
67Alteryx and Power BI are powerful tools that can help turn your old-school audit
78trackers into interactive tools that provide useful insights and potential
content/blog/2024-01-27-tableau-dashboard.org +1
@@ -2,6 +2,7 @@
22#+title: Preparing and Visualizing Omaha Crime Data (2015-2023) in Tableau
33#+description: Detailed procedure for data preparation and interactive visualization of crime trends in Omaha, using Tableau software from 2015 through 2023 data.
44#+slug: tableau-dashboard
5#+filetags: :web:
56
67In this project, I am going to show you how to use Tableau Public for free to
78create simple dashboards.
content/blog/2024-02-06-zfs.org +1
@@ -2,6 +2,7 @@
22#+title: Creating and Managing ZFS Storage Pools on Ubuntu Linux
33#+description: Stepwise guide to setting up ZFS storage pools on Ubuntu, including initial installation, pool creation, expansion, and maintenance.
44#+slug: zfs
5#+filetags: :linux:
56
67This post details the process I used to create ZFS pools, datasets, and
78snapshots on Ubuntu Server.
content/blog/2024-02-13-ubuntu-emergency-mode.org +1
@@ -2,6 +2,7 @@
22#+title: Resolving Ubuntu Boot Issues Caused by Invalid /etc/fstab Mounts
33#+description: Detailed instructions to identify errors in the /etc/fstab file causing Ubuntu to enter emergency mode and steps to edit and restore normal boot operations.
44#+slug: ubuntu-emergency-mode
5#+filetags: :linux:
56
67* The Problem
78
content/blog/2024-02-21-self-hosting-otter-wiki.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: An Otter Wiki
33#+description: Stepwise directions for installing Otter Wiki, configuring Docker Compose environment, and setting up Nginx reverse proxy for secure access.
44#+slug: self-hosting-otter-wiki
5#+filetags: :linux:self-hosting:
56
67* An Otter Wiki
78
content/blog/2024-03-13-doom-emacs.org +1
@@ -2,6 +2,7 @@
22#+title: Doom Emacs & Org-Mode Setup
33#+description: Technical manual covering installation, configuration files, and usage procedures for Doom Emacs and Org-Mode targeting note management and task organization.
44#+slug: doom-emacs
5#+filetags: :emacs:
56
67** Screenshots
78
content/blog/2024-03-15-self-hosting-ddns-updater.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: DDNS Updater
33#+description: Step-by-step configuration guide for deploying a Dynamic DNS updater using Docker Compose, integrating with Cloudflare API, and securing with Nginx reverse proxy.
44#+slug: self-hosting-ddns-updater
5#+filetags: :linux:self-hosting:
56
67#+caption: DDNS Updater Web View
78#+attr_html: :alt An example of the DDNS Updater app running and showing that cleberg.net's IP has been updated on Cloudflare.
content/blog/2024-03-29-org-blog.org +1
@@ -2,6 +2,7 @@
22#+title: Blogging with Emacs Org-Mode and Weblorg
33#+description: Instructional content for preparing and publishing blogs using Emacs Org-Mode, including setup of static site generators and content management workflows.
44#+slug: org-blog
5#+filetags: :emacs:web:
56
67First and foremost, apologies to those who subscribe via RSS as I know that my
78feed duplicated itself when I moved this blog over to org-mode last night.
content/blog/2024-04-06-convert-onenote-to-markdown.org +1
@@ -2,6 +2,7 @@
22#+title: Converting OneNote Exports to Markdown and Org-Mode
33#+description: Detailed conversion instructions to transform OneNote document files into Markdown or Org-Mode formats using Pandoc command-line utility on Windows systems.
44#+slug: convert-onenote-to-markdown
5#+filetags: :emacs:
56
67If you're looking to convert your OneNote content to another format, such as
78Markdown or Org-Mode, you're in luck. I use a solution that doesn't require
content/blog/2024-04-08-docker-local-web-server.org +1
@@ -2,6 +2,7 @@
22#+title: Local Web Dev Server Setup with Docker & Nginx
33#+description: Instructions for setting up a local web development environment employing Docker Desktop and Nginx web server to facilitate development and testing workflows.
44#+slug: docker-local-web-server
5#+filetags: :self-hosting:web:
56
67When developing websites locally, I often use a simple Python web server to
78observe the changes.
content/blog/2024-04-18-mu4e.org +1
@@ -2,6 +2,7 @@
22#+title: Configuring Mu4e with Doom Emacs on macOS
33#+description: Stepwise procedure for installing, configuring, and using Mu4e email client within Doom Emacs on macOS for organized email management.
44#+slug: mu4e
5#+filetags: :emacs:linux:
56
67This post was heavily inspired by [[https://macowners.club/posts/email-emacs-mu4e-macos/][Email setup in Emacs with Mu4e on macOS]], but
78with my own tweaks for a single-account configuration and some Doom-specific
content/blog/2024-05-03-ubuntu-on-macos.org +1
@@ -2,6 +2,7 @@
22#+title: OrbStack on macOS: Running a Full Ubuntu Linux Environment
33#+description: Technical guide outlining the installation and operation of OrbStack to run Ubuntu Linux containers natively on macOS systems with performance considerations.
44#+slug: ubuntu-on-macos
5#+filetags: :linux:
56
67Being a macOS user who previously used Linux for many years, I often find myself
78searching for alternatives to the Linux-native tools and methods that I had
content/blog/2024-06-19-deprecated-trusted-gpg-fix.org +1
@@ -2,6 +2,7 @@
22#+title: Migrating Ubuntu GPG Keys to trusted.gpg.d
33#+description: Technical instructions to relocate GPG keys from the deprecated trusted.gpg keyring to the supported trusted.gpg.d directory for system security maintenance.
44#+slug: deprecated-trusted-gpg-fix
5#+filetags: :linux:
56
67** System Warning
78
content/blog/2024-07-11-emacs-on-ipad.org +1
@@ -2,6 +2,7 @@
22#+title: Running Emacs Natively on Apple Silicon iPad
33#+description: Procedural instructions for installing Emacs on iPadOS devices with Apple Silicon architecture, including configuration and operational guidance.
44#+slug: emacs-on-ipad
5#+filetags: :emacs:
56
67This post describes the process to install and use Emacs on the iPad Air 13-inch
78(M2). The iPad used in this post is running iPadOS 17.6.
content/blog/2024-08-11-org-mode-features.org +1
@@ -2,6 +2,7 @@
22#+title: Essential Org-Mode Features for Productivity
33#+description: Detailed overview of essential Org-Mode functionalities focusing on task organization, note-taking, and workflow optimization.
44#+slug: org-mode-features
5#+filetags: :emacs:
56
67* Cycling (Folding)
78
content/blog/2024-08-25-n8n-sentiment-analysis.org +1
@@ -2,6 +2,7 @@
22#+title: Automate Email Sentiment Analysis with n8n
33#+description: Detailed procedural steps for configuring an n8n workflow to perform sentiment analysis on incoming email messages, enabling automated classification based on sentiment.
44#+slug: n8n-sentiment-analysis
5#+filetags: :self-hosting:
56
67* n8n
78
content/blog/2024-09-20-prometheus-grafana-cloud.org +1
@@ -2,6 +2,7 @@
22#+title: Linux Server Monitoring with Prometheus & Grafana Cloud
33#+description: Stepwise method for deploying Prometheus with Docker to monitor Linux servers and integrating Grafana Cloud for visualization and analysis of collected metrics.
44#+slug: prometheus-grafana-cloud
5#+filetags: :linux:self-hosting:
56
67This tutorial will guide you through the process of:
78
content/blog/2024-09-23-self-hosting-transmission.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Transmission BitTorrent Client
33#+description: Comprehensive setup instructions for installing and configuring the Transmission BitTorrent client on a Linux server, including securing remote access through Nginx reverse proxy.
44#+slug: self-hosting-transmission
5#+filetags: :linux:self-hosting:
56
67#+begin_quote
78If you're torrenting anything sensitive, I *highly* recommend you use a VPN.
content/blog/2024-10-31-continue-ollama-code-assistant.org +1
@@ -2,6 +2,7 @@
22#+title: Ollama Code Assistant Setup in VS Codium
33#+description: Technical overview and configuration guide for incorporating Ollama as a code assistance tool within VS Codium and VS Code editors to enhance development workflows.
44#+slug: continue-ollama-code-assistant
5#+filetags: :linux:
56
67* Background
78
content/blog/2024-12-27-self-hosting-the-lounge.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: The Lounge (IRC)
33#+description: Step-by-step instructions for installing and configuring The Lounge IRC web client on Linux systems utilizing Docker Compose to provide persistent and secure chat access.
44#+slug: self-hosting-the-lounge
5#+filetags: :linux:self-hosting:
56
67* The Lounge
78
content/blog/2025-01-23-self-hosting-tandoor.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Tandoor Recipe Manager
33#+description: Detailed tutorial on deploying Tandoor, an open-source recipe management application, including installation steps and configuration for self-hosted operation.
44#+slug: self-hosting-tandoor
5#+filetags: :linux:self-hosting:
56
67* Overview
78
content/blog/2025-02-11-obscura-vpn.org +1
@@ -2,6 +2,7 @@
22#+title: Obscura VPN: A Two-Party Protocol Review
33#+description: Analytical review outlining the features, implementation, and security aspects of Obscura VPN's two-party protocol in conjunction with Mullvad VPN.
44#+slug: obscura-vpn
5#+filetags: :security:
56
67#+begin_quote
78This review is written at a high-level for users, not a technical deep-dive of
content/blog/2025-02-24-email-migration.org +1
@@ -2,6 +2,7 @@
22#+title: How I Transferred 5000+ Emails from Proton Mail to Migadu
33#+description: Detailed instructions describing the process and considerations involved in transferring email data securely from Proton Mail to Migadu email hosting.
44#+slug: email-migration
5#+filetags: :privacy:
56
67* The Setup
78
content/blog/2025-04-05-git-mirror.org +1
@@ -2,6 +2,7 @@
22#+title: Automating GitHub to GitLab Repository Sync
33#+description: Technical steps for setting up automated synchronization and mirroring of source code repositories from GitHub to GitLab for redundancy and repository management.
44#+slug: git-mirror
5#+filetags: :self-hosting:
56
67This is a short post detailing how I maintained repositories on GitHub and
78mirrors on GitLab - including both public and private repositories.
content/blog/2025-05-02-asahi-linux.org +1
@@ -2,6 +2,7 @@
22#+title: Running Asahi Linux on Apple M2 MacBook Pro: My Experience
33#+description: Documented analysis of installation procedure, system performance, and software compatibility for running Asahi Linux on the Apple M2 MacBook Pro 16-inch model.
44#+slug: asahi-linux
5#+filetags: :linux:
56
67* Trying out Asahi Linux
78
content/blog/2025-05-30-it-audit-career.org +1
@@ -2,6 +2,7 @@
22#+title: Mastering Emerging Tech for IT Audit Career Growth
33#+description: Instructional content detailing actionable knowledge areas including artificial intelligence, blockchain, cloud computing, DevOps, and automation relevant for audit professionals.
44#+slug: it-audit-career
5#+filetags: :audit:
56
67* Introduction
78
content/blog/2025-06-02-private-ios-apps.org +1
@@ -2,6 +2,7 @@
22#+title: Privacy-First iOS Apps for Minimalists
33#+description: Curated listing of iOS applications prioritized for privacy preservation and data security, targeted at users requiring minimal data exposure.
44#+slug: private-ios-apps
5#+filetags: :linux:privacy:
56
67The world is evolving into a privacy nightmare, where our own devices are being
78used by numerous parties to constantly track and report on our activities. This
content/blog/2025-09-04-website-redesign.org +1
@@ -2,6 +2,7 @@
22#+title: Crafting a More Human-Centric Design for My Website
33#+description: Read this post to understand my latest website redesign and the context for the refresh.
44#+slug: human-website-design
5#+filetags: :web:
56
67#+begin_quote
78/Please note that this redesign is a work-in-progress and is not complete. The
content/blog/2025-09-25-minimalist-website-redesign.org +1
@@ -2,6 +2,7 @@
22#+title: Simplifying the Site: A Minimalist Approach
33#+description: This post details a complete redesign of a blog post, stripping away extraneous CSS and HTML elements to prioritize readability and user experience.
44#+slug: minimalist-website-redesign
5#+filetags: :web:
56
67I know what you're thinking: "ANOTHER blog post about redesigning the website?"
78
content/blog/2025-10-03-privacy-toolkit.org +1
@@ -2,6 +2,7 @@
22#+title: My Privacy Toolkit
33#+description: Learn about the tools I use to keep my life private and data secure.
44#+slug: privacy-toolkit
5#+filetags: :privacy:
56
67* VPN
78
content/blog/2025-10-06-rocket-league-macos.org +1
@@ -2,6 +2,7 @@
22#+title: Playing Rocket League on macOS via CrossOver
33#+description: Learn how to play Rocket League on macOS via CrossOver.
44#+slug: rocket-league-macos
5#+filetags: :linux:
56
67#+caption: Rocket League on macOS
78#+attr_html: :alt The Rocket League launch screen on macOS.
content/blog/2025-10-24-digital-garden.org +1
@@ -2,6 +2,7 @@
22#+title: Digital Garden
33#+description: A post dedicated to digital gardens, an online space for personal knowledge management, creative exploration, and reflection.
44#+slug: digital-garden
5#+filetags: :web:
56
67* What's a Digital Garden?
78
content/blog/2025-11-02-aerc-macos.org +1
@@ -2,6 +2,7 @@
22#+title: Using aerc on macOS
33#+description: Learn how I use aerc, a TUI email client, on macOS.
44#+slug: aerc-macos
5#+filetags: :linux:
56
67#+caption: aerc-mail
78#+attr_html: :alt An image of aerc with an email opened in the reader window.
content/blog/2025-11-13-wcag.org +1
@@ -2,6 +2,7 @@
22#+title: Striving for 100% WCAG 2 Compliance
33#+description: Read on to learn more about how I've ensured my humble site is compliant with WCAG 2.
44#+slug: wcag
5#+filetags: :audit:web:
56
67* WCAG 2
78
content/blog/2025-11-23-it-audit-ai.org +1
@@ -2,6 +2,7 @@
22#+title: Practical Uses for AI in IT Audit
33#+description: Learn how I'm currently using AI in my role in Technology Assurance (i.e., IT Audit) at KPMG.
44#+slug: it-audit-ai
5#+filetags: :audit:
56
67* My AI Toolkit
78
content/blog/2025-12-06-self-hosting-tor.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Tor Websites
33#+description: Learn how to host your own website on Tor with an Onion Address in a few short steps!
44#+slug: self-hosting-tor
5#+filetags: :linux:self-hosting:
56
67* Installation
78
content/blog/2025-12-20-self-hosting-home-assistant.org +1
@@ -2,6 +2,7 @@
22#+title: Self-Hosting Guide: Home Assistant
33#+description: A guide to configuring and customizing Home Assistant.
44#+slug: self-hosting-home-assistant
5#+filetags: :linux:self-hosting:
56
67* Overview
78
content/blog/2026-01-31-emacs-carnival-2026-01-this-year-i-will.org +1
@@ -2,6 +2,7 @@
22#+title: Emacs Carnival: “This Year, I Will...”
33#+description: My response to the Emacs Carnival post for January 2026.
44#+slug: emacs-carnival-2026-01-this-year-i-will
5#+filetags: :emacs:personal:
56
67This year in Emacs, I expect to do a lot. However, here are some actionable
78goals for myself that should have a positive impact as I start out 2026.
content/blog/2026-02-02-emacs-carnival-2026-02-completion.org +1
@@ -2,6 +2,7 @@
22#+title: Emacs Carnival: "Completion"
33#+description: My response to the Emacs Carnival post for February 2026.
44#+slug: emacs-carnival-2026-02-completion
5#+filetags: :emacs:personal:
56
67I'm having a great time with the Emacs Carnival, as it has inspired me to write
78two posts in such a short time. It's been a much needed inspiration to write
content/blog/2026-02-07-indieweb-carnival-2026-02-intersecting-interests.org +1
@@ -2,6 +2,7 @@
22#+title: IndieWeb Carnival: "Intersecting Interests"
33#+description: Contrasting my passions with technology vs. natural hobbies.
44#+slug: indiweb-carnival-2026-02-intersecting-interests
5#+filetags: :personal:web:
56
67I thought about this topic for a long time today before starting to write this
78post, as I don't think of myself as someone with intersecting interests. I
content/blog/2026-02-08-gnu-stow.org +1
@@ -2,6 +2,7 @@
22#+title: Managing My Dotfiles with GNU Stow and Git
33#+description: Learn how I use GNU Stow to manage my user dotfiles and configurations.
44#+slug: gnu-stow
5#+filetags: :emacs:linux:
56
67* What is GNU Stow?
78
content/blog/2026-02-12-automating-weblorg-deployments.org +1
@@ -2,6 +2,7 @@
22#+title: Automating Weblorg Deployments with GitHub Actions
33#+description: Learn how I've automated all deployment for my org-mode blog with GitHub Actions and a custom Docker image.
44#+slug: automating-weblorg-deployments
5#+filetags: :self-hosting:web:
56
67As I've mentioned in previous posts, I utilize a unique pipeline to draft posts,
78compose my website, and to build and deploy the static files.
content/blog/2026-02-21-auditing-aws-iam.org +1
@@ -2,6 +2,7 @@
22#+title: Auditing AWS IAM Users
33#+description: Learn how to audit IAM user assignments in AWS.
44#+slug: auditing-aws-iam
5#+filetags: :audit:
56
67If you've ever asked an IT team for a list of who has access to an AWS account,
78you've probably received a spreadsheet that was already out of date. Or worse,
content/blog/2026-02-21-auditing-aws-passwords.org +1
@@ -2,6 +2,7 @@
22#+title: Auditing AWS Passwords
33#+description: Learn how to audit passwords in AWS.
44#+slug: auditing-aws-passwords
5#+filetags: :audit:
56
67One of the first controls an IT Auditor learns is how to audit passwords in any
78number of IT systems. However, things have changed with the introduction of
content/blog/2026-03-03-auditing-aws-s3.org +1
@@ -2,6 +2,7 @@
22#+title: Auditing AWS S3 Buckets
33#+description: Learn how to audit AWS S3 buckets for public access.
44#+slug: auditing-aws-s3
5#+filetags: :audit:
56
67This is the latest in my series of posts on auditing AWS, a cloud platform that
78has existed for around two decades but can still be a mystery to auditors who
tag_preview.py added +177
@@ -0,0 +1,177 @@
1#!/usr/bin/env python3
2"""
3Preview tag assignments for all blog posts.
4Run with --write to actually add #+filetags to org files.
5"""
6import re
7import sys
8from pathlib import Path
9
10CONTENT_DIR = Path("./content/blog")
11
12# Explicit overrides take priority over rules
13OVERRIDES = {
14 "2018-11-28-cpp-compiler": ["linux"],
15 "2019-12-16-password-security": ["security"],
16 "2020-07-26-business-analysis": ["audit"],
17 "2020-08-22-redirect-github-pages": ["web"],
18 "2020-09-22-internal-audit": ["audit"],
19 "2020-12-28-neon-drive": ["personal"],
20 "2020-12-29-zork": ["personal"],
21 "2021-08-25-audit-sampling": ["audit"],
22 "2021-12-04-cisa": ["audit"],
23 "2023-05-22-burnout": ["personal"],
24 "2023-06-20-audit-review-template": ["audit"],
25 "2023-08-18-agile-auditing": ["audit"],
26 "2025-05-30-it-audit-career": ["audit"],
27 "2025-11-13-wcag": ["audit", "web"],
28 "2025-11-23-it-audit-ai": ["audit"],
29 "2026-02-21-auditing-aws-iam": ["audit"],
30 "2026-02-21-auditing-aws-passwords": ["audit"],
31 "2026-03-03-auditing-aws-s3": ["audit"],
32 "2020-09-01-visual-recognition": ["linux"],
33 "2024-01-26-audit-dashboard": ["audit"],
34 "2023-09-19-audit-sql-scripts": ["audit"],
35 "2021-04-28-photography": ["personal"],
36 "2022-06-22-daily-poetry": ["personal"],
37 "2020-09-25-happiness-map": ["personal"],
38 "2022-03-03-financial-database": ["self-hosting"],
39 "2023-01-03-recent-website-changes": ["personal", "web"],
40 "2025-09-25-minimalist-website-redesign": ["web"],
41 "2026-02-07-indieweb-carnival-2026-02-intersecting-interests": ["personal", "web"],
42}
43
44TAG_RULES = {
45 "audit": [
46 "audit", "cisa", "ansoff",
47 ],
48 "emacs": [
49 "emacs", "org-mode", "org-blog", "mu4e", "doom-emacs",
50 "emacs-carnival", "gnu-stow",
51 ],
52 "linux": [
53 "linux", "ubuntu", "debian", "fedora", "alpine",
54 "customizing-ubuntu", "linux-software", "linux-display",
55 "mtp-linux", "serenity-os", "fedora-i3", "fedora-login",
56 "flatpak", "zfs", "ubuntu-emergency", "ubuntu-on-macos",
57 "steam-on-ntfs", "bash-it", "byobu", "scli",
58 "terminal-lifestyle", "curseradio", "st", "flac-to-opus",
59 "pinetime", "server-build", "macos", "macos-customization",
60 "deprecated-trusted-gpg", "exiftool", "graphene",
61 "asahi", "aerc", "rocket-league",
62 ],
63 "self-hosting": [
64 "self-hosting", "homelab", "vps-web-server", "git-server",
65 "plex", "nextcloud", "wireguard", "backblaze", "syncthing",
66 "docker", "n8n", "prometheus-grafana", "transmission",
67 "goaccess", "unifi", "git-mirror", "automating-weblorg",
68 ],
69 "security": [
70 "aes-encryption", "cryptography", "gnupg", "password",
71 "server-hardening", "ssh-mfa", "ufw", "hardening",
72 "authelia", "wireguard", "njalla-dns", "cloudflare-dns",
73 "ditching-cloudflare", "obscura-vpn",
74 ],
75 "privacy": [
76 "privacy", "graphene-os", "session-messenger", "fediverse",
77 "digital-minimalism", "privacy-com", "local-llm",
78 "email-migration", "dont-say-hello",
79 ],
80 "web": [
81 "nginx", "apache", "php", "css", "redirect", "website-redesign",
82 "gemini", "indieweb", "weblorg", "html", "digital-garden",
83 "tableau",
84 ],
85 "personal": [
86 "mediocrity", "burnout", "tuesday", "leaving-the-office",
87 "vaporwave", "video-game-sales", "reliable-notes",
88 "mass-unlike-tumblr", "changing-git-authors", "delete-gitlab",
89 "clone-github", "this-year-i-will", "completion",
90 "seum", "neon-drive", "zork",
91 ],
92}
93
94def assign_tags(slug: str, title: str) -> list[str]:
95 if slug in OVERRIDES:
96 return OVERRIDES[slug]
97 slug_lower = slug.lower()
98 title_lower = title.lower()
99 tags = []
100 for tag, patterns in TAG_RULES.items():
101 for pattern in patterns:
102 if pattern in slug_lower or pattern in title_lower:
103 if tag not in tags:
104 tags.append(tag)
105 break
106 return sorted(tags)
107
108def get_title(path: Path) -> str:
109 title_pat = re.compile(r"^#\+title:\s*(.+)$", re.IGNORECASE)
110 with path.open("r", encoding="utf-8") as f:
111 for line in f:
112 m = title_pat.match(line)
113 if m:
114 return m.group(1).strip()
115 return path.stem
116
117def has_filetags(path: Path) -> bool:
118 with path.open("r", encoding="utf-8") as f:
119 for line in f:
120 if re.match(r"^#\+filetags:", line, re.IGNORECASE):
121 return True
122 return False
123
124def write_filetags(path: Path, tags: list[str]):
125 tag_str = ":" + ":".join(tags) + ":"
126 content = path.read_text(encoding="utf-8")
127 slug_pat = re.compile(r"(#\+slug:\s*.+\n)", re.IGNORECASE)
128 m = slug_pat.search(content)
129 if m:
130 insert_at = m.end()
131 new_content = content[:insert_at] + f"#+filetags: {tag_str}\n" + content[insert_at:]
132 path.write_text(new_content, encoding="utf-8")
133 return True
134 return False
135
136write_mode = "--write" in sys.argv
137
138untagged = []
139rows = []
140for org_path in sorted(CONTENT_DIR.glob("*.org")):
141 slug = org_path.stem
142 title = get_title(org_path)
143 tags = assign_tags(slug, title)
144 if not tags:
145 untagged.append((slug, title))
146 rows.append((slug, title, tags))
147
148print(f"{'SLUG':<50} {'TAGS'}")
149print("-" * 85)
150for slug, title, tags in rows:
151 tag_str = ", ".join(tags) if tags else "-- UNTAGGED --"
152 print(f"{slug:<50} {tag_str}")
153
154print(f"\nTotal: {len(rows)} posts | Untagged: {len(untagged)}")
155if untagged:
156 print("\nUntagged posts:")
157 for slug, title in untagged:
158 print(f" {slug}")
159
160if write_mode:
161 written = 0
162 skipped = 0
163 for org_path in sorted(CONTENT_DIR.glob("*.org")):
164 slug = org_path.stem
165 title = get_title(org_path)
166 tags = assign_tags(slug, title)
167 if not tags:
168 skipped += 1
169 continue
170 if has_filetags(org_path):
171 skipped += 1
172 continue
173 if write_filetags(org_path, tags):
174 written += 1
175 print(f"\nWrote filetags to {written} files, skipped {skipped}.")
176else:
177 print("\nRun with --write to apply filetags to org files.")
theme/static/styles.css +14
@@ -581,3 +581,17 @@ img:hover { filter: grayscale(0); }
581581@media (max-width: 480px) {
582582 .masthead nav li { width: 100%; }
583583}
584
585/* Tags page */
586.tag-toc {
587 display: flex;
588 flex-wrap: wrap;
589 gap: 0.5rem 1.5rem;
590 list-style: none;
591 padding: 0;
592 margin: 0 0 3rem;
593}
594.tag-count {
595 color: var(--meta);
596 font-size: var(--text-xs);
597}
theme/templates/base.html +1
@@ -21,6 +21,7 @@
2121 <nav aria-label="Site Navigation">
2222 <ul>
2323 <li><a href="/blog/">Blog</a></li>
24 <li><a href="/tags/">Tags</a></li>
2425 <li><a href="/guides/index.html">Guides</a></li>
2526 <li><a href="/apps/">Apps</a></li>
2627 <li><a href="/garden/">Garden</a></li>