add rate limiting, CSRF, newsletter, auto-checker, /uses and /projects pages

This commit is contained in:
Blake Ridgway
2026-03-11 14:12:52 -05:00
parent 261745a5b7
commit 58831e2429
17 changed files with 913 additions and 19 deletions

View File

@@ -8,6 +8,7 @@
<a href="/admin/new" class="btn">New Post</a>
<a href="/admin/status" class="btn btn-outline">Edit Status</a>
<a href="/admin/uploads" class="btn btn-outline">Uploads</a>
<a href="/admin/newsletter" class="btn btn-outline">Newsletter</a>
<a href="/" class="btn btn-outline">View Site</a>
<form method="POST" action="/admin/logout" class="inline-form">
<button type="submit" class="btn btn-outline">Logout</button>

View File

@@ -0,0 +1,45 @@
{{define "title"}}Newsletter &mdash; Admin{{end}}
{{define "content"}}
<div class="admin-wrap">
<div class="admin-header">
<h1>Newsletter Subscribers</h1>
<div class="admin-actions">
<a href="/admin" class="btn btn-outline">Back to Dashboard</a>
</div>
</div>
{{if .Flash}}<p class="flash-msg">{{.Flash}}</p>{{end}}
<p class="text-muted">{{.Count}} subscriber{{if ne .Count 1}}s{{end}}</p>
{{if not .Subscribers}}
<p class="empty-state">No subscribers yet.</p>
{{else}}
<table class="admin-table">
<thead>
<tr>
<th>Email</th>
<th>Subscribed</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{range .Subscribers}}
<tr>
<td>{{.Email}}</td>
<td class="text-muted mono">{{formatDate .CreatedAt}}</td>
<td class="actions-cell">
<form method="POST" action="/admin/newsletter" class="inline-form"
onsubmit="return confirm('Remove {{.Email}}?')">
<input type="hidden" name="email" value="{{.Email}}">
<button type="submit" class="btn btn-sm btn-danger">Remove</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}
</div>
{{end}}

View File

@@ -49,6 +49,19 @@
Pricing by project or hourly &mdash; contact me for details.
</div>
<section class="subscribe-section">
<h2>Stay updated</h2>
<p>Occasional posts on OpenBSD, homelab builds, and infrastructure work. No spam.</p>
<form method="POST" action="/newsletter" class="subscribe-form">
<div class="hp-field" aria-hidden="true">
<label for="url">URL</label>
<input type="text" id="url" name="url" tabindex="-1" autocomplete="off">
</div>
<input type="email" name="email" placeholder="your@email.com" required autocomplete="email">
<button type="submit" class="btn btn-outline">Subscribe</button>
</form>
</section>
<section class="contact-section">
<h2>Get in touch</h2>
<p>Tell me about your project or problem. I'll respond within one business day.</p>
@@ -61,6 +74,12 @@
{{if .Error}}<p class="form-error">{{.Error}}</p>{{end}}
<form method="POST" action="/hire" class="contact-form">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
{{/* Honeypot: hidden from humans, bots fill it in */}}
<div class="hp-field" aria-hidden="true">
<label for="website">Website</label>
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
</div>
<div class="form-group">
<label for="name">Name <span class="required-mark">*</span></label>
<input type="text" id="name" name="name" value="{{.Name}}" required autocomplete="name" placeholder="Jane Smith">

87
templates/projects.html Normal file
View File

@@ -0,0 +1,87 @@
{{define "title"}}Projects &mdash; Ridgway Systems{{end}}
{{define "meta-desc"}}Infrastructure projects and builds by Blake Ridgway — homelab, monitoring systems, security tooling, and more.{{end}}
{{define "content"}}
<div class="projects-page">
<div class="page-header">
<h1>Projects</h1>
<p class="page-desc">Things built, broken, and rebuilt.</p>
</div>
<div class="project-list">
<div class="project-item">
<div class="project-header">
<h2 class="project-title">ridgwaysystems.org</h2>
<div class="project-tags">
<span class="tag">Go</span>
<span class="tag">OpenBSD</span>
<span class="tag">self-hosted</span>
</div>
</div>
<p>This site. A single Go binary serving a blog, status page, hire page, and admin panel &mdash; no database, no Docker, no external dependencies at runtime. Flat Markdown files on disk, HMAC-signed sessions, chroma syntax highlighting. Deployed on OpenBSD behind relayd. The build log covers the whole thing.</p>
<div class="project-links">
<a href="/blog">Build log &rarr;</a>
<a href="https://git.ridgwaysystems.org">Source &rarr;</a>
</div>
</div>
<div class="project-item">
<div class="project-header">
<h2 class="project-title">Policy-as-Code Firewall Framework</h2>
<div class="project-tags">
<span class="tag">pf</span>
<span class="tag">IaC</span>
<span class="tag">security</span>
</div>
</div>
<p>A policy-as-code system for managing pf firewall rules across multiple OpenBSD hosts. Rules defined in structured configuration, rendered to pf.conf via templating, with automated geo-location blocking and rule validation before deployment. Deployed at Triangle Insurance to manage ~200 rules across three firewall segments.</p>
<div class="project-links">
<a href="/blog/pf-vlans">Related post &rarr;</a>
</div>
</div>
<div class="project-item">
<div class="project-header">
<h2 class="project-title">ISP Network Monitoring</h2>
<div class="project-tags">
<span class="tag">Prometheus</span>
<span class="tag">Grafana</span>
<span class="tag">Go</span>
</div>
</div>
<p>Custom Prometheus exporter that continuously measures ISP throughput, latency, and packet loss across multiple WAN connections. Exports to Grafana for real-time dashboards and alerting. Replaced manual speed tests that only caught outages after users complained. Cut time-to-detect WAN degradation from hours to minutes.</p>
</div>
<div class="project-item">
<div class="project-header">
<h2 class="project-title">Homelab Infrastructure</h2>
<div class="project-tags">
<span class="tag">OpenBSD</span>
<span class="tag">Ansible</span>
<span class="tag">Terraform</span>
<span class="tag">homelab</span>
</div>
</div>
<p>The homelab: fw01 running OpenBSD with pf and WireGuard, two Dell rack servers, VLAN-segmented network (management, servers, IoT, guest), self-hosted Gitea, Matrix, Jellyfin, Prometheus, and Grafana. Fully documented, IaC'd where possible, and used as a test bed before anything touches production.</p>
<div class="project-links">
<a href="/infrastructure">Infrastructure diagram &rarr;</a>
<a href="/uses">What I run &rarr;</a>
</div>
</div>
<div class="project-item">
<div class="project-header">
<h2 class="project-title">Zero-Touch Provisioning System</h2>
<div class="project-tags">
<span class="tag">PXE</span>
<span class="tag">Ansible</span>
<span class="tag">automation</span>
</div>
</div>
<p>PXE boot + Ansible-based provisioning pipeline for deploying standardized workstation images across Air Force Training bases. Reduced per-machine setup time by 75% and eliminated configuration drift between deployments. Machines boot, pull config from the server, and are production-ready without a human touching them after the initial PXE boot.</p>
</div>
</div>
</div>
{{end}}

99
templates/uses.html Normal file
View File

@@ -0,0 +1,99 @@
{{define "title"}}Uses &mdash; Ridgway Systems{{end}}
{{define "meta-desc"}}Hardware, software, and tools Blake Ridgway uses in the homelab and day-to-day work.{{end}}
{{define "content"}}
<div class="uses-page">
<div class="page-header">
<h1>Uses</h1>
<p class="page-desc">Hardware, software, and tools — homelab and daily driver.</p>
</div>
<section class="uses-section">
<h2>Hardware</h2>
<div class="uses-item">
<div class="uses-item-header">
<span class="uses-name">fw01</span>
<span class="uses-role">Firewall / Router</span>
</div>
<p>SuperMicro 1U, Intel E3-1230v2, 16GB ECC RAM. Running OpenBSD. Handles all pf firewall rules, VLANs, WireGuard VPN, unbound DNS, and relayd reverse proxy. The critical piece everything else depends on.</p>
</div>
<div class="uses-item">
<div class="uses-item-header">
<span class="uses-name">srv01</span>
<span class="uses-role">Primary Services</span>
</div>
<p>Dell PowerEdge R720, dual Xeon E5-2600, 64GB RAM. Main workload server — runs Prometheus, Grafana, Gitea, OpenSMTPD, Matrix/Conduit. Loud and power-hungry, but handles everything without complaint.</p>
</div>
<div class="uses-item">
<div class="uses-item-header">
<span class="uses-name">srv02</span>
<span class="uses-role">Media / Secondary</span>
</div>
<p>Dell PowerEdge R710. Jellyfin media server, game server VMs, secondary storage, authoritative DNS (nsd). The workhorse for anything that doesn't need to be bulletproof.</p>
</div>
<div class="uses-item">
<div class="uses-item-header">
<span class="uses-name">ws01</span>
<span class="uses-role">Workstation</span>
</div>
<p>Desktop, AMD Ryzen. Daily driver for development, terminal sessions, and homelab management. Running Fedora Linux.</p>
</div>
</section>
<section class="uses-section">
<h2>Operating Systems</h2>
<ul class="uses-list">
<li><strong>OpenBSD</strong> &mdash; fw01, this web server. Chosen for its security defaults, pf, and the fact that it does exactly what it says on the tin.</li>
<li><strong>AlmaLinux / Rocky</strong> &mdash; srv01, srv02. RHEL-compatible for production workloads where SELinux and systemd are expected.</li>
<li><strong>Fedora</strong> &mdash; Workstation. Stays close to bleeding-edge tooling without being Arch.</li>
</ul>
</section>
<section class="uses-section">
<h2>Networking</h2>
<ul class="uses-list">
<li><strong>pf</strong> &mdash; OpenBSD packet filter. VLANs, NAT, geo-blocking, antispoof. The whole reason fw01 runs OpenBSD.</li>
<li><strong>WireGuard</strong> &mdash; VPN for remote access. Simple, fast, auditable.</li>
<li><strong>unbound</strong> &mdash; Recursive DNS resolver on fw01. Validates DNSSEC, blocks ad/tracking domains.</li>
<li><strong>nsd</strong> &mdash; Authoritative DNS on srv02 for the ridgwaysystems.org zone.</li>
<li><strong>relayd</strong> &mdash; OpenBSD reverse proxy in front of this site and internal services.</li>
</ul>
</section>
<section class="uses-section">
<h2>Infrastructure &amp; Automation</h2>
<ul class="uses-list">
<li><strong>Terraform</strong> &mdash; Cloud infrastructure (Azure, AWS). Anything that touches a cloud API gets IaC'd.</li>
<li><strong>Ansible</strong> &mdash; Configuration management for Linux servers. Idempotent, no agent required.</li>
<li><strong>Gitea</strong> &mdash; Self-hosted git at <a href="https://git.ridgwaysystems.org">git.ridgwaysystems.org</a>. Lightweight, fast, no subscription required.</li>
<li><strong>Prometheus + Grafana</strong> &mdash; Metrics and dashboards for everything. Custom exporters for pf counters, ISP throughput, and hardware sensors.</li>
<li><strong>Nagios</strong> &mdash; Service alerting. Opinionated but reliable — been running since before dashboards were cool.</li>
</ul>
</section>
<section class="uses-section">
<h2>Development</h2>
<ul class="uses-list">
<li><strong>VS Code</strong> &mdash; Primary editor. Remote SSH extension makes working directly on servers seamless.</li>
<li><strong>Go</strong> &mdash; Preferred language for infrastructure tooling and this site. Fast to compile, easy to deploy a single binary.</li>
<li><strong>Python</strong> &mdash; Scripting, automation, quick data processing.</li>
<li><strong>Bash / ksh</strong> &mdash; Bash on Linux, ksh on OpenBSD. Shell scripts for anything that doesn't need to outlast the week.</li>
<li><strong>tmux</strong> &mdash; Terminal multiplexer. Multiple panes across multiple SSH sessions, always.</li>
</ul>
</section>
<section class="uses-section">
<h2>Self-hosted Services</h2>
<ul class="uses-list">
<li><strong>OpenSMTPD</strong> &mdash; Mail server. Handles inbound and outbound for ridgwaysystems.org.</li>
<li><strong>Matrix / Conduit</strong> &mdash; Self-hosted chat. Federated, encrypted. Currently migrating.</li>
<li><strong>Jellyfin</strong> &mdash; Media server. No subscription, no phone-home, streams anywhere on the LAN.</li>
</ul>
</section>
</div>
{{end}}