Arishawke's Homelab

Arishawke's Homelab

A browser-sized desktop about my homelab. Everything on it is curated and simulated. Nothing here is live.

About

I build and run a small homelab, and this is the tour. Take a look around!

What I build

  • a high fantasy world (Aevren)
  • a private Android calendar (Asala)
  • a color theme used everywhere (Fadetouched)
  • this desktop

Find me

This desktop is a simulation: hand-written data, a window manager built for the browser, and not one packet to the real lab. The real one is air-gapped from your browser, the way we both prefer it.

Terminal

ari@homelab~> fastfetch
/\ ari@homelab
/ \ -----------
/ \ OS:Arishawke Web Desktop x86_64
/ \ Host:Browser Tab (yours)
/ /\ \ Kernel:any modern browser
/ / \ \ Uptime:247 days, 3 power cuts survived
/ /----\ \ Packages:7 (apps), 28 (services)
/ / \ \ Shell:portfolio.sh 1.0
/___/ \___\DE:KDE-Plasma-inspired
WM:Browser Compositor
Theme:Fadetouched [everywhere]
Icons:hand-drawn [svg]
Terminal:this window
CPU:yours (borrowed politely)
Memory:a few MB of your browser

Services

status: onlinemaintenanceprivatepublic

  • AdGuard Homedns and ad blockingonline
  • Caddyreverse proxyonline
  • Homepagethis dashboardonline
  • Immichphoto managementonline
  • Jellyfinmedia serveronline
  • Mealierecipe boxonline
  • Navidromemusic serveronline
  • Uptime Kumaservice monitoringonline
  • LRCGETsynced lyricsmaintenance
  • Actual Budgetbudgetingprivate
  • Backrestbackupsprivate
  • Baikalcalendar and contactsprivate
  • BentoPDFpdf toolboxprivate
  • Courierparcel intakeprivate
  • Dockhanddocker managementprivate
  • FileBrowser Quantumfile managementprivate
  • Gluetunvpn tunnelprivate
  • Kavitaebook libraryprivate
  • Komfmetadata fetcherprivate
  • OmniToolsutility beltprivate
  • Paperless-ngxdocument managementprivate
  • Scrutinydrive healthprivate
  • Shelfmarkreading trackerprivate
  • SillyTavernai chat frontendprivate
  • Suwayomimanga readerprivate
  • Syncthingfile syncprivate
  • The Stacksthe acquisitions departmentprivate
  • Forgejogit forgepublic

Projects

  • Aevren

    coming soon

    A high fantasy world: regions, bestiary, and the book that holds them.

    • Astro
    • vanilla JS
    • hand-drawn SVG
  • Asala

    stable

    A private, open-source calendar for Android. No account, no cloud.

    • Kotlin
    • Room
    • Material 3
  • A dark, earthy color theme, ported to every tool I touch.

    • OKLCH
    • design tokens
  • LuxeCafe

    stable

    A dashboard for dialing in espresso shots on the Ninja Luxe.

    • TypeScript
    • charts
  • This desktop

    active

    The site you are on: a browser window manager built by hand.

    • Astro
    • vanilla JS
    • bespoke CSS

Lab Dashboard

Machine

  • Beelink Me ProIntel N150 . 16GB LPDDR5-4800 . 1TB SSDOne box now. It does not miss being three.

Drives

  • docker1TB . SSDBoot drive. Containers and apps live here.
  • storage16TB . IronWolf Pro HDDMedia, books, whatever earns a permanent home.
  • backup16TB . IronWolf Pro HDDMirrors storage by hand. Not a backup strategy on its own.

Systems

  • Compute1 machine4 cores, 16GB RAM, no failover
  • Storage9.8 TiBof about 30 TiB raw across the SSD and two IronWolf Pros
  • Network2 VLANslab and life, firewalled apart
  • Containers28 running2 one-shots exited clean, 0 on fire
  • Backupsnightlyverified weekly, restored quarterly
  • Uptime247 days, 3 power cuts survivedthe counter resets, the lab does not

Firefox

Good evening

28 Jul 2026 at 02:23

cpu12%
memory10.4 GiB free
docker412 GB free
storage6.2 TB free
backup6.2 TB free

Core

  • Caddy

    Reverse proxy

  • AdGuard Home

    DNS and ad blocking

    7,513,697queries
    1,003,146blocked
    0filtered
    0.501 mslatency
  • Gluetun

    VPN tunnel

  • Dockhand

    Docker management

  • Uptime Kuma

    Service monitoring

    22sites up
    4sites down
    85%uptime
  • Scrutiny

    Drive health

  • Backrest

    Backups

  • Syncthing

    File sync

Media

  • Jellyfin

    Media server

    64movies
    64series
    3,545episodes
    0songs
  • Navidrome

    Music server

    0active streams
  • Suwayomi

    Manga reader

    4,095read
    7,498unread
    0downloaded
    11,593sources
  • Kavita

    Ebook library

  • Komf

    Metadata fetcher

  • LRCGET

    Synced lyrics

  • The Stacks

    The acquisitions department

    32wanted
    0queue
    235shelved
    2requests
  • Courier

    Parcel intake

    0leech
    7seed
    0 B/sdown
    0.7 MiB/sup

Library

  • Paperless-ngx

    Document management

  • Shelfmark

    Reading tracker

  • BentoPDF

    PDF toolbox

  • FileBrowser Quantum

    File management

Life

  • Immich

    Photo management

    1users
    1,712photos
    34videos
    3.6 GiBstorage
  • Mealie

    Recipe box

  • Actual Budget

    Budgeting

  • Baikal

    Calendar and contacts

Tools

  • Forgejo

    Git forge

  • OmniTools

    Utility belt

  • SillyTavern

    AI chat frontend

  • Homepage

    This dashboard

Files

/
home
ari
.bashrc
# ~/.bashrc: interactive shell bits only, batch jobs never read this
export EDITOR=nvim
export PATH="$HOME/.local/bin:$PATH"

alias ll='ls -lah'
alias gs='git status'
alias dc='docker compose'
alias stacks='cd /opt/stacks'

# the day I forget this alias is the day I start typing docker compose in full
alias dcl='docker compose logs -f'

PS1='\u@\h:\w\$ '
.gitconfig
[user]
	name = ari
	email = ari@home.lan
[core]
	editor = nvim
[init]
	defaultBranch = main
[alias]
	st = status
	co = checkout
	last = log -1 HEAD
notes.md
# notes

- scrutiny says the backup drive is approaching end of life again.
  it said that in 2025 too. still spinning.
- remember: gluetun forwards a port, the port changes, nothing downstream
  ever remembers to check.
- baikal calendar sync broke for a week and nobody noticed until a birthday
  went uncelebrated. calendars are the loneliest self hosted app.
- if paperless ever misfiles another utility bill under "correspondence:
  the void", start the sweep by hand.
- the stacks card catalog is fiction, but the shelves are not. mostly.
- reminder to self: this file, like the rest of this desktop, is decorative.
  the real notes live somewhere less browsable.
opt
stacks
core
.env
# core stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  caddy:
    image: caddy:2-alpine
    container_name: caddy
    ports:
      - "80:80/tcp"
      - "443:443/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/caddy/config:/config
      - /srv/data/core/caddy:/data
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguardhome
    ports:
      - "53:53/udp"
      - "53:53/tcp"
      - "3053:3000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/adguardhome/config:/config
      - /srv/data/core/adguardhome:/data
  dockhand:
    image: fnsys/dockhand:latest
    container_name: dockhand
    ports:
      - "8081:3000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/dockhand/config:/config
      - /srv/data/core/dockhand:/data
  uptime-kuma:
    image: louislam/uptime-kuma:1
    container_name: uptime-kuma
    ports:
      - "3001:3001/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/uptime-kuma/config:/config
      - /srv/data/core/uptime-kuma:/data
  scrutiny:
    image: ghcr.io/analogj/scrutiny:latest-omnibus
    container_name: scrutiny
    ports:
      - "8087:8080/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/scrutiny/config:/config
      - /srv/data/core/scrutiny:/data
  backrest:
    image: garethgeorge/backrest:latest
    container_name: backrest
    ports:
      - "9898:9898/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/backrest/config:/config
      - /srv/data/core/backrest:/data
  syncthing:
    image: syncthing/syncthing:latest
    container_name: syncthing
    ports:
      - "8384:8384/tcp"
      - "22000:22000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/core/syncthing/config:/config
      - /srv/data/core/syncthing:/data
downloads
.env
# downloads stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  gluetun:
    image: qmcgaw/gluetun:latest
    container_name: gluetun
    ports:
      - "8080:8080/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/downloads/gluetun/config:/config
      - /srv/data/downloads/gluetun:/data
  courier:
    image: forge.arishawke.com/lab/courier:latest
    container_name: courier
    restart: unless-stopped
    volumes:
      - /opt/stacks/downloads/courier/config:/config
      - /srv/data/downloads/courier:/data
  the-stacks:
    image: forge.arishawke.com/lab/the-stacks:latest
    container_name: the-stacks
    ports:
      - "2500:2500/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/downloads/the-stacks/config:/config
      - /srv/data/downloads/the-stacks:/data
life
.env
# life stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  paperless:
    image: ghcr.io/paperless-ngx/paperless-ngx:latest
    container_name: paperless
    ports:
      - "8000:8000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/paperless/config:/config
      - /srv/data/life/paperless:/data
  mealie:
    image: ghcr.io/mealie-recipes/mealie:latest
    container_name: mealie
    ports:
      - "9925:9000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/mealie/config:/config
      - /srv/data/life/mealie:/data
  actual-budget:
    image: actualbudget/actual-server:latest
    container_name: actual-budget
    ports:
      - "5006:5006/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/actual-budget/config:/config
      - /srv/data/life/actual-budget:/data
  baikal:
    image: ckulka/baikal:nginx
    container_name: baikal
    ports:
      - "8800:80/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/baikal/config:/config
      - /srv/data/life/baikal:/data
  shelfmark:
    image: ghcr.io/calibrain/shelfmark:latest
    container_name: shelfmark
    ports:
      - "8085:8084/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/shelfmark/config:/config
      - /srv/data/life/shelfmark:/data
  bentopdf:
    image: ghcr.io/alam00000/bentopdf-simple:latest
    container_name: bentopdf
    ports:
      - "8082:8080/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/life/bentopdf/config:/config
      - /srv/data/life/bentopdf:/data
media
.env
# media stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  jellyfin:
    image: jellyfin/jellyfin:10.10.7
    container_name: jellyfin
    ports:
      - "8096:8096/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/jellyfin/config:/config
      - /srv/data/media/jellyfin:/data
  navidrome:
    image: deluan/navidrome:latest
    container_name: navidrome
    ports:
      - "4533:4533/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/navidrome/config:/config
      - /srv/data/media/navidrome:/data
  suwayomi:
    image: ghcr.io/suwayomi/suwayomi-server:stable
    container_name: suwayomi
    ports:
      - "4567:4567/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/suwayomi/config:/config
      - /srv/data/media/suwayomi:/data
  kavita:
    image: jvmilazz0/kavita:latest
    container_name: kavita
    ports:
      - "5000:5000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/kavita/config:/config
      - /srv/data/media/kavita:/data
  komf:
    image: sndxr/komf:latest
    container_name: komf
    ports:
      - "8086:8085/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/komf/config:/config
      - /srv/data/media/komf:/data
  lrcget:
    image: gtt1229/docker-lrcget:latest
    container_name: lrcget
    ports:
      - "5800:5800/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/media/lrcget/config:/config
      - /srv/data/media/lrcget:/data
photos
.env
# photos stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  immich:
    image: ghcr.io/immich-app/immich-server:release
    container_name: immich
    ports:
      - "2283:2283/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/photos/immich/config:/config
      - /srv/data/photos/immich:/data
tools
.env
# tools stack, synthetic env only
TZ=Etc/UTC
PUID=1000
PGID=1000
compose.yaml
services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:15
    container_name: forgejo
    ports:
      - "3300:3000/tcp"
      - "2222:22/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/tools/forgejo/config:/config
      - /srv/data/tools/forgejo:/data
  filebrowser-quantum:
    image: ghcr.io/gtsteffaniak/filebrowser:latest
    container_name: filebrowser-quantum
    ports:
      - "8090:80/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/tools/filebrowser-quantum/config:/config
      - /srv/data/tools/filebrowser-quantum:/data
  omni-tools:
    image: iib0011/omni-tools:latest
    container_name: omni-tools
    ports:
      - "8092:80/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/tools/omni-tools/config:/config
      - /srv/data/tools/omni-tools:/data
  sillytavern:
    image: ghcr.io/sillytavern/sillytavern:latest
    container_name: sillytavern
    ports:
      - "8008:8000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/tools/sillytavern/config:/config
      - /srv/data/tools/sillytavern:/data
  homepage:
    image: ghcr.io/gethomepage/homepage:latest
    container_name: homepage
    ports:
      - "3000:3000/tcp"
    restart: unless-stopped
    volumes:
      - /opt/stacks/tools/homepage/config:/config
      - /srv/data/tools/homepage:/data
srv
media
Books
Movies
Music
Shows

3 items (0 folders, 3 files)This filesystem is decorative.