Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b4434b8
feat(umbrel): add headless seeder daemon, axum web server, and umbrel…
borocode Aug 22, 2026
711483e
ci: add GitHub Actions workflow to build and publish multi-arch Docke…
borocode Aug 22, 2026
39d7c7c
fix(docker): copy full src-tauri directory for tauri-build in Dockerf…
borocode Aug 22, 2026
ca5fb3c
fix(docker): upgrade rust-builder to rust:1-bookworm for Rust 2024 ed…
borocode Aug 22, 2026
9cefe4e
ci: optimize workflow to build linux/amd64 natively (under 2m)
borocode Aug 22, 2026
98b50d8
ci: switch to runs-on: self-hosted for local 32-core runner
borocode Aug 22, 2026
ed0808b
ci: enable multi-arch linux/amd64,linux/arm64 on self-hosted runner
borocode Aug 22, 2026
ffef1b5
ci: use docker-container driver for multi-arch buildx push
borocode Aug 22, 2026
05690bf
fix(docker): remove heavy unused WebKit GUI dependencies from headles…
borocode Aug 22, 2026
d54c055
ci: run multi-arch build on cloud ubuntu-latest
borocode Aug 22, 2026
0d6d4a1
ci: use standard buildx builder on ubuntu-latest
borocode Aug 22, 2026
20c9633
fix(docker): restore libwebkit2gtk-4.1-dev for tauri-sys crate depend…
borocode Aug 22, 2026
8f89c94
ci: switch to self-hosted runner for local build
borocode Aug 22, 2026
a49ab7d
ci: publish multi-arch on ubuntu-latest cloud runner
borocode Aug 22, 2026
ed41f04
ci: execute multi-arch build on local 32-core self-hosted runner
borocode Aug 22, 2026
2c67e11
ci: point setup-buildx-action to mybuilder docker-container builder
borocode Aug 22, 2026
d097a7d
fix(headless): support headless key persistence fallback and include …
borocode Aug 23, 2026
72f0b03
fix(docker): install full GTK/WebKit runtime stack in runtime stage
borocode Aug 23, 2026
739af71
fix(ci): force docker-container builder for multi-platform builds
borocode Aug 23, 2026
72fe104
fix(ci): pass builder explicitly to build-push-action
borocode Aug 23, 2026
dd7c9a8
fix(ci): move multi-arch build to hosted ubuntu runner
borocode Aug 23, 2026
f591b5c
docs(readme): clarify Umbrel port, add fork additions/removals + upda…
borocode Aug 23, 2026
18030cd
feat: sync upstream lnbits/napstr 0.1.4 + headless daemon compatibility
borocode Aug 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Build and Publish Napstr Umbrel Docker Image

on:
push:
branches: [ "main", "feat/umbrel-headless-daemon" ]
tags: [ 'v*.*.*' ]
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository_owner }}/napstr-umbrel

jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=latest,enable=true
type=ref,event=branch
type=semver,pattern={{version}}

- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.umbrel
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
67 changes: 67 additions & 0 deletions Dockerfile.umbrel
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# syntax=docker/dockerfile:1

# Stage 1: Build Svelte 5 Frontend
FROM node:22-alpine AS frontend-builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Build Rust Headless Daemon
FROM rust:1-bookworm AS rust-builder
WORKDIR /usr/src/napstr
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
libasound2-dev \
libwebkit2gtk-4.1-dev \
build-essential \
curl \
&& rm -rf /var/lib/apt/lists/*

COPY src-tauri ./src-tauri
WORKDIR /usr/src/napstr/src-tauri

RUN cargo build --release --bin napstr-daemon

# Stage 3: Minimal Runtime
FROM debian:bookworm-slim
LABEL org.opencontainers.image.title="Napstr Umbrel" \
org.opencontainers.image.description="Sovereign P2P Nostr & Tor audio seeder and web player" \
org.opencontainers.image.source="https://github.com/lnbits/napstr"

RUN apt-get update && apt-get install -y \
tor \
ca-certificates \
libasound2 \
libdbus-1-3 \
libwebkit2gtk-4.1-0 \
libgtk-3-0 \
libsoup-3.0-0 \
libjavascriptcoregtk-4.1-0 \
curl \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app

# Copy compiled frontend static assets
COPY --from=frontend-builder /app/build /app/build

# Copy compiled backend daemon binary
COPY --from=rust-builder /usr/src/napstr/src-tauri/target/release/napstr-daemon /usr/local/bin/napstr-daemon

ENV PORT=30421 \
HOST=0.0.0.0 \
DATA_DIR=/data \
MUSIC_DIR=/music \
STATIC_DIR=/app/build

VOLUME ["/data", "/music"]

EXPOSE 30421

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:30421/api/version || exit 1

ENTRYPOINT ["/usr/local/bin/napstr-daemon"]
129 changes: 95 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,114 @@
<img width="300" height="100" alt="napstr-logo-small" src="https://github.com/user-attachments/assets/83c9ccea-3241-4fce-a7cf-16c83629484b" />
# 🧅 Napstr for Umbrel & Community App Store

<img height="400" alt="image" src="https://github.com/user-attachments/assets/95b4d9f8-a844-49e1-ba9a-6dd003c8acd3" />
[![Umbrel OS](https://img.shields.io/badge/Umbrel-Community%20App-00ff66?style=for-the-badge&logo=docker)](https://umbrel.com)
[![Architecture](https://img.shields.io/badge/Arch-amd64%20%7C%20arm64-blue?style=for-the-badge)](https://github.com/borocode/napstr-umbrel)
[![License](https://img.shields.io/badge/License-MIT-black?style=for-the-badge)](LICENSE)

Napstr uses Nostr for discovery and Tor for private file sharing.
Run a sovereign, self-hosted **P2P music library & streaming node** directly on your **Umbrel server** (Raspberry Pi 4/5 or x86_64 Home Server). Napstr uses **Nostr** for discovery and **Tor** for private, lossless file transfer — no central server, no IP leaks, your catalogue published to the decentralized swarm. This repository is an **Umbrel community port** of [`lnbits/napstr`](https://github.com/lnbits/napstr), packaged and CI-hardened by [Boro Labs](https://github.com/borocode).

https://napstr.net
<img height="400" alt="napstr-ui" src="https://github.com/user-attachments/assets/95b4d9f8-a844-49e1-ba9a-6dd003c8acd3" />

## Build your own Napstr!
---

See the complete [Napstr protocol specification](PROTOCOL.md) for everything
needed to build an interoperable client.
## ⚠️ Read This Before You "Update"

## Build from source
The in-app store may show **"New release 0.1.4 available."** That version comes from **upstream** `lnbits/napstr` — **not** from this Umbrel package.

Install [Node.js](https://nodejs.org/), [Rust](https://rustup.rs/), and the
[Tauri prerequisites for your OS](https://v2.tauri.app/start/prerequisites/),
then:
- This port's last tagged build is `v0.1.2`; the running image is the `dd7c9a8` CI build (version string `0.1.0`).
- Upstream 0.1.4 is a **different binary** with different packaging. Installing it through the Umbrel updater will **overwrite tonight's working deployment** and drop the runtime fixes listed below.
- **Do not blind-update.** If you want upstream 0.1.4, diff it, confirm the Dockerfile still builds clean against it (our runtime-lib fix must survive), then let CI rebuild. Same closed-loop posture as everything else here.

```bash
git clone https://github.com/lnbits/napstr.git
cd napstr
npm ci
npm run desktop
```
---

Development builds use `NAPSTR_TOR_PATH` when set, then a bundled Tor binary, then `tor` on `PATH`.
## 🌟 Features

On macOS, install Tor with Homebrew and start Napstr with:
- **1-Click Umbrel Deployment:** Pre-configured Docker orchestration (`docker-compose.yml` + `umbrel-app.yml`) with persistent state at `/data` and your music library mounted at `/music`.
- **Sovereign P2P Stack:** Nostr (Kind 30421 catalogues, Kind 30422 availability heartbeats, NIP-17 private negotiation) for discovery + Tor v3 onion services for transfer — no direct-IP fallback, no central server.
- **Web UI + Trollbox:** Built-in Svelte player and live NIP-C7 chat, exposed via Umbrel's app proxy on port `30421`.
- **Headless Daemon:** Runs as a server binary (no desktop/GUI session needed) — the right shape for a 24/7 Pi.
- **Multi-Architecture Support:** Native multi-stage builds for both `linux/amd64` (PC / Intel / AMD) and `linux/arm64` (Raspberry Pi 4/5), published to GHCR via hosted CI.

```bash
brew install tor
NAPSTR_TOR_PATH="$(command -v tor)" npm run desktop
```
---

## 📦 Umbrel App Store Installation

### Method 1: Add as a Community App Store (Instant 1-Click)

1. Open your **Umbrel Dashboard** (e.g. `http://umbrel.local`).
2. Navigate to **App Store** → Click the **Three Dots (⋮)** in the top right → **Community App Stores**.
3. Paste this repository URL:
```text
https://github.com/borocode/napstr-umbrel
```
4. Click **Add**. **Napstr** will appear in your App Store ready to install!

To create a package for your operating system with Tor included, run:
### Method 2: Manual Local Installation via SSH

```bash
npm run bundle
# 1. SSH into your Umbrel server
ssh umbrel@10.0.0.67

# 2. Create the app-data directory
mkdir -p ~/umbrel/app-data/napstr

# 3. Clone this repository
git clone https://github.com/borocode/napstr-umbrel.git temp
cp -r temp/* ~/umbrel/app-data/napstr/
rm -rf temp

# 4. Start the app via Docker Compose
cd ~/umbrel/app-data/napstr
docker compose up -d
```

Napstr automatically downloads and verifies the pinned official Tor Expert
Bundle for your platform before building.
---

## 🔧 What This Umbrel Port Changes (vs. upstream `lnbits/napstr`)

This is a **packaging fork**, not a feature fork. The daemon, web UI, Nostr/Tor logic, and protocol are upstream's. We changed only what's needed to run it as a headless, multi-arch Umbrel app.

### ➕ Additions

- **`umbrel-app.yml`** — Umbrel community-store manifest (id `napstr`, port `30421`, Media category, Tor/Nostr tagline).
- **`docker-compose.yml`** — three services: `server` (Napstr daemon + web UI), `app_proxy` (Umbrel reverse proxy), and `tor_server` (bundled Tor sidecar). Mounts `/data` (state) and `/music` (your library).
- **`Dockerfile.umbrel`** — multi-stage build: Svelte frontend → Rust `napstr-daemon` → minimal Debian runtime. Publishes a multi-arch image to GHCR.
- **Full GTK/WebKit runtime stack in the runtime image** — `libwebkit2gtk-4.1-0`, `libgtk-3-0`, `libsoup-3.0-0`, `libjavascriptcoregtk-4.1-0`, `libdbus-1-3`, `libasound2`. The `src-tauri` daemon links the WebKitGTK stack **even in headless mode**, so these are required at runtime or the container crash-loops on `error while loading shared libraries`.
- **Headless key-persistence fallback** — the daemon stores its Nostr identity in the OS credential store on desktop; in a container we fall back to a file under `DATA_DIR` so the key survives restarts.
- **Hosted CI** (`.github/workflows/docker-publish.yml`) — multi-arch build on `ubuntu-latest` (the self-hosted Windows runner couldn't do multi-platform builds).

### ➖ Removals / Divergences

- **No desktop/Tauri app** — upstream ships a `npm run desktop` Tauri GUI; this port builds and runs only the `napstr-daemon` server binary. The ~250MB of GUI-only libraries remain in the runtime image only because the daemon still links them (a future Option-B refactor would decouple and shed them).
- **No `npm run bundle` / bundled-Tor-download step** — Tor is installed via `apt` in the runtime image and run as a separate `tor_server` container, not downloaded at build time.
- **App version pinned at `0.1.0`** in `umbrel-app.yml` while upstream has moved to `0.1.4` — see the update warning above.

---

## 🌐 Network & Port Allocations

| Port | Protocol | Purpose |
| :--- | :--- | :--- |
| **`30421`** | `HTTP` | Napstr Web UI, API & daemon (via Umbrel app proxy) |
| **`9050`** | `TCP` | Tor SOCKS proxy (internal, `tor_server`) |

Music is served losslessly over ephemeral Tor v3 onion services; the web UI is reachable on your LAN through Umbrel's reverse proxy.

---

## 🛠️ Upstream Submission / Sync

To stay current with [`lnbits/napstr`](https://github.com/lnbits/napstr):

1. `git remote add upstream https://github.com/lnbits/napstr.git`
2. `git fetch upstream && git merge upstream/main`
3. Re-apply the Umbrel additions above (they live in `umbrel-app.yml`, `docker-compose.yml`, `Dockerfile.umbrel`).
4. Confirm the runtime-image WebKit/GTK libs still cover whatever `src-tauri` now links, then let CI rebuild.

For official [`getumbrel/umbrel-apps`](https://github.com/getumbrel/umbrel-apps) submission: copy the `napstr/` package directory into your fork and open a PR — same path as `octra-umbrel`.

## Implemented architecture
---

- On first launch, Napstr creates a Nostr identity and securely stores its private key using your operating system's credential store.
- Nostr publishes the searchable catalogue, live seeders, NIP-C7 trollbox, and per-track discussions; NIP-17 handles private download negotiation.
- A bundled Tor process carries transfers without a direct-IP fallback.
- One recursively watched folder contains both downloads and shared audio.
- Files are audio-validated and identified by SHA-256. Downloads use a responsive seeder, verify the complete hash, and are available in the built-in player.
## 📜 License

Profiles and catalogue metadata are public. Requests, transfer credentials, file contents, and peer IP addresses are not published. Tor use may still be visible to an ISP.
Packaged with 🧅 by [Boro Labs](https://github.com/borocode).
Napstr core is developed by [lnbits/napstr contributors](https://github.com/lnbits/napstr).
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
version: "3.7"

services:
app_proxy:
environment:
APP_HOST: napstr_server_1
APP_PORT: 30421

server:
image: lnbits/napstr-umbrel:v0.1.0
restart: on-failure
stop_grace_period: 30s
environment:
- PORT=30421
- HOST=0.0.0.0
- DATA_DIR=/data
- MUSIC_DIR=/music
- STATIC_DIR=/app/build
- RUST_LOG=info
volumes:
- ${APP_DATA_DIR}/data:/data
- ${UMBREL_ROOT}/data/storage/downloads/music:/music:rw
ports:
- "30421:30421"
Loading