Month: November 2023

  • Proxmox on Hetzner Setup Notes

    Installation

    Basic installation over plain debian https://pve.proxmox.com/wiki/Install_Proxmox_VE_on_Debian_12_Bookworm

    Network config

    Network configs derived from: https://community.hetzner.com/tutorials/install-and-configure-proxmox_ve

    sysctl -w net.ipv4.ip_forward=1
    sysctl -w net.ipv6.conf.all.forwarding=1

    Proxmox host /etc/network/interfaces

    This example is for the main IPv4 of 157.90.92.151 with two subnets of 157.90.196.48/28 and 162.55.142.192/28. The IPv4 gateway is derived from the existing Hetzner configs given on install.

    source /etc/network/interfaces.d/*

    auto lo
    iface lo inet loopback
    iface lo inet6 loopback

    auto enp8s0
    iface enp8s0 inet static
    address 157.90.92.151
    netmask 255.255.255.255
    pointopoint 157.90.92.129
    gateway 157.90.92.129

    iface enp8s0 inet6 static
    address 2a01:4f8:252:3e22::2
    netmask 128
    gateway fe80::1

    auto vmbr0
    iface vmbr0 inet static
    address 157.90.92.151
    netmask 255.255.255.255
    bridge_ports none
    bridge_stp off
    bridge_fd 0
    pre-up brctl addbr vmbr0
    up ip route add 157.90.196.48/28 dev vmbr0
    up ip route add 162.55.142.192/28 dev vmbr0
    down ip route del 157.90.196.48/28 dev vmbr0
    down ip route del 162.55.142.192/28 dev vmbr0
    post-down brctl delbr vmbr0

    iface vmbr0 inet6 static
    address 2a01:4f8:252:3e22::2
    netmask 64

    The important bits here are sysctl forwarding and routing our guest subnet to vmbr0.

    Also need to systemctl disable --now rpcbind.socket per Hetzner rules.

    Debian guest config

    Subnet: 157.90.196.48/28

    auto ens18
    iface ens18 inet static
    address 157.90.196.48/32
    # or address 157.90.196.X/32
    gateway 157.90.92.151

    iface ens18 inet6 static
    # in this case i'm using the same ending as ipv4
    address 2a01:4f8:252:3e22::48/64
    gateway 2a01:4f8:252:3e22::2

    /etc/apt/sources.list

    deb http://mirror.hetzner.de/debian/packages bookworm main
    deb http://mirror.hetzner.de/debian/packages bookworm-updates main
    deb http://mirror.hetzner.de/debian/packages bookworm-backports main
    deb http://mirror.hetzner.de/debian/security bookworm-security main

    deb http://security.debian.org bookworm-security main

    /etc/resolv.conf

    These are specifically Hetzner’s internal resolvers.

    nameserver 213.133.100.100
    nameserver 213.133.98.98
    nameserver 213.133.99.99
    nameserver 2a01:4f8:0:1::add:1010
    nameserver 2a01:4f8:0:1::add:9999
    nameserver 2a01:4f8:0:1::add:9898
  • We saw Vulfpeck in Brooklyn

    Great show, so much talent!

    Unfortunately, they didn’t do an encore because we went to the early show.

  • Mastodon Admin Notes

    This is the cron job that runs daily to do media and federation data cleanup:

    #!/bin/sh
    
    printf "%s: running cleanup tasks\n" "$(date)"
    RAILS_ENV=production /home/mastodon/.rbenv/shims/ruby /home/mastodon/live/bin/tootctl media remove --days=7
    RAILS_ENV=production /home/mastodon/.rbenv/shims/ruby /home/mastodon/live/bin/tootctl media remove --days=7 --remove-headers
    RAILS_ENV=production /home/mastodon/.rbenv/shims/ruby /home/mastodon/live/bin/tootctl media remove --days=7 --prune-profiles
    RAILS_ENV=production /home/mastodon/.rbenv/shims/ruby /home/mastodon/live/bin/tootctl media remove-orphans
    RAILS_ENV=production /home/mastodon/.rbenv/shims/ruby /home/mastodon/live/bin/tootctl preview_cards remove --days=30
    
    printf "%s: dumping db\n" "$(date)"
    pg_dump -Fc mastodon_production | ssh rsync "dd of=mastodon/db.dump"
    
    date
    

    This is the wrapper script I use to make sure I restart all necessary processes after updates.

    root@mastodon:~# cat /usr/local/bin/masto
    #!/bin/sh
    
    case $1 in
            start|restart|stop|status)
                    printf "%sing mastodon services\n" "$1"
                    ;;
    
            logs)
                    exec journalctl -fu mastodon-\*
                    ;;
            *)
                    printf "%s: invalid action. try logs, status, start, stop, restart.\n" "$1"
                    exit 1
                    ;;
    esac
    
    exec systemctl $1 mastodon-web \
            mastodon-streaming \
            mastodon-sidekiq@default \
            mastodon-sidekiq@pull \
            mastodon-sidekiq@push \
            mastodon-sidekiq@mailers \
            mastodon-sidekiq@scheduler \
            mastodon-sidekiq@ingress
    

    The mastodon-sidekiq@.service units were added to address queues backing up and is essentially the same as the default unit file but with the -q queue name parameter added.

  • Some good podcasts

    These are some of my favorite podcasts. Check them out if you’re so inclined.

    NameBlurbStatus
    1619examining the propaganda of american historyEnded
    20k hertzstories behind the world’s most recognizable and interesting sounds
    99% Invisiblehow design shapes our lives
    A Way With Wordsinteresting discussions on language
    The Anthropocene Reviewed2 topics rated on a 5-star scale
    Ask Me AnotherNPR trivia showEnded
    Benjamen Walker’s Theory of Everythingsome fiction and wild stories – i originally found tilde.club from this episode
    Broken Recordliner notes for the digital age with malcolm gladwell and rick rubin
    Ear Hustletales from prison shared by those inside
    Endless Threadstories from cool things found on reddit
    Everything is Aliveian chillag interviews inanimate objects
    Hello Internettwo youtubers (brady haran and cgp grey) discuss internet thingsEnded
    Invisibiliascience and stories about the invisible forces that affect and steer our livesEnded
    LeVar Burton Readslevar burton hand picks short fiction and reads it to you
    Lingthusiasma podcast that explores the hidden linguistic patterns and features of languages around the world
    On the Mediaa weekly investigation into how the media shapes our worldview
    Radiolaban exploration of science
    Reply Alla podcast about the internet that explores modern life and how to survive it: start hereEnded
    Rough Translationstories about language and interactions across the worldEnded
    The Allusionista language podcast by helen zaltzman
    The Bugleaudio newspaper for a visual world
    The Truthmovies for your ears – short audio fiction stories
    The Unmade Podcasttim and brady discuss podcast ideas that they probably won’t make
    This American Lifestories compiled for radio and podcast by wbez chicago
    Wait Wait Don’t Tell Menpr’s weekly news quiz show
  • 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!