From 00a73b421b78f95cb017d33e75b2906a782dd19d Mon Sep 17 00:00:00 2001 From: Matthew Binning Date: Thu, 1 Jan 2026 15:38:41 -0800 Subject: [PATCH] init: Restart blog Bootstrapped the site from scratch following a data loss event. Set up a simple HTML/CSS page served from nginx. Added a navbar with the index page anchored in the top-left, a blog page link, and a link to the Forgejo instance. Added contact info and a genealogy blurb to the index page. Added an example resume page linked from the navbar. --- .gitignore | 1 + 404.html | 27 ++++ README.md | 35 +++++ blog.html | 89 +++++++++++++ deploy.sh | 15 +++ includes/footer.html | 3 + includes/navbar.html | 10 ++ index.html | 37 ++++++ nginx.nix | 140 ++++++++++++++++++++ resume.html | 122 +++++++++++++++++ style.css | 305 +++++++++++++++++++++++++++++++++++++++++++ www.code-workspace | 7 + 12 files changed, 791 insertions(+) create mode 100644 .gitignore create mode 100644 404.html create mode 100644 README.md create mode 100644 blog.html create mode 100755 deploy.sh create mode 100644 includes/footer.html create mode 100644 includes/navbar.html create mode 100644 index.html create mode 100644 nginx.nix create mode 100644 resume.html create mode 100644 style.css create mode 100644 www.code-workspace diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2858192 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +blog/* diff --git a/404.html b/404.html new file mode 100644 index 0000000..33c62f8 --- /dev/null +++ b/404.html @@ -0,0 +1,27 @@ + + + + + + 404 - Page Not Found + + + + + +
+
+

404 - Page Not Found

+

The page you're looking for doesn't exist.

+
+ +
+

What happened?

+

The page you requested could not be found. It may have been moved, deleted, or never existed.

+

← Go back to homepage

+
+
+ + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..2cb2fc5 --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# WWW + +Www is my personal website, blog project, and portfolio page. +It should be available at https://wwww.binning.dev + +# History + +## 2025-02-28 + +I restarted this in [Rocket](https://rocket.rs) after yet another data loss event. + +## 2024-06-21 + +I migrated from cgit to forgejo and from kuberentes to simply nginx. + +## 2023-10-07 + +I merged the deployment repository into this one. +I also moved to self-hosting at some point. + +## 2022-01-05 + +I moved hosting to Vultr and moved to a Cobalt. +One neat command to unhide files was: + +`for i in \.*; do if [ ${i} != '.' ] && [ ${i} != '..' ]; then mv {.,}${i/\./} ; fi; done;` + +## 2018-12-16 + +I started this blog with [Namecheap][Namecheap], [Ruby][Ruby], [Jekyll][Jekyll], and [Github-Pages][Github-Pages]. + +[Namecheap]: https://www.namecheap.com/ +[Ruby]: https://www.ruby-lang.org/ +[Jekyll]: https://jekyllrb.com/ +[Github-Pages]: https://pages.github.com/ \ No newline at end of file diff --git a/blog.html b/blog.html new file mode 100644 index 0000000..7c4e8fd --- /dev/null +++ b/blog.html @@ -0,0 +1,89 @@ + + + + + + Blog - WWW + + + + + +
+
+

Blog

+

Stories, adventures, and reflections from life's journey

+
+ + +
+

The Copper Chronicle

+

Adventures and travels with Copper, exploring the beautiful outdoors.

+
+
+

Big Sur Adventure

+

April 2024

+

Exploring the stunning coastline and trails of Big Sur with Copper.

+
+
+

Dove Hunting

+

September 2024

+

A day in the field with friends, shotguns, and good company.

+
+
+

Shasta & Dunsmuir

+

September 2024

+

Mountain adventures in Northern California.

+
+
+
+ + +
+

Life & Reflections

+

Personal thoughts and journeys on health, faith, and life.

+
+
+

Health Journey

+

Private Article

+

Reflections on physical and mental wellness.

+ 🔒 Private +
+
+

Faith Journey

+

Private Article

+

Personal spiritual reflections and growth.

+ 🔒 Private +
+
+
+ + +
+

Events & Experiences

+

Special moments and memorable experiences.

+
+
+

DefCon

+

Private Article

+

Notes and reflections from DefCon.

+ 🔒 Private +
+
+

Oktoberfest

+

Private Article

+

Celebrating traditions and community.

+ 🔒 Private +
+ +
+
+
+ + + + diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..daf400e --- /dev/null +++ b/deploy.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +sudo cp -rt /srv/www/binning.net \ + blog \ + includes \ + index.html \ + blog.html \ + resume.html \ + style.css \ + 404.html + +sudo chown -R nginx:nginx /srv/www/binning.net/ + +sudo cp -t /etc/nixos/ \ + nginx.nix \ No newline at end of file diff --git a/includes/footer.html b/includes/footer.html new file mode 100644 index 0000000..d78ea74 --- /dev/null +++ b/includes/footer.html @@ -0,0 +1,3 @@ + diff --git a/includes/navbar.html b/includes/navbar.html new file mode 100644 index 0000000..4cccc2f --- /dev/null +++ b/includes/navbar.html @@ -0,0 +1,10 @@ + diff --git a/index.html b/index.html new file mode 100644 index 0000000..ae2384c --- /dev/null +++ b/index.html @@ -0,0 +1,37 @@ + + + + + + WWW - Personal Website + + + + + +
+
+

Welcome

+

This is my personal website and blog.

+
+ +
+

About & Contact

+
+

Email: example@example.com

+

Feel free to reach out via email for any inquiries.

+
+
+ +
+

Genealogy

+
+

I am interested in family history and genealogy. This website serves as a personal space to share stories, chronicles, and musings about life's journey, adventures, and family heritage.

+

The Copper Chronicle contains stories and memories from various trips and experiences. More to come as this site develops.

+
+
+
+ + + + diff --git a/nginx.nix b/nginx.nix new file mode 100644 index 0000000..a2f5b7d --- /dev/null +++ b/nginx.nix @@ -0,0 +1,140 @@ +{ config, pkgs, lib, ... }: + +let + # Read multiple API keys from the secrets file at build time + # Note: This embeds the secrets in the Nix store, which is a trade-off + # Alternative: Keep secrets file and read via njs module or external auth service + secretsFile = "/srv/nginx/secrets"; + + # Read API keys from file (one key per line, will be evaluated at build time) + # If the file doesn't exist yet, this will fail - create it first + apiKeysRaw = builtins.readFile secretsFile; + apiKeys = lib.filter (k: k != "") (lib.splitString "\n" apiKeysRaw); + + # Generate map entries for each key + mapEntries = lib.concatMapStringsSep "\n " + (key: ''"Bearer ${key}" "authorized";'') + apiKeys; + +in +{ + services.nginx = { + enable = true; + + # Recommended settings + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + + # Increase bucket size for long Bearer tokens + mapHashBucketSize = 128; + + # Map directive to check Authorization header against multiple keys + appendHttpConfig = '' + # Check if the Authorization header matches any expected value + map $http_authorization $auth_status { + default "unauthorized"; + "" "no_auth"; + ${mapEntries} + } + ''; + + # Virtual hosts configuration + virtualHosts = { + + # Main website - Static HTML/CSS + "www.binning.net" = { + enableACME = true; + forceSSL = true; + + root = "/srv/www/binning.net"; + + locations."/" = { + index = "index.html"; + tryFiles = "$uri $uri/ =404"; + extraConfig = '' + # Enable Server Side Includes for navbar/footer includes + ssi on; + ''; + }; + + # Optional: Custom 404 page + extraConfig = '' + error_page 404 /404.html; + ''; + }; + + # Ollama with Bearer token authentication + "ollama.binning.net" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + extraConfig = '' + # Check auth status + if ($auth_status = "no_auth") { + return 401 "Unauthorized: Bearer token required\n"; + } + if ($auth_status = "unauthorized") { + return 403 "Forbidden: Invalid API key\n"; + } + + # Proxy to Ollama (only if authorized) + proxy_pass http://localhost:11434; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Timeouts for long-running requests + proxy_read_timeout 300s; + proxy_connect_timeout 300s; + proxy_send_timeout 300s; + + # Allow large request bodies + client_max_body_size 100M; + + # Logging + access_log /var/log/nginx/ollama_access.log; + error_log /var/log/nginx/ollama_error.log; + ''; + }; + }; + + # Forgejo + "forgejo.binning.net" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + proxyPass = "http://127.0.0.1:3000"; + # No extraConfig needed - recommendedProxySettings handles headers + }; + }; + + # Radicale + "radicale.binning.net" = { + enableACME = true; + forceSSL = true; + + locations."/" = { + proxyPass = "http://127.0.0.1:5232"; + # recommendedProxySettings handles most headers + extraConfig = '' + proxy_set_header X-Script-Name ""; + ''; + }; + }; + }; + }; + + # Firewall + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + # ACME/Let's Encrypt + security.acme = { + acceptTerms = true; + defaults.email = "hvanb@pm.me"; + }; +} diff --git a/resume.html b/resume.html new file mode 100644 index 0000000..cc726f1 --- /dev/null +++ b/resume.html @@ -0,0 +1,122 @@ + + + + + + Resume - WWW + + + + + +
+
+

Resume

+

Professional Experience & Skills

+
+ +
+

Summary

+

Experienced software engineer with expertise in systems engineering, cloud infrastructure, and full-stack development. Passionate about building reliable, scalable solutions using modern technologies.

+
+ +
+

Technical Skills

+
+
+

Languages

+
    +
  • Rust
  • +
  • Python
  • +
  • Go
  • +
  • JavaScript/TypeScript
  • +
  • HTML/CSS
  • +
+
+
+

Systems & Infrastructure

+
    +
  • Linux/NixOS
  • +
  • Docker
  • +
  • Nginx
  • +
  • Git
  • +
  • CI/CD
  • +
+
+
+

Frameworks & Tools

+
    +
  • Rocket (Rust)
  • +
  • React
  • +
  • Node.js
  • +
  • PostgreSQL
  • +
  • RESTful APIs
  • +
+
+
+
+ +
+

Professional Experience

+ +
+

Software Engineer

+

Example Company • 2020 - Present

+
    +
  • Designed and implemented scalable backend services using Rust and Python
  • +
  • Managed infrastructure using NixOS and containerization technologies
  • +
  • Built and maintained CI/CD pipelines for automated testing and deployment
  • +
  • Collaborated with cross-functional teams to deliver high-quality software solutions
  • +
+
+ +
+

Systems Administrator

+

Previous Company • 2018 - 2020

+
    +
  • Maintained Linux-based server infrastructure and monitoring systems
  • +
  • Automated routine tasks using shell scripting and Python
  • +
  • Implemented security best practices and access control policies
  • +
  • Provided technical support and documentation for development teams
  • +
+
+
+ +
+

Education

+
+

Bachelor of Science in Computer Science

+

University Name • 2014 - 2018

+

Focus on software engineering, algorithms, and systems programming.

+
+
+ +
+

Projects

+
+

Self-Hosted Infrastructure

+

Designed and deployed a complete self-hosted solution including:

+
    +
  • Git hosting with Forgejo
  • +
  • Web server with Nginx and SSL/TLS
  • +
  • Calendar and contacts sync with Radicale
  • +
  • Declarative configuration management with NixOS
  • +
+
+ +
+

Personal Website & Blog

+

Built a simple, reliable website using primitive technologies (HTML/CSS) focused on performance and maintainability.

+
+
+ +
+

Contact

+

Email: example@example.com

+

GitHub: forgejo.binning.net

+
+
+ + + + diff --git a/style.css b/style.css new file mode 100644 index 0000000..41b685a --- /dev/null +++ b/style.css @@ -0,0 +1,305 @@ +/* CSS Reset and Base Styles */ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; + line-height: 1.6; + color: #333; + background-color: #f5f5f5; +} + +/* Navbar Styles */ +.navbar { + background-color: #2c3e50; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); + position: sticky; + top: 0; + z-index: 1000; +} + +.nav-container { + max-width: 1200px; + margin: 0 auto; + padding: 1rem 2rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.nav-brand { + color: #fff; + text-decoration: none; + font-size: 1.5rem; + font-weight: bold; +} + +.nav-brand:hover { + color: #3498db; +} + +.nav-menu { + list-style: none; + display: flex; + gap: 2rem; +} + +.nav-menu a { + color: #fff; + text-decoration: none; + font-size: 1rem; + transition: color 0.3s ease; +} + +.nav-menu a:hover { + color: #3498db; +} + +/* Main Container */ +.container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; +} + +/* Hero Section */ +.hero { + background-color: #fff; + padding: 3rem 2rem; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + margin-bottom: 2rem; + text-align: center; +} + +.hero h1 { + font-size: 2.5rem; + color: #2c3e50; + margin-bottom: 1rem; +} + +.hero p { + font-size: 1.2rem; + color: #555; +} + +/* Content Section */ +.content-section { + background-color: #fff; + padding: 2rem; + margin-bottom: 2rem; + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +.content-section h2 { + color: #2c3e50; + font-size: 2rem; + margin-bottom: 1.5rem; + border-bottom: 3px solid #3498db; + padding-bottom: 0.5rem; +} + +.contact-info p, +.genealogy-blurb p { + margin-bottom: 1rem; + line-height: 1.8; + color: #555; +} + +.contact-info strong { + color: #2c3e50; +} + +/* Footer */ +.footer { + background-color: #2c3e50; + color: #fff; + text-align: center; + padding: 2rem; + margin-top: 3rem; +} + +.footer p { + font-size: 0.9rem; +} + +/* Blog Styles */ +.section-description { + color: #666; + font-style: italic; + margin-bottom: 1.5rem; +} + +.blog-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1.5rem; + margin-top: 1.5rem; +} + +.blog-card { + background-color: #f9f9f9; + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 1.5rem; + transition: transform 0.2s ease, box-shadow 0.2s ease; + position: relative; +} + +.blog-card:hover { + transform: translateY(-4px); + box-shadow: 0 4px 12px rgba(0,0,0,0.15); +} + +.blog-card h3 { + color: #2c3e50; + margin-bottom: 0.5rem; + font-size: 1.3rem; +} + +.blog-card h3 a { + color: #2c3e50; + text-decoration: none; + transition: color 0.3s ease; +} + +.blog-card h3 a:hover { + color: #3498db; +} + +.blog-meta { + color: #999; + font-size: 0.9rem; + margin-bottom: 0.75rem; +} + +.blog-card p { + color: #555; + line-height: 1.6; +} + +.blog-card.private { + border-color: #f39c12; + background-color: #fff9f0; +} + +.private-badge { + display: inline-block; + background-color: #f39c12; + color: #fff; + padding: 0.25rem 0.75rem; + border-radius: 4px; + font-size: 0.85rem; + margin-top: 0.5rem; +} + +/* Resume Styles */ +.skills-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + margin-top: 1.5rem; +} + +.skill-category h3 { + color: #2c3e50; + margin-bottom: 1rem; + font-size: 1.2rem; + border-bottom: 2px solid #3498db; + padding-bottom: 0.5rem; +} + +.skill-category ul { + list-style: none; + padding-left: 0; +} + +.skill-category li { + padding: 0.5rem 0; + color: #555; + position: relative; + padding-left: 1.5rem; +} + +.skill-category li:before { + content: "▸"; + position: absolute; + left: 0; + color: #3498db; + font-weight: bold; +} + +.experience-item { + margin-bottom: 2rem; +} + +.experience-item:last-child { + margin-bottom: 0; +} + +.experience-item h3 { + color: #2c3e50; + font-size: 1.4rem; + margin-bottom: 0.5rem; +} + +.job-meta { + color: #999; + font-size: 0.95rem; + margin-bottom: 1rem; + font-style: italic; +} + +.experience-item ul { + margin-top: 1rem; + padding-left: 1.5rem; +} + +.experience-item li { + color: #555; + margin-bottom: 0.5rem; + line-height: 1.7; +} + +.experience-item p { + color: #555; + line-height: 1.7; +} + +/* Responsive Design */ +@media (max-width: 768px) { + .nav-container { + flex-direction: column; + gap: 1rem; + } + + .nav-menu { + flex-direction: column; + gap: 1rem; + text-align: center; + } + + .container { + padding: 1rem; + } + + .hero h1 { + font-size: 2rem; + } + + .content-section h2 { + font-size: 1.5rem; + } + + .blog-grid { + grid-template-columns: 1fr; + } + + .skills-grid { + grid-template-columns: 1fr; + } +} diff --git a/www.code-workspace b/www.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/www.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file