Posts tagged: til

All posts with the tag "til"

118 posts latest post 2026-04-03
Publishing rhythm
Dec 2025 | 2 posts

I am working on using gotify cli for notifying me of nextcloud uploads and I’ll start by running the gotify cli as my user so I’ll need to be able to see the directory in the filesystem that Nextcloud stores the data in.

That folder on disk is owned by www-data (see Nextcloud permissions with ZFS and Ansible-NAS

Turns out it’s my computer and I can do what I want so I just add myself to the www-data group instead of running the gotify cli as root

Bonus

You can remove users from groups with gpasswd -d username groupname

I have tons of linting errors in my nvim config, partly because I use Lazyvim plus a set of poorly written customizations that have traveled with me for a while. I try to re-work things and right now I’ve been revisiting my developer setup. Well the LSP rrors as I’ve gone through my neovim config are ticking me off - and this was the biggest one “Undefined global: vim”. I saw vim.fn everywhere but the LSP hated it… turns out vim is a given global and you can help your lsp with this:

---@diagnostic disable: undefined-global
-- vim is a global in Neovim Lua scripts

For example:


---@diagnostic disable: undefined-global
-- vim is a global in Neovim Lua scripts
return {
  "pypeaday",
  dir = vim.fn.stdpath("config") .. "/lua/pypeaday",
  config = function()
    local daily = require("pypeaday.daily")
    vim.api.nvim_create_user_command("DailyNote", daily.check_and_open_daily_note, {})
    vim.api.nvim_create_user_command("Daily", daily.check_and_open_daily_note, {})
    vim.api.nvim_create_user_command("BackLinks", daily.find_backlinks, {})
    vim.keymap.set("n", "<leader>dn", daily.check_and_open_daily_note, { desc = "Open daily note" })
    vim.keymap.set("n", "<leader>df", daily.find_daily_files, { desc = "Find daily files" })
    vim.keymap.set("n", "<leader>dl", daily.find_backlinks, { desc = "Find backlinks" })
  end,
}

you can hexify your Nostr key when you need to sometimes which I needed to for Posts tagged: postiz (link with a thought I’m sure I have on postiz)


# /// script
# requires-python = ">=3.8"
# dependencies = [
#     "bech32",
# ]
# ///
#
import os

import bech32

# Set your nsec... key to NOSTR_PRIVATE_KEY or bake it in...
nsec_key = os.environ.get("NOSTR_PRIVATE_KEY")


def decode_nsec(nsec_key):
    hrp, data = bech32.bech32_decode(nsec_key)
    if hrp != "nsec":
        raise ValueError("Not a valid nsec key")
    decoded = bech32.convertbits(data, 5, 8, False)
    return bytes(decoded).hex()


# Example usage
raw_hex = decode_nsec(nsec_key)
print(f"Raw hex private key: {raw_hex}")

💭 slash pages

Waylon's mentioned slash pages before, but as I work on building my blog again and writing more regularly thanks to "tho

1 min

tl;dr

Copy paste - don’t rely on typing correctly…

The Issue

I use tailscale at home and generally love it. One thing I use it for is whitelisting - so I have some apps publically available and my homelab ones have DNS with SSL certs by LE but I whitelist to only my private IPs so that I can use https at home basically. However I have had a few issues with a couple apps, and I kind of chaulked it up to “network protocol this” “need to figure out that header that” but ultimately I was being lazy and the issues weren’t catastrophic… it was things like:

  1. couldn’t get to my NVR by DNS, so I’d have to use tailscale_ip:port
  2. couldn’t login with my user in jellyfin cause I lock me down to LAN only since I dont’ use a password
  3. gotify wouldn’t connect using DNS

These things aren’t huge but they are annoying and today I decided to figure it out.

Typo! #

I’m not an expert yet but I think the main problem was the CIDR block I was using in my traefik config.

This’ll shock some of you but 10.64.0.0/10 and 100.64.0.0/10 are not the same blocks!

Check your CIDRs

It’s always DNS, and even when it’s not, it’s still probably networking

I accidently chown’d -R an app directory and it totally screwed up the database folder. Luckily I zfs replicate my docker volumes to another drive even on the same host, so a quick [rsync] from /harbor/encrypted/docker/manyfold to /tank/encrypted/docker/manyfold got me back up and running since I hadn’t replicated the messed up permission set yet

Q: How to link to my rsync like a pro post?

A: Wikilinks <a href="/rsync-like-a-pro/" class="wikilink" data-title="rsync like a pro" data-description="I am moving a hefty amount of data to a new ZFS pool due to some corruption and I want to avoid using for this just to make sure I don&#39;t propagate any..." data-date="2024-12-11">rsync like a pro</a> rsync like a pro

I keep running out of space with my swap getting maxxed out… I don’t know why but U-Blue uses Zram already and apparently I can easily override the defaults:

in usr/lib/systemd/zram-generator.conf


# This config file enables a /dev/zram0 device with the default settings:
# — size — same as available RAM or 8GB, whichever is less
# — compression — most likely lzo-rle
#
# To disable, uninstall zram-generator-defaults or create empty
# /etc/systemd/zram-generator.conf file.
[zram0]
zram-size = min(ram, 8192)

And so I just made my own file in /etc/systemd/zram-generator.conf:


[zram0]
zram-size = min(ram, 16384)

TIL

Today I learned that the .info() of a pandas.DataFrame will always give you an answer, but it is wildly difficult to know how accurate it is, because it depends on the underlying data types. If everything is a NumPy Dtype, then the result you get is the amount of memory NumPy is using under the hood, which is very accurate. But as soon as you have something like a Python string in the data frame, now pandas will tell you how much memory the NumPy data types are using, and it will give you some quick estimate of how much memory space the Python string types are using because numpy is just storing a pointer to that data in memory, but this is far less accurate because it doesn’t actually know what the strings are.

Memory Usage Deep or True #

To get an honest answer about a DataFrame’s memory usage, you need to pass memory_usage='deep' to the .info() method.

# This is the default
In [50]: df.info(memory_usage=True)
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   s1      10 non-null     int64 
 1   s2      10 non-null     int64 
 2   s3      10 non-null     object
dtypes: int64(2), object(1)
memory usage: 372.0+ bytes

Notice that the memory usage has a + in it? You can force a deeper analysis by passing memory_usage='deep'

In [51]: df.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 10 entries, 0 to 9
Data columns (total 3 columns):
 #   Column  Non-Null Count  Dtype 
---  ------  --------------  ----- 
 0   s1      10 non-null     int64 
 1   s2      10 non-null     int64 
 2   s3      10 non-null     object
dtypes: int64(2), object(1)
memory usage: 792.0 bytes

I heard about SearXNG on a couple podcasts and saw it trending on GitHub several times before I finally decided to stand it up. I used it transparently when trying out khoj, a self-hosted AI LLM agent playground kind of a thing, but I’ve also been messing around with Open-WebUI to have a self-hosted ChatGPT-like experience. I don’t know if SearchXNG used to be harder to set up, but it was pretty simple with a Docker Compose up and a couple configuration options given my personal homelab setup. Using it feels very nice.

services:
  redis:
    container_name: redis
    image: docker.io/valkey/valkey:8-alpine
    command: valkey-server --save 30 1 --loglevel warning
    restart: unless-stopped
    volumes:
      - ./data/redis:/data
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

  searxng:
    container_name: searxng
    image: docker.io/searxng/searxng:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    volumes:
      - ./data/searxng:/etc/searxng:rw
    env_file: .env
    environment:
      # - SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/
      - UWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4}
      - UWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4}
    logging:
      driver: "json-file"
      options:
        max-size: "1m"
        max-file: "1"

I love the self-hosted aspect. I love not seeing any ads on my search results. I did a few searches where I know what results to expect and it did okay. It is good right now at filtering out garbage in my results.

SearXNG

So I look forward to tweaking it and using it as a search backend with open web UI. Next on my list is having enough resources to run Ollama and a stable diffusion generator at the same time and have image generation working through open web UI.

It’s easy to configure push notifications through Gotify from Grafana by setting up a generic Webhook Alerting Contact Point…

The parameters are:

  • HTTP Method: POST
  • URL: http:///message
  • Authentication is done with an app token generated from Gotify, and you put it in Authorization Header: Credentials in the Grafana configuration

See image