Categories
Uncategorized

DNSSEC wasn’t worth it

In reply to Calling Time on DNSSEC? by Geoff Huston.

[… we] estimate that DNSSEC validation is performed around 1% of the time, given the DNS query profile of today’s data

I run my own authoritative nameservers and have had a slight nagging feeling that I should’ve enabled DNSSEC years ago. It’s been on my perpetual to-do list but I’ve never gotten around to it. I’ve definitely caused some outages trying to get DNSSEC to work.

Came across this article and it confirms that my procrastination was pretty OK in this specific case.

Categories
Uncategorized

Bluesky PDS Without Docker

Here’s how I got a self-hosted PDS (personal data server) running without docker.

This can be useful if you want to run the PDS on an existing machine or just don’t like docker. I came up with these steps by emulating what the installer script does.

My setup uses nginx and a wildcard TLS cert for my PDS domain.

Get the code

Clone the PDS repo

$ git clone https://github.com/bluesky-social/pds

Set up nginx

I use certbot to issue wildcard certs for my domains. See my wildcard cert script here. Note that you will need to set up credentials for your nameservers. I’m not aware of a way in nginx to issue certs on-demand like the example caddy config does.

Here’s my nginx config for the PDS.

server {
listen 80;
server_name hellthread.pro *.hellthread.pro;
return 302 https://$host$request_uri;
}

server {
listen 443 ssl http2;
server_name hellthread.pro *.hellthread.pro;
ssl_certificate /etc/letsencrypt/live/hellthread.pro/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hellthread.pro/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

location / {
include proxy_params;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:3002;
}
}

Configure your .env file

Adjust the top 4 options, filling in your domain and generating keys with the following commands:

Use this for the JWT_SECRET:

$ openssl rand --hex 16

Use this twice to generate the admin password and rotation key:

$ openssl ecparam --name secp256k1 --genkey --noout --outform DER | tail --bytes=+8 | head --bytes=32 | xxd --plain --cols 32
PDS_HOSTNAME="your domain here"
PDS_JWT_SECRET="generated secret"
PDS_ADMIN_PASSWORD="generated key"
PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX="another generated key"

PDS_DATA_DIRECTORY=./data
PDS_BLOBSTORE_DISK_LOCATION=./data/blocks
PDS_DID_PLC_URL=https://plc.directory
PDS_BSKY_APP_VIEW_URL=https://api.bsky.app
PDS_BSKY_APP_VIEW_DID=did:web:api.bsky.app
PDS_REPORT_SERVICE_URL=https://mod.bsky.app
PDS_REPORT_SERVICE_DID=did:plc:ar7c4by46qjdydhdevvrndac
PDS_CRAWLERS=https://bsky.network
LOG_ENABLED=true
NODE_ENV=production
PDS_PORT=3002

Run the PDS

Be sure to install the dependencies:

$ cd service
$ pnpm install --production --frozen-lockfile
$ mkdir -p data/blocks

This is the systemd setup I use to run the PDS. Add your own user unit with the following steps:

$ mkdir -p ~/.config/systemd/user
$ $EDITOR ~/.config/systemd/user/pds.service
# copy in the example below and adjust as needed
$ systemctl --user daemon-reload
$ systemctl --user enable --now pds

pds.service:

[Unit]
Description=atproto personal data server

[Service]
WorkingDirectory=/home/ben/workspace/pds/service
ExecStart=/usr/bin/node --enable-source-maps index.js
Restart=on-failure
EnvironmentFile=/home/ben/workspace/pds/service/.env

[Install]
WantedBy=default.target

View the logs from journalctl like this:

$ journalctl --user --output=cat --follow --unit pds | jq

You can run the pdsadmin commands by setting the PDS_ENV_FILE variable like this:

ben@odin ~/w/p/pdsadmin (main)> PDS_ENV_FILE=../service/.env bash account.sh list
Handle Email DID
ben.hellthread.pro ben@hellthread.pro did:plc:g5isluhi3wkw557ucarjgtgy

Update

To update your PDS, use git pull in the directory you cloned it in. Then update dependencies in the service subdirectory and restart the unit:

$ cd pds
$ git pull
$ cd service
$ pnpm install --production --frozen-lockfile
$ systemctl --user restart pds
Categories
Uncategorized

Uses

Haven’t written anything here this year yet. Here’s my uses page!

Hardware

My desktop is a custom build that I put together about a year ago (Jan 2023). Here’s the part list on pcpartpicker. It’s super beefy and runs any- and everything with no complaints. Getting to this point was a little painful as the graphics card I bought was open box from Micro Center. After two RMAs, MSI ended up sending me a brand new card.

Important Specs:

  • i9-13900k
  • RTX 4080
  • 64 GB RAM

For a laptop I have a Framework 13. I’ve been super happy with that as an on-the-go device.

My phone is a Pixel 6a. It does the trick, but I’m still angry they removed the headphone jack.

I have a random collection of old laptops and desktops that I’m using as a home proxmox cluster. This site is hosted on one of the computers on that rack.

any homelab folks out there?feeling glad that electricity is relatively cheap here

ben (@benharr.is) 2023-05-15T18:13:12.830Z

For servers, I’m not even sure at this point. I think my wikipage is up to date.

Software

You can find my dotfiles here.

I use Firefox as my browser on all my devices.

I do email in Thunderbird on desktop, and Aqua Mail on my phone.

Most days, I’ll boot into windows 11 on my desktop to remote into my $dayjob development VM (the VMware remote client runs better on windows). I also have a linux dual-boot setup but I hardly bother rebooting to switch. I’ve been playing videogames quite a bit lately and haven’t taken the time to set up linux gaming on the other drive.

My laptop is running Fedora and I’m currently running KDE. GNOME is also fine. Use what you like 🙂

Text editor is vim and/or sublime text. I use Visual Studio and Jetbrains Rider for the C# I do at work.

I use fish shell as my main interactive shell, and some of the most common tools I use are ripgrep, fzf, and a bunch of aliases and shell scripts I’ve built up over the years.

For IRC, I use WeeChat. I’ve written previously about my setup. I use weechat-android on my phone to keep up to date.

Password manager is KeepassXC, and keepassdx on android. I use Syncthing for my files, including my keepass db file, and all the associated files in my pubdir (separate synced dirs).

My phone number is on jmp.chat, so I use XMPP to send and receive SMS. I run the cheogram client on my phone to integrate with the system dialer. On desktop, I tend to SMS from my weechat via bitlbee.

My font of choice is Berkeley Mono, an absolutely fantastic font. Runners up are Input Mono and Jetbrains Mono.

This site is WordPress, but it was previously in several different incarnations, starting from a very old WordPress site, then I switched at some point to bashblog. That grew tiring to deal with once you have more than a handful of posts. I switched to hugo, which I also wrote about. I guess I’m more of a GUI guy than I thought because I ended up going back to WordPress at some point last year.

Since I got deep into pinball over the last couple years, I use Match Play to run the two weekly tournaments here in TC. The tcpinball.org site is also WordPress, and I use the Jetpack plugin to publish new posts on the various social media pages we have for that.

Categories
Uncategorized

Keep it Simple

I run two weekly pinball tournaments here in Traverse City (https://tcpinball.org/) which we submit to the IFPA for global rankings.

The IFPA charges a $1 per player fee to be “sanctioned”. This fee is generously sponsored by each location that we run tournaments at. Thinking it’d be easy enough to pull back the player counts later on, I put the fee payments on my credit card and figured I’d get reimbursed later on.

This is what the stats page shows on IFPA, which is not useful to me, but it shows I’ve paid $568 as of this date in fees. I need to know how much each location owes me.

I spent probably 4 hours yesterday digging through the API docs for matchplay and the IFPA directly trying to get a count of players by location.

I ended up writing some code which didn’t quite solve it either. The list of tournaments that it gives back doesn’t include the player count, meaning I have to make another API call to get the player details for each tournament. I got rate-limited almost immediately just testing it.

While the data I need might not be accessible via the APIs, it’s right here on my TD page in a nice little table. Queue another hour of trying to parse the HTML with several different tools.

The brain blast came as I was eating dinner. Stop trying to parse it and just paste it into a spreadsheet. Works immediately. Save as a CSV and import to a sqlite db.

sqlite> .mode csv
sqlite> .import ifpa.csv ifpa
sqlite> select sum(players) from ifpa where tournament like '%coin slot%';
436
sqlite> select sum(players) from ifpa where tournament like '%right brain%';
148

I could’ve figured out how to match this up with a calculated column in the spreadsheet but the important feature there was just parsing the HTML from my clipboard.

Major props to spreadsheets and sqlite yet again!

Categories
Uncategorized

WordPress block theme fragment offset

I just solved a slight visual bug on a wordpress site (tcpinball.org) with id permalinks.

I recently added made the site header sticky on there, which started covering the heading you jumped to when clicking a fragment id.

Here’s the solution:

[id] {
    scroll-margin-top: 80px;
}

You can add this CSS snippet in the block editor with the “Additional CSS” option in the global styles panel.

Easy fix without editing any theme or plugin files!

Categories
Uncategorized

Phoenix Forum

Inspired by oodsnet, (and my pull request to add darkmode), I started to create my own tilde.team fork (now forum.tilde.team).

The first step was to switch out the css to the tilde.team standard and update the classes for bootstrap. Once I got it going and integrated with the tilde.team linux auth service, I asked other tildeans for input and suggestions.

~micaiah was interested in helping, but also wanted to learn a new language and/or framework, so we decided to start over, recreating the entire forum with elixir/phoenix. We’d discussed elixir previously, but never had a convincing use case to force us to learn it.

The project is live, with the source code on github.

The thing that I’m most impressed with is the speed of the erlang runtime 😀

Give it a look, and join the tilde.team if you want to come hang out!

Update: This didn’t get much use at the time and I didn’t want to maintain it any longer. Source code is archived on tildegit.

Categories
Uncategorized

Why I chose Silex for this website

UPDATE: this is a very old post imported from my old site… I’m including it for historical purposes. deployed version and the source for it

This is an introduction to my choice of framework in building this website.

Several options I considered for my website:

  • Django
    • Django’s opinionated Model model with its strong database ties seemed a bit much for a relatively static site
    • It’s huge and unnecessarily complicated for a simple website
    • It would be a great learning experience in Python
  • Vanilla PHP
    • I have a lot of experience in vanilla PHP at my internship at Northern Michigan University working in the Information Services department where I develop web applications for internal use.
    • I often find myself frustrated with PHP’s quirkiness and wouldn’t learn new material if I used this for my personal website.
  • Silex
    • This is a micro-framework built using components of the much larger Symfony framework.
    • I discovered Silex in Heroku’s PHP deployment guide where I noticed that it was small enough to not draw unneeded overhead and extensible enough for my website to grow as it needed.

I opted to go with Silex. The source code is available here for your perusal.

I have gone through many iterations of this site. The first version was simply a clone of the homepage that I have on my university’s computer science department server. This wasn’t a very useful homepage as many of the projects that I wanted to show in a portfolio were tied to a database on that server.

I eventually moved towards a one-page style layout (in this commit) where the links in the navbar would scroll the page to pre-defined regions. I then ditched the old multipage layout and at this point I discovered Grav. After difficulties integrating Grav within my app (read more here), I decided to roll my own blogging solution modeled after Grav’s markdown content system.

I included a YAML Front Matter + Markdown Parser and used that to define the metadata for a blogpost.

There is still much to do (post sort order, paging, tagging, etc), but I appreciate the experience that I have gained in building this blogging system.

Categories
Uncategorized

Heroku with Grav flat-file CMS

NOTE: this is a historical post imported from my old site.

When I started building a website (sparked by the purchase of my first personal domain name), I started looking into many different solutions to my web development process.

I had already decided that I would use a free dyno on Heroku for hosting.

As I researched additional solutions, I came upon the world of the PHP CMS (Content Management System, for the uninitiated). Just the sheer number and variety of CMS is terrifying.

The free tier for databases in Heroku felt lacking in peace of mind and ease of setup so I focused my search to the realm of the “flat-file” CMS.

I discovered Grav purely by chance. Grav claims to be fast and extensible. I was enticed by the flashy admin interface replete with responsive UI and a gorgeous built-in Markdown editor for content creation.

After a bit of configuration, I managed to deploy a Grav instance into a Heroku dyno (a rather annoying affair which involved deploying caches to Heroku and mod_rewrite rules in .htaccess).

The tricky part came when I brought the Admin Plugin into the picture. Without the Admin Plugin, you need to directly change the configurations and add content from the filesystem and then deploy that to the web. You are able, however, to use PHP’s built-in development webserver (php -S localhost:9000) to test your changes.

Once I got the Admin plugin working (don’t forget to clear your cache if you’re deploying to Heroku – or make sure that the cache directory is in your .gitignore file), I started making changes to my .yml configuration files and writing some content with the built-in Markdown editor. I was very impressed with the Admin interface. It’s very modern-feeling, while still being lightning-quick.

Then I needed to make a change that wasn’t available from the Admin interface… After the next deploy to Heroku, every change that I had made from within the Admin interface was obliterated. This is the main flaw in hosting a Grav app on Heroku. The ephemeral file system for a dyno on Heroku works just fine, but when the dyno restarts, it is regenerated to the state at the latest build. It’s important to note that dynos go down any time you push a new build and at least once a day.

Dynos restart when:

  • create a new release by deploying new code
  • change your config vars
  • change your add-ons
  • run heroku restart

I then read more about the ephemeral filesystem of Heroku dynos.

Each dyno gets its own ephemeral filesystem, with a fresh copy of the most recently deployed code. During the dyno’s lifetime its running processes can use the filesystem as a temporary scratchpad, but no files that are written are visible to processes in any other dyno and any files written will be discarded the moment the dyno is stopped or restarted. For example, this occurs any time a dyno is replaced due to application deployment and approximately once a day as part of normal dyno management.

This is a useless setup for a Grav application where everything is a file. This may sound a bit harsh, but changes to the live app will be destroyed within a day. This just means that there are two options:

  1. Ditch the Admin plugin
  1. Use a full LAMP stack locally to make changes to the files from within the Admin interface before deploying to Heroku

I chose to ditch the Admin plugin. Making changes to the project from within the filesystem in my text editor was totally acceptable.

Not long after trying to integrate a Grav app within the Silex application that is my website (rather than linking to the Grav app through a subdomain of benhh.com), I gave up Grav for my blog entirely and decided to roll my own blogging solution.