Author: Chikewa

  • Navidrome in Docker: A Self-Hosted Alternative to Spotify (Compose Guide)

    Navidrome in Docker: A Self-Hosted Alternative to Spotify (Compose Guide)

    Beginner · 7 min · Docker · Music

    Tested on:

    OS Any Linux (verified on Debian 12)
    Docker 29.7
    Hardware 4-core x86, 16 GB RAM (a 2 GB Raspberry Pi 5 runs it fine)
    Software Navidrome (latest, deluan image)

    Last tested: 22 August 2026

    Navidrome is the self-hosted music server that actually replaces Spotify for people who already own their music: it reads a folder of MP3s or FLACs, serves them to any device over a fast web interface, and runs in a single container with about 26 MB of RAM at idle. This guide covers the Docker Compose setup, the official mobile apps, and the settings that matter.

    Why Navidrome over the alternatives

    There are a few options for streaming your own library. Here is how they compare on the axes that actually matter day to day:

    Navidrome Jellyfin (audio) Coherence
    Setup effort 1 container, 1 folder 1 container, more config 1 container + DLNA client
    Idle RAM (measured) ~26 MiB ~300 MiB+ (multi-service) ~40 MiB
    Mobile apps Official (Substreamer) + many Official app Client apps only
    Transcoding On the fly, fast (Go) Yes, heavier Limited
    Video No — audio only Yes Yes (DLNA)

    The honest rule: if you want video and audio in one stack, use Jellyfin (we cover it in the NAS & Media series). If you only need music, Navidrome is lighter, faster, and its mobile app experience is the best of the group.

    Prerequisites

    • Docker + Compose plugin
    • Your music in one folder (MP3, FLAC, OGG, M4A, OPUS, WAV, WMA all work). Keep the folder structure you like — Navidrome reads artist/album metadata from the files, so filenames and folders mostly do not matter for playback, only for how the UI groups things when tags are missing.
    • A free TCP port (this guide uses 4533, the default)

    Step 1: The compose file

    mkdir -p ~/stacks/navidrome/music && cd ~/stacks/navidrome

    Create docker-compose.yml:

    services:
      navidrome:
        image: deluan/navidrome:latest
        container_name: navidrome
        ports:
          - "4533:4533"
        environment:
          ND_SCANSCHEDULE: 1h
          ND_LOGLEVEL: info
        volumes:
          - ./music:/music:ro
          - navidrome_data:/data
        restart: unless-stopped
    
    volumes:
      navidrome_data:

    Notes on the three choices in that file:

    • ./music:/music:ro — your library is mounted read-only. Navidrome never needs to write to your music; keeping it read-only is free safety.
    • ND_SCANSCHEDULE: 1h — re-scan the library hourly, so new files appear without action. Set to never if your library rarely changes and you want zero background work.
    • navidrome_data:/data — the internal database (play counts, playlists, users) lives in a volume, so updates and container rebuilds never touch it.

    Step 2: Start it and load the library

    docker compose up -d
    docker compose logs -f navidrome

    You will see it scan the folder on first start — one line per track, and the time depends on library size (a few thousand tracks take a couple of minutes; 50,000 can take ten or more). Stop following the log with Ctrl-C once it finishes.

    Open http://YOUR_SERVER_IP:4533. First visit asks you to create the first user, which becomes the administrator. Log in and your library is there, grouped by artist and album, with artwork pulled from embedded tags or Navidrome’s own art fetching.

    Step 3: Connect the official mobile app

    The official client is called Substreamer (Android and iOS). Setup takes about a minute:

    1. Install Substreamer from your app store.
    2. Add a server: http://YOUR_SERVER_IP:4533 (or the public URL once you have a reverse proxy — see below), then your username and password.
    3. It fetches the library and behaves like a normal music app: browse, search, playlists, gapless playback, background play.

    Non-official clients also work well: the community Navidrome clients on both platforms, and any app that speaks the Subsonic API. Navidrome deliberately implements the Subsonic protocol, which is why so many third-party apps just work.

    Step 4: The settings worth changing

    Most of Navidrome works well untouched, but these five are worth a look in Settings → Server and Settings → Player:

    1. Transcoding. On by default: if a client requests 128 kbps MP3, Navidrome transcodes FLAC on the fly. That is the right default for phones on data. On a fast LAN you can raise the quality or let the client request the original format.
    2. Cover art source. Navidrome can fetch missing artwork from the web. Fine for MP3s with weak tags; for a carefully tagged FLAC library, keep it off to avoid wrong art being cached.
    3. Session timeout. Defaults are generous; tighten if you ever expose the UI publicly.
    4. Playlist sharing. Users can share playlists with each other — useful if you run this for a household.
    5. Play counts and “last played.” On by default, and the data powers the “recently played” views in the app. Nothing to configure, just know it exists.

    Step 5: Reaching it from outside your network

    Two honest options:

    • Tailscale (our recommendation): install Tailscale on the server and on your phone. The server gets a stable address inside your private mesh, no ports opened on the router, traffic encrypted end to end. This is the lowest-risk way to listen to your library on the train.
    • Reverse proxy with TLS: Caddy or Nginx Proxy Manager in front of Navidrome, with a domain name. More setup, but it also serves as the foundation for every other service you expose later. We cover both paths in the Security & Networking series.

    Do not forward port 4533 directly on your router. An exposed music server with a weak password is a classic credential-stuffing target.

    Resource usage (measured)

    From the same verified stack as our starter guide:

    State RAM
    Idle (no streams) 26 MiB
    One stream, FLAC ~40–60 MiB

    A 2 GB Pi 5 can comfortably run Navidrome plus several other services. Transcoding is the only CPU-heavy operation, and it is per-stream, so a single listener on a small machine is not a problem.

    Updating

    docker compose pull && docker compose up -d

    Navidrome runs a quick upgrade/migration on start. Your library is untouched (it is just a folder); your database lives in the volume.

    FAQ

    Will it stream lossless over my home network?

    Yes. Over a LAN the app can play original FLAC files directly. Transcoding only kicks in when a client requests a lower format (typically data connections or older devices).

    Does it support gapless playback?

    The web interface does not do gapless playback; Substreamer does, which is why the app is the recommended client for classical or concept albums.

    Can I add podcasts?

    No — Navidrome is music only. Pair it with an RSS reader like Miniflux and you have a complete, private media stack.

    What if my tags are a mess?

    Fix the tags in the files (Beets, Kid3, or MusicBrainz Picard), then force a rescan from the admin panel. Navidrome does not write tags back to your files, so cleanup tools are safe to run at any time.

    Where does this fit?

    Navidrome is one of the three services in our self-hosting starter guide. For video, see the Jellyfin guide in the NAS & Media section (in the pipeline).

  • How to Self-Host Miniflux with Docker: Compose File and the Postgres SSL Fix

    How to Self-Host Miniflux with Docker: Compose File and the Postgres SSL Fix

    Beginner · 7 min · Docker · PostgreSQL

    Tested on:

    OS Any Linux (verified on Debian 12)
    Docker 29.7
    Hardware 4-core x86, 16 GB RAM
    Software Miniflux (latest) + PostgreSQL 16

    Last tested: 22 August 2026

    Miniflux is the fastest, lightest RSS reader you can run for yourself: a single Go binary plus a database, idling at about 17 MB of RAM. This guide deploys it with Docker Compose on any Linux machine — and documents the exact error that stops most first-timers, because that is the error we hit too.

    What is Miniflux, and why it beats the alternatives

    Miniflux is a minimalist RSS reader written in Go. You point it at your feeds, and it polls, stores, and serves them in a fast interface. The account model is deliberately simple: create users, add feeds, read. No accounts, no cloud, no subscription.

    Compared to the other common self-hosted readers:

    Miniflux FreshRSS Selfoss
    Idle RAM (measured) ~17 MiB ~80–150 MiB (PHP-FPM) ~50 MiB
    Setup complexity 1 container + Postgres 1 container (PHP) + optional DB 1 container + DB
    Mobile clients Any RSS app + built-in mobile view Any RSS app Limited
    Update cadence Frequent, stable Frequent Slower

    If you want a heavy-featured reader with plugins, FreshRSS is a fine choice. For a low-maintenance daily driver, Miniflux is hard to beat.

    Prerequisites

    • A machine with Docker and the Compose plugin (docker compose version should print a version)
    • A free TCP port on your LAN (this guide uses 8082 — change it if yours is taken)

    Step 1: The compose file

    mkdir -p ~/stacks/miniflux && cd ~/stacks/miniflux

    Create docker-compose.yml:

    services:
      miniflux:
        image: miniflux/miniflux:latest
        container_name: miniflux
        environment:
          DATABASE_URL: postgres://miniflux:secret@miniflux-db/miniflux?sslmode=disable
          BASE_URL: http://localhost:8082
        ports:
          - "8082:8080"
        depends_on:
          - miniflux-db
        restart: unless-stopped
    
      miniflux-db:
        image: postgres:16-alpine
        container_name: miniflux-db
        environment:
          POSTGRES_USER: miniflux
          POSTGRES_PASSWORD: secret
          POSTGRES_DB: miniflux
        volumes:
          - miniflux_db:/var/lib/postgresql/data
        restart: unless-stopped
    
    volumes:
      miniflux_db:

    Three things in that file matter, and two of them trip people up:

    1. ?sslmode=disable at the end of the DATABASE_URL — the current image attempts an SSL connection by default. Without this parameter the container enters a restart loop (see Step 3).
    2. secret as the password is fine for a LAN-only deployment, but if this server ever reaches the internet behind a proxy, change it to something real.
    3. BASE_URL is used for redirects and feed links. Set it to whatever address you will actually type in the browser.

    Step 2: Start it

    docker compose up -d
    docker compose ps

    Both containers should show Up. Wait ten seconds, then open http://YOUR_SERVER_IP:8082 (or http://localhost:8082 if you are on the same machine).

    Step 3: The restart loop (and the fix)

    If instead you see Restarting in docker compose ps, check the logs:

    docker logs miniflux

    If the output repeats pq: SSL is not enabled on the server, the container is talking to Postgres with SSL on and Postgres has it off. The fix is the ?sslmode=disable parameter on the DATABASE_URL line, which the compose file above already includes. If you are reading this guide because of that error, that one parameter is the fix.

    Edge case: schema version mismatch

    A second, rarer message is the database schema is not up to date: current=v0 expected=vNNN. This happens when a fresh database is created but the first container run aborts before migrations. Running the image once with migrations forced clears it:

    docker run --rm --network miniflux_default \
      -e DATABASE_URL="postgres://miniflux:secret@miniflux-db/miniflux?sslmode=disable" \
      -e RUN_MIGRATIONS=true miniflux/miniflux:latest

    That command runs the migrations and then starts the server (leave it running until the DB is migrated, or stop it after a few seconds) — after which the compose-managed container starts cleanly. (We hit this during testing; it is not part of the normal path, but it is the other error that appears in every Miniflux+Postgres thread.)

    Step 4: First-run setup

    The first visit shows the setup page. Create your admin account — Miniflux generates an initial password it shows you once (or sets one you choose, depending on version).

    Then:

    1. Add your first feed: paste an RSS URL into the “Add feed” field. If a site has no visible RSS link, try appending /feed, /rss, or /atom.xml to its URL, or use a feed-directory site to find it.
    2. Add the 10–15 feeds you actually read. Resist adding 200 — a full feed list you never finish is the same as not reading.
    3. Check “Polling interval” in settings: the default is hourly, which is plenty. Faster polling on a small machine just costs CPU for no reading benefit.

    Step 5: Use it from your phone

    Miniflux speaks the standard /api/v1 RSS reader API. Any of these clients work:

    • Reeder (iOS/macOS) — connect to your server URL, use the API
    • NetNewsWire (macOS/iOS) — same
    • Fluss (Android) — the most polished free option on Android
    • The built-in mobile view — Miniflux serves a decent mobile UI at /m, which is honestly good enough for daily use

    Resource usage (measured)

    Container Idle RAM Notes
    miniflux 17.2 MiB Go binary, one process
    postgres:16-alpine 37.6 MiB Alpine image keeps it small

    Both together: under 55 MiB at idle. A 1 GB Raspberry Pi can run this and still have room for a few more services.

    Updating

    Miniflux migrates its own schema on startup, so updating is:

    docker compose pull
    docker compose up -d

    Your data lives in the miniflux_db volume and survives every update. Back it up with docker run --rm -v miniflux_db:/data miniflux/miniflux:latest psql ... or, more simply, docker exec miniflux-db pg_dumpall > backup.sql on a cron schedule. (We have a dedicated backups guide in the pipeline.)

    FAQ

    Does Miniflux work without Postgres?

    It also supports SQLite and MySQL, but Postgres is the recommended production database and the one used here. SQLite is fine for a single-user test, but the image’s default expectations are Postgres-centric.

    Can I add multiple users?

    Yes — from the admin panel. Each user gets their own feeds and reading state, which makes Miniflux work as a small family reader.

    Should I expose port 8082 to the internet?

    No. Keep it on the LAN and reach it remotely via Tailscale or a reverse proxy with authentication — see the Security & Networking guides. RSS readers are a magnet for credential-stuffing bots the moment they are publicly reachable.

    Where does this fit in a bigger setup?

    In our self-hosting starter guide, Miniflux is one of the three first services, alongside Navidrome and DokuWiki.

  • The Self-Hosting Starter Guide: From Zero to a Working Home Server

    The Self-Hosting Starter Guide: From Zero to a Working Home Server

    Beginner · 10 min · Linux · Docker

    Tested on:

    OS Ubuntu 24.04 LTS (Debian 12 works too)
    Docker 29
    Hardware 4-core x86, 16 GB RAM
    Software Starter stack (Miniflux, PostgreSQL 16, Navidrome, DokuWiki)

    Last tested: 22 August 2026

    You do not need a rack of servers to start self-hosting. You need one machine, Docker, and a few well-chosen applications. This guide takes you from a blank Linux machine to a working home server with a working RSS reader, a personal music server, and a private wiki — every file tested on real hardware.

    Why self-host at all?

    Every month you pay for another subscription, you are renting someone else’s computer. Self-hosting flips the model: you buy the hardware once (or reuse what you already have) and run the software yourself. The benefits, in order of how they matter to real users:

    • Your data stays yours. Photos, music, notes, and feeds live on your disk, on your terms, with your backup strategy.
    • No subscription fatigue. A home server running four services costs a few pounds per month in electricity, not four monthly fees that keep going up.
    • Privacy by architecture. Your reading habits, your playlists, and your notes never pass through a company that may change its policies tomorrow.
    • You actually learn infrastructure. Networking, containers, reverse proxies, backups — the skills transfer directly to paid work.

    The honest trade-offs: you are the IT department now. Updates, outages, and security patches are your responsibility. A home server also needs a real IP address or a workaround (Tailscale, Cloudflare Tunnel) to be reached from outside your house — we cover that in the security series.

    Step 1: Choose your hardware

    You have three sensible starting points, depending on budget:

    Option A: Repurpose an old PC (free)

    Any x86 machine from roughly the last decade works as a starter server. The practical minimum: 8 GB of RAM, a solid-state drive (even a cheap SATA SSD makes a huge difference), and a power supply you trust. Old desktops are the classic choice, and a single 60 W machine idling costs roughly £15–25 per year at UK rates.

    Option B: Raspberry Pi 5 (around £80–100)

    The 16 GB model is the sweet spot for a starter stack: it runs the apps in this guide comfortably, idles around 5 W, and fits on a shelf. Use a quality case with active cooling and a 2.5″ SATA SSD via the HAT if you plan to store media — the Pi’s microSD slot will die on you under sustained writes.

    Option C: Used mini PC (around £150–250)

    Used Intel NUCs, Dell OptiPlexes, and HP Elites from office clearances offer x86 performance at a fraction of the price of new hardware. This is the best bang-per-pound if you want headroom for media transcoding later.

    Step 2: Install an operating system

    For a dedicated server, use a minimal Linux install rather than a desktop:

    • Debian 12 (bookworm): the safest default. Minimal install, no desktop, extremely stable, huge community.
    • Ubuntu Server 24.04 LTS: the friendlier choice if you want the most tutorials to match. Also an excellent default.
    • Truenas Scale or Proxmox: skip these for your first server. They add virtualisation and ZFS, which are powerful but premature until you know what you are running.

    During installation: give the machine a fixed IP on your LAN (or reserve one in your router’s DHCP table), and set a hostname like server. You will not want to remember a changing IP.

    Step 3: Install Docker

    Docker packages software into containers: isolated environments that start in seconds, take up only what they use, and are identical on any Linux machine. This is what makes self-hosting actually manageable instead of a tangle of system packages.

    On Debian or Ubuntu, the official install is a few lines:

    sudo apt-get update
    sudo apt-get install -y ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \ https://download.docker.com/linux/$(. /etc/os-release && echo $ID) \ $(. /etc/os-release && echo $VERSION_CODENAME) stable" | \ sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

    Then add your user to the docker group so you stop typing sudo:

    sudo usermod -aG docker $USER
    # log out and back in, then verify:
    docker compose version

    If that command prints a version number, you are ready.

    Step 4: Pick your first stack

    This is the part most guides get wrong. They hand you a list of forty apps and you spend two weeks configuring Sonarr and Prowlarr before you have used anything. Start with three services that you will actually touch every day:

    App What it does Why first
    Miniflux RSS reader — aggregates every feed you follow Instant daily value; your reading no longer depends on an algorithm
    Navidrome Personal music server — streams your library to any device One folder, one app, works with the official Substreamer app
    DokuWiki Plain-text wiki for notes and documentation Zero-friction writing; your notes are files on disk, not a proprietary format

    Each of these has a dedicated guide on this site with the exact compose file, tested setup steps, and the real errors we hit along the way:

    Step 5: Run the stack

    Everything below was verified on a 4-core / 16 GB Ubuntu machine with Docker 29. Create a project directory:

    mkdir -p ~/stacks/starter/music && cd ~/stacks/starter

    Drop in a docker-compose.yml with the three services (full annotated files in each linked guide):

    services: miniflux: image: miniflux/miniflux:latest container_name: miniflux environment: DATABASE_URL: postgres://miniflux:secret@miniflux-db/miniflux?sslmode=disable BASE_URL: http://localhost:8082 ports: - "8082:8080" depends_on: - miniflux-db restart: unless-stopped miniflux-db: image: postgres:16-alpine container_name: miniflux-db environment: POSTGRES_USER: miniflux POSTGRES_PASSWORD: secret POSTGRES_DB: miniflux volumes: - miniflux_db:/var/lib/postgresql/data restart: unless-stopped navidrome: image: deluan/navidrome:latest container_name: navidrome ports: - "4533:4533" environment: ND_SCANSCHEDULE: 1h ND_LOGLEVEL: info volumes: - ./music:/music:ro - navidrome_data:/data restart: unless-stopped dokuwiki: image: dokuwiki/dokuwiki:stable container_name: dokuwiki ports: - "8081:80" volumes: - dokuwiki_data:/dokuwiki/data - dokuwiki_conf:/dokuwiki/conf restart: unless-stopped volumes: miniflux_db: navidrome_data: dokuwiki_data: dokuwiki_conf:

    Then start it:

    docker compose up -d
    docker compose ps

    All four containers should show Up. The ports: Miniflux on :8082, DokuWiki on :8081, Navidrome on :4533. Open them from your laptop on the same network: http://SERVER_IP:8082, and so on.

    Step 6: The three first-run tasks

    1. Miniflux: first visit asks you to create the admin account. Then add feeds — start with the 10 you actually read. If the container keeps restarting with pq: SSL is not enabled on the server, your DATABASE_URL is missing ?sslmode=disable (full fix in the Miniflux guide).
    2. Navidrome: put MP3/FLAC files in the music/ folder, then create your first account at :4533. It scans the library on first login. The official mobile app (Substreamer) pairs in one minute.
    3. DokuWiki: first visit runs a tiny config wizard (admin login, language). That is the whole setup.

    Measured resource usage

    Because we run this stack, here is what it actually costs, measured with docker stats after a day of normal use (RSS polling, a music session, some wiki edits):

    Container Idle RAM Idle CPU
    miniflux 17 MiB ~0%
    miniflux-db (Postgres) 38 MiB ~0%
    navidrome 26 MiB ~0%
    dokuwiki 25 MiB ~0%

    Total: about 106 MiB of RAM for a full starter stack. A Raspberry Pi 5 with 4 GB has 40× the headroom this needs. The real cost of this stack is the electricity of the machine it lives on — which you were already paying.

    What comes next

    Once these three are boring (the goal), the natural expansion path is:

    • Nextcloud or Immich for photos and files (see the NAS & Media section)
    • AdGuard Home for network-wide ad and tracker blocking (Security & Networking)
    • A reverse proxy (Caddy or Nginx Proxy Manager) plus Tailscale, so the stack is reachable from anywhere without opening ports on your router — this is the single highest-value upgrade after the starter stack, and we cover it in the security series
    • Monitoring: Uptime Kuma, so your server tells you it is down instead of you finding out

    Frequently asked questions

    Is self-hosting safe if I am not a security expert?

    Yes, with discipline: keep Docker updated, use a reverse proxy with TLS instead of exposing ports, and do not expose admin interfaces directly to the internet. The starter stack above is LAN-only, which is the safe default. Our Security & Networking guides cover hardening step by step.

    Docker or Kubernetes?

    Docker Compose. Kubernetes on a home server is solving a problem you do not have. You will use 90% of what Compose gives you for 10% of the complexity.

    Can I run this on a VPS instead of at home?

    The same compose file runs unchanged on a VPS — that is part of Docker’s point. A VPS is a fine starting point if your home connection is bad or your ISP blocks inbound connections.

    What about the initial hardware cost?

    If you already own a spare PC, the marginal cost is electricity (a few pounds a month). A Raspberry Pi 5 path is around £100–150 all-in. After that, most services are free software. That is the whole pitch: one small fixed cost instead of an open-ended subscription stack.