How to Deal with Homebrew 6.0 Asking y/N on Upgrade

How to handle Homebrew 6.0's new interactive upgrade confirmation prompts

From Homebrew 6.0 onwards, running brew upgrade or brew install asks you to confirm whether to continue. Copy ==> This action will upgrade X formulae. Proceed? [y/N] Until now it went ahead automatically, so I imagine many people were caught off guard. In this article I summarize the ways to deal with it depending on the situation. Dealing with it on the spot If you do not need to change any settings in particular, all you do is type y and press Enter when the prompt appears. [Read More]

Removing Containers and Volumes for Just One Docker Compose Project

Safely Clean Up a Single Docker Compose Project

There are plenty of occasions where you clone a repository on GitHub and bring up a Docker environment temporarily to try it out. Deleting the containers and volumes that are no longer needed after testing one by one, however, is a chore. Commands such as docker system prune are convenient, but using them also deletes containers and volumes that are not running and have nothing to do with the test, which has bitten me several times. So I wrote a script that can safely remove the Docker environment of one specific project in a single shot. [Read More]

Generating llms.txt and llms-full.txt in Hugo with Output Formats

Adding llms.txt and llms-full.txt to a Hugo blog on Cloudflare Pages

I added llms.txt , a specification that lets LLMs retrieve the information on a website efficiently, to this Hugo blog. Environment Hugo v0.155.2 Theme: Beautifulhugo Cloudflare Pages What llms.txt is A Markdown-format text file placed at the root of a website, proposed at llmstxt.org . Like robots.txt or sitemap.xml, it provides an overview of the site and its main links in a form that is easy for an LLM to read. There are two main kinds of file: [Read More]

Powerlevel10k to Starship: Migration Steps and Customization

How to Migrate from Powerlevel10k to Starship Prompt

A Migration Guide from Powerlevel10k to Starship (2025 Edition) Introduction I migrated from Powerlevel10k, which I had used for years, to Starship. In this article I summarize the differences between the two, recent developments, the migration procedure, and how to customize it. Powerlevel10k vs Starship Powerlevel10k Features: A prompt theme for Zsh only Extremely fast startup time (under 10ms) Beginner-friendly setup through a configuration wizard (p10k configure) More than 10 built-in themes Advanced customization is possible Drawbacks: [Read More]

Handy Ways to Use Miniflux: Bookmarklet and Mobile App Integration

Efficient Miniflux Usage: Bookmarklet and Mobile App Integration

In a previous post I covered building “Miniflux”, an RSS reader you can run yourself. Its appeal is that it is simple and fast, but there are ways to make the day-to-day work of “registering feeds” and “reading on mobile” even more convenient. This time I explain the combination that is still the strongest as of 2026: registering feeds at blazing speed from a PC browser with the bookmarklet, and setting up synced reading in “NetNewsWire”, the popular iPhone app. [Read More]

Self-Hosting Miniflux with Docker Compose and Traefik

Deploy Miniflux with Traefik and Docker Compose: Complete Setup Guide

Up to now I had been self-hosting RSS with FreshRSS, but since Miniflux is lightweight and can integrate with all sorts of external services, I migrated to it.

I am building it with Docker again this time, and I am writing it up on the following assumptions.

Environment

  • My own domain (already registered with Cloudflare)
  • Network: traefik-network (external)
  • CertResolver: cloudflare
  • entryPoints: web (80), websecure (443)

docker-compose.yml

services:
  miniflux:
    image: miniflux/miniflux:latest
    container_name: miniflux
    restart: always
    depends_on:
      db:
        condition: service_healthy
    environment:
      - DATABASE_URL=postgres://miniflux:${DB_PASSWORD}@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=${ADMIN_USERNAME}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD}
      - BASE_URL=https://${MINIFLUX_DOMAIN}
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=traefik-network"
      - "traefik.http.routers.miniflux.rule=Host(`${MINIFLUX_DOMAIN}`)"
      - "traefik.http.routers.miniflux.entrypoints=websecure"
      - "traefik.http.routers.miniflux.tls=true"
      - "traefik.http.routers.miniflux.tls.certresolver=cloudflare"
      - "traefik.http.services.miniflux.loadbalancer.server.port=8080"
    networks:
      - traefik-network
      - miniflux-internal
    healthcheck:
      test: ["CMD", "/usr/bin/miniflux", "-healthcheck", "auto"]
      interval: 10s
      start_period: 30s
  db:
    image: postgres:17
    container_name: miniflux-db
    restart: always
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=${DB_PASSWORD}
      - POSTGRES_DB=miniflux
    volumes:
      - miniflux-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "miniflux"]
      interval: 10s
      start_period: 30s
    networks:
      - miniflux-internal
networks:
  traefik-network:
    external: true
  miniflux-internal:
    driver: bridge
volumes:
  miniflux-db:

.env

DB_PASSWORD=your_secure_db_password
ADMIN_USERNAME=admin
ADMIN_PASSWORD=your_secure_admin_password
MINIFLUX_DOMAIN=rss.your-domain.com

Starting it up

docker compose up -d

Building Miniflux safely with Traefik + Docker Compose

  • PostgreSQL: the official documentation uses Postgres 18, but it is still beta, so I use 17
  • Network isolation: the DB is connected only to miniflux-internal, so it cannot be reached from outside
  • Traefik integration: the miniflux container is connected to traefik-network, and the routing is configured with labels
  • Ports: miniflux starts on 8080 by default, so there is no need to publish a port to the host (Traefik handles it)

Securing the Vaultwarden ADMIN_TOKEN with an Argon2 Hash in Docker

Run Vaultwarden with Argon2-Hashed ADMIN_TOKEN in Docker

Making the Vaultwarden ADMIN_TOKEN secure with an Argon2 hash Introduction When you open the Vaultwarden admin page, the following warning is sometimes displayed. Copy You are using a plain text `ADMIN_TOKEN` which is insecure. Please generate a secure Argon2 PHC string by using `vaultwarden hash` or `argon2`. Since Vaultwarden 1.28.0, hashing ADMIN_TOKEN with Argon2 is recommended. In this article I explain how to configure ADMIN_TOKEN securely in a Docker Compose environment. [Read More]

Why Is This Port Open? Answering It in One Command with witr

Replace manual netstat workflows with witr’s single-command answers

Introduction: the late-night “what was this port again?” problem When you run servers, you repeatedly end up in the situation where you see an alert in the middle of the night, SSH into the machine, and think “what is listening on this port again?” Until now I combined netstat / ss / lsof / nmap / systemctl / docker ps and worked out the identity and the origin of the process by hand. Recently I started using a CLI tool called witr (Why is this running), and because it explains in a single command even why a process exists, my investigation flow has changed considerably. [Read More]

Why sudo Loses Your PATH on Linux and How to Keep It

How to keep your PATH when using sudo on Linux

When you use the sudo command on Linux, the PATH you configured as a normal user is not applied and you can end up with “command not found”. This happens especially often when you try to run a command inside Linuxbrew (Homebrew) with sudo and the command cannot be found. This article explains how to carry your PATH environment variable over into sudo. Why PATH changes under sudo For security reasons, sudo resets environment variables by default. [Read More]

Making Hugo Post List Summaries Plain Text with plainify

Removing HTML tags from article summaries in Hugo using plainify

The summary display in the article list on the top page was being shown with the HTML notation still left in it, which felt wrong, so I fixed it ↓

Stripping the HTML also looks better for SEO, so I made the following change

layouts/partials/post_preview.html

<article class="post-preview">
    <a href="{{ .Permalink }}">
        <h2 class="post-title">{{ .Title }}</h2>
        {{ if .Params.subtitle }}
        <h3 class="post-subtitle">
            {{ .Params.subtitle }}
        </h3>
        {{ end }}
        {{ if .Params.image }}
        <img src="{{ .Params.image }}" alt="{{ .Title }}" class="img-title" />
        {{ end }}
        {{ if .Params.video }}
        <video loop autoplay muted playsinline class="img-title">
            <source src="{{ .Params.video }}">
        </video>
        {{ end }}
    </a>

    <p class="post-meta">
        {{ partial "post_meta.html" . }}
    </p>
    <div class="post-entry">
        {{ if or (.Truncated) (.Params.summary) }}
        {{ .Summary | plainify }}
        <a href="{{ .Permalink }}" class="post-read-more">[{{ i18n "readMore" }}]</a>
        {{ else }}
        {{ .Content }}
        {{ end }}
    </div>

    {{ if .Params.tags }}
    <div class="blog-tags">
        {{ range .Params.tags }}
       <a href="{{"tags" | absLangURL}}/{{ . | urlize }}/">{{ . }}</a>&nbsp;
        {{ end }} 
    </div>
    {{ end }}

</article>