Add Docker and Nix packaging for the node
server/docker/: multi-stage image (rust:1-slim build, trixie runtime) with all four binaries plus the pinned yggdrasil 0.5.14 .deb (sha256-verified, fetched from the official release), a compose example per household (host network, NET_ADMIN, /dev/net/tun, init: true), a German-commented node.toml.example (safe default: leech mode) and a README covering privileges, two-household wiring, leech mode and the kill switch. Image build and smoke tests verified locally with docker 29.8.1. flake.nix: builds the workspace as one spidernet package via rustPlatform.buildRustPackage (cargoLock against the committed Cargo.lock) plus an experimental NixOS module; written without a local Nix and marked accordingly.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
#
|
||||
# SpiderNet node container image (multi-stage).
|
||||
#
|
||||
# NO WARRANTY — SpiderNet is provided "as is", without warranty of any kind
|
||||
# (AGPL-3.0, sections 15/16). Running a node is entirely at the operator's
|
||||
# own responsibility, including all traffic sent and received with it.
|
||||
#
|
||||
# Build context is the `server/` directory (see docker-compose.yml):
|
||||
# docker build -t spidernet-node -f docker/Dockerfile ..
|
||||
|
||||
# --- Stage 1: build the Rust workspace --------------------------------------
|
||||
|
||||
FROM rust:1-slim AS build
|
||||
|
||||
WORKDIR /server
|
||||
|
||||
COPY Cargo.toml Cargo.lock ./
|
||||
COPY crates ./crates
|
||||
|
||||
# --locked: the build must match the committed Cargo.lock exactly.
|
||||
RUN cargo build --release --locked --workspace
|
||||
|
||||
# --- Stage 2: runtime --------------------------------------------------------
|
||||
|
||||
# trixie, not bookworm: rust:1-slim is trixie-based, and binaries built
|
||||
# against its glibc (2.41) need a matching runtime (bookworm only has 2.36).
|
||||
FROM debian:trixie-slim
|
||||
|
||||
# Yggdrasil sidecar: current stable release of yggdrasil-go. Release v0.5.14
|
||||
# ships official .deb packages (no raw tarballs). Binary inside: /usr/bin/yggdrasil.
|
||||
# Digests from https://api.github.com/repos/yggdrasil-network/yggdrasil-go/releases/latest
|
||||
ARG YGGDRASIL_VERSION=0.5.14
|
||||
ARG TARGETARCH
|
||||
|
||||
# ca-certificates: TLS for sn-exit/sn-fetch (rustls) and tls:// peers.
|
||||
# curl is only needed to fetch the yggdrasil .deb and is removed again.
|
||||
# TARGETARCH is only set by BuildKit; fall back to the host arch otherwise
|
||||
# (both use the same amd64/arm64 naming as the yggdrasil .deb assets).
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates curl \
|
||||
&& ARCH="${TARGETARCH:-$(dpkg --print-architecture)}" \
|
||||
&& case "$ARCH" in \
|
||||
amd64) YGGDRASIL_SHA256=72745496b09baa1c3f5a6741e1257a704cfdb9d00cdf3ddbef025987b239699d ;; \
|
||||
arm64) YGGDRASIL_SHA256=ac8c9a9a76c54b878fd251aef5a2bbd20375c6109b28b32435683441462360c9 ;; \
|
||||
*) echo "unsupported architecture: $ARCH" >&2; exit 1 ;; \
|
||||
esac \
|
||||
&& curl -fsSL -o /tmp/yggdrasil.deb \
|
||||
"https://github.com/yggdrasil-network/yggdrasil-go/releases/download/v${YGGDRASIL_VERSION}/yggdrasil-${YGGDRASIL_VERSION}-${ARCH}.deb" \
|
||||
&& echo "${YGGDRASIL_SHA256} /tmp/yggdrasil.deb" | sha256sum -c - \
|
||||
&& dpkg-deb -x /tmp/yggdrasil.deb /tmp/yggdrasil-root \
|
||||
&& cp /tmp/yggdrasil-root/usr/bin/yggdrasil /usr/local/bin/yggdrasil \
|
||||
&& rm -rf /tmp/yggdrasil.deb /tmp/yggdrasil-root \
|
||||
&& apt-get purge -y curl \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=build /server/target/release/sn-node /usr/local/bin/sn-node
|
||||
COPY --from=build /server/target/release/sn-exit /usr/local/bin/sn-exit
|
||||
COPY --from=build /server/target/release/sn-fetch /usr/local/bin/sn-fetch
|
||||
COPY --from=build /server/target/release/sn-fair /usr/local/bin/sn-fair
|
||||
|
||||
# WORKDIR matches the state volume in docker-compose.yml; a config that
|
||||
# leaves `state_dir` at its default then resolves to the volume as well.
|
||||
WORKDIR /var/lib/spidernet
|
||||
|
||||
ENTRYPOINT ["sn-node", "daemon", "--config", "/etc/spidernet/node.toml"]
|
||||
@@ -0,0 +1,125 @@
|
||||
# SpiderNet-Node mit Docker
|
||||
|
||||
Dieser Ordner enthält alles, um den SpiderNet-Node eines Haushalts als
|
||||
Container zu betreiben: Multi-Stage-Dockerfile, ein Compose-Beispiel für
|
||||
einen Host und eine kommentierte Beispiel-Konfiguration.
|
||||
|
||||
## Haftungsausschluss
|
||||
|
||||
> **KEINE GARANTIE.** Diese Software wird "as is" ohne jegliche Garantie
|
||||
> bereitgestellt (AGPL §§ 15/16). Die Betreiber und Contributor:innen dieses
|
||||
> Projekts übernehmen **keinerlei Verantwortung oder Haftung** dafür, wozu
|
||||
> Nutzer:innen die Software verwenden oder welche Inhalte über sie
|
||||
> übertragen werden. Die Verantwortung für gesendete und empfangene Inhalte
|
||||
> liegt vollständig bei den Nutzer:innen.
|
||||
|
||||
## Quickstart
|
||||
|
||||
```sh
|
||||
# 1. Konfiguration anlegen und anpassen
|
||||
cp node.toml.example node.toml
|
||||
$EDITOR node.toml
|
||||
|
||||
# 2. Image bauen und starten (Build-Kontext ist server/, daher "context: ..")
|
||||
docker compose up --build -d
|
||||
|
||||
# 3. Beobachten
|
||||
docker compose logs -f
|
||||
|
||||
# 4. Overlay-Status ansehen (Admin-Socket lauscht auf localhost:9001)
|
||||
docker compose exec node sn-node status
|
||||
|
||||
# 5. Einen großen Download über die gepoolte Bandbreite laden
|
||||
docker compose exec node sn-fetch "https://…/große-datei.iso" \
|
||||
-o /tmp/out.iso -e "1=2,2=1@http://[<ygg-adresse-des-nachbarn>]:8080"
|
||||
```
|
||||
|
||||
Image direkt bauen (ohne Compose), Build-Kontext `server/`:
|
||||
|
||||
```sh
|
||||
docker build -t spidernet-node -f docker/Dockerfile ..
|
||||
```
|
||||
|
||||
## Was die Container-Privilegien bedeuten
|
||||
|
||||
| Einstellung | Warum |
|
||||
|---|---|
|
||||
| `network_mode: host` | Yggdrasil muss auf dem realen LAN peeren und auf der Overlay-Seite erreichbar sein. Mit Bridge-NAT würden Peer-Verbindungen und der Exit-Port nicht stimmen. |
|
||||
| `cap_add: [NET_ADMIN]` | Yggdrasil legt das TUN-Interface (`ifname`) an und konfiguriert es — das braucht `CAP_NET_ADMIN`. |
|
||||
| `/dev/net/tun` | Das Kernel-TUN-Gerät, das Yggdrasil öffnet. |
|
||||
| `init: true` | Sauberer PID 1: Reaping + SIGTERM erreicht den Daemon, damit `docker compose stop` als sauberer Kill-Switch funktioniert. |
|
||||
|
||||
Der Container läuft als `root` — für TUN im Container üblich. `NET_ADMIN`
|
||||
ist bewusst nur als Capability gesetzt, ohne `privileged`.
|
||||
|
||||
## Zwei Haushalte verbinden
|
||||
|
||||
Beide Hosts laufen mit demselben Image; die Rolle (Exit oder Leech) steht
|
||||
nur in der jeweiligen `node.toml`.
|
||||
|
||||
- **Die Mesh-Verbindung liegt außerhalb des Containers:** Glasfaser,
|
||||
Switch oder WiFi zwischen den Haushalten. Der Container peeret über das
|
||||
Host-Netzwerk.
|
||||
- **Auto-Peering:** Im selben LAN (Multicast aktiv) finden sich
|
||||
Yggdrasil-Nodes selbst — `peers = []` reicht.
|
||||
- **Explizit:** Falls Multicast nicht geht (z. B. VLANs), trägt man in
|
||||
`node.toml` bei `peers` URIs wie `tcp://<nachbar-lan-ip>:1337` ein.
|
||||
- **ACL:** Die 64-Hex-Public-Keys der erlaubten Nachbarn gehören in
|
||||
`allow_keys`, sonst kann jeder Node im Overlay peeren.
|
||||
|
||||
Die `node.toml` jedes Haushalts enthält persönliche Daten der Nachbarschaft
|
||||
(Public Keys, Adressen) und später den Node-Private-Key im State-Verzeichnis:
|
||||
**niemals committen**, außerhalb des Repos aufbewahren.
|
||||
|
||||
## Leech-Modus (Empfang ohne Exit)
|
||||
|
||||
Die Beispiel-Konfiguration startet sicher im **Leech-Modus** — ein
|
||||
Haushalt, der nur empfangen will, muss nichts ändern:
|
||||
|
||||
```toml
|
||||
[exit]
|
||||
enabled = false
|
||||
```
|
||||
|
||||
Das ist ausdrücklich legitim — Leeches werden bei Sättigung zuerst
|
||||
gedrosselt, aber nie ausgeschlossen. Es gibt kein separates Leech-Image;
|
||||
das Compose-Beispiel funktioniert unverändert.
|
||||
|
||||
Wer seinen Uplink als Exit anbieten will (opt-in), setzt:
|
||||
|
||||
```toml
|
||||
[exit]
|
||||
enabled = true
|
||||
allow = ["<overlay-adresse-des-nachbarn>"]
|
||||
```
|
||||
|
||||
`enabled = true` mit leerer `allow`-Liste ist ungültig — der Daemon
|
||||
verweigert dann den Start (Ausnahme: Dev-Modus mit Loopback-bind).
|
||||
|
||||
## Kill-Switch
|
||||
|
||||
```sh
|
||||
docker compose stop
|
||||
```
|
||||
|
||||
Stoppen des Exits bzw. des Daemons ist der Kill-Switch: Sobald der Daemon
|
||||
nicht läuft, stellt der Haushalt keinen Uplink mehr bereit. Der eigene Node
|
||||
fällt auf den eigenen Internetanschluss zurück. Wichtig zum Verständnis:
|
||||
SpiderNet v0 leitet **normalen Verkehr nicht um** — kein Routing, kein
|
||||
NAT-Trick. Nur Downloads, die `sn-fetch` explizit über das Netz verteilt,
|
||||
nutzen die gepoolte Bandbreite; alles andere geht wie gewohnt über den
|
||||
eigenen Anschluss.
|
||||
|
||||
## Zustand
|
||||
|
||||
`node.key` und die generierte `yggdrasil.conf` liegen im State-Verzeichnis
|
||||
(`/var/lib/spidernet`, Named Volume `spidernet-state` im Compose-Beispiel).
|
||||
Der Node behält damit seine Identität über Container-Neustarts. Volume
|
||||
löschen = neue Node-Identität.
|
||||
|
||||
## Noch offen / Hinweise
|
||||
|
||||
- Der `daemon`-Subcommand ist implementiert und die Beispiel-Konfiguration
|
||||
wurde damit verifiziert (`sn-node daemon --check` → `config ok`).
|
||||
- Images werden lokal gebaut, nicht in ein Registry gepusht (das Projekt
|
||||
kennt keine zentrale Infrastruktur).
|
||||
@@ -0,0 +1,74 @@
|
||||
# SpiderNet node — single-household example (one node per host).
|
||||
#
|
||||
# NO WARRANTY — SpiderNet is provided "as is" without warranty of any kind
|
||||
# (AGPL-3.0, sections 15/16). Running a node is entirely at the operator's
|
||||
# own responsibility.
|
||||
#
|
||||
# The same image serves both roles:
|
||||
# - exit household: [exit] enabled = true in node.toml (plus neighbor
|
||||
# addresses in [exit].allow — enabled with an empty allowlist is
|
||||
# rejected by the daemon)
|
||||
# - leech household: [exit] enabled = false in node.toml (the example
|
||||
# config default — safe, receive-only)
|
||||
# There is no separate leech image; only the config differs.
|
||||
#
|
||||
# Quickstart:
|
||||
# cp node.toml.example node.toml # then edit node.toml
|
||||
# docker compose up --build -d
|
||||
|
||||
services:
|
||||
node:
|
||||
build:
|
||||
# Build context is server/, matching the Dockerfile paths.
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
image: spidernet-node
|
||||
container_name: spidernet-node
|
||||
# Proper PID 1: reaps zombies and makes sure SIGTERM reaches sn-node
|
||||
# so `docker compose stop` behaves as the documented kill switch.
|
||||
init: true
|
||||
# Yggdrasil must bind its TUN interface and peer on the real LAN;
|
||||
# both require the host network stack (no NAT translation).
|
||||
network_mode: host
|
||||
cap_add:
|
||||
# Needed by yggdrasil to create/configure the TUN interface.
|
||||
- NET_ADMIN
|
||||
devices:
|
||||
# The kernel TUN device used for the overlay interface.
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
# Config is read-only; state (node.key, yggdrasil.conf) goes to a
|
||||
# named volume so the node identity survives container upgrades.
|
||||
- ./node.toml:/etc/spidernet/node.toml:ro
|
||||
- spidernet-state:/var/lib/spidernet
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# EXIT VARIANT (offering the household's uplink as exit):
|
||||
#
|
||||
# The example config defaults to leech mode ([exit] enabled = false). To
|
||||
# become an exit household set enabled = true in node.toml and add the
|
||||
# neighbor overlay addresses to [exit].allow. This compose file works
|
||||
# unchanged for both roles (kill switch: `docker compose stop`).
|
||||
#
|
||||
# If you prefer two service definitions (e.g. to toggle via profiles), note
|
||||
# that `network_mode: host` allows only ONE node per host — stop the other
|
||||
# service first:
|
||||
#
|
||||
# node-leech:
|
||||
# build:
|
||||
# context: ..
|
||||
# dockerfile: docker/Dockerfile
|
||||
# image: spidernet-node
|
||||
# container_name: spidernet-node-leech
|
||||
# init: true
|
||||
# network_mode: host
|
||||
# cap_add: [NET_ADMIN]
|
||||
# devices: ["/dev/net/tun:/dev/net/tun"]
|
||||
# restart: unless-stopped
|
||||
# volumes:
|
||||
# - ./node-leech.toml:/etc/spidernet/node.toml:ro
|
||||
# - spidernet-state-leech:/var/lib/spidernet
|
||||
|
||||
volumes:
|
||||
spidernet-state:
|
||||
@@ -0,0 +1,95 @@
|
||||
# Beispielkonfiguration für den SpiderNet-Node-Daemon (`sn-node daemon`).
|
||||
#
|
||||
# Vorlage: diese Datei nach `node.toml` kopieren und anpassen. Die
|
||||
# Compose-Datei in diesem Ordner bindet `./node.toml` ein.
|
||||
#
|
||||
# KEINE GARANTIE — SpiderNet wird "as is" ohne jegliche Garantie
|
||||
# bereitgestellt (AGPL §§ 15/16). Nutzung auf eigene Verantwortung;
|
||||
# die Verantwortung für gesendete und empfangene Inhalte liegt bei den
|
||||
# Nutzer:innen.
|
||||
#
|
||||
# WICHTIG: Die echte node.toml enthält persönliche Daten der Nachbarschaft
|
||||
# (Public Keys, Adressen) und später den Node-Private-Key im state_dir.
|
||||
# node.toml NIEMALS ins Repository committen.
|
||||
|
||||
[node]
|
||||
# Admin-Socket des Yggdrasil-Knotens (tcp://host:port oder unix:///pfad).
|
||||
# Wird auch als Yggdrasil-AdminListen verwendet, wenn der Daemon das
|
||||
# Yggdrasil-Sidecar selbst verwaltet (siehe [yggdrasil].manage).
|
||||
admin_endpoint = "tcp://localhost:9001"
|
||||
|
||||
# Verzeichnis für den Zustand des Nodes (node.key, generierte
|
||||
# yggdrasil.conf). Optional, Standard "spidernet-state" — relativ zum
|
||||
# Arbeitsverzeichnis des Daemons. Im Container besser absolut setzen,
|
||||
# damit es auf das State-Volume fällt:
|
||||
state_dir = "/var/lib/spidernet"
|
||||
|
||||
[yggdrasil]
|
||||
# true = der Daemon startet und überwacht das Yggdrasil-Sidecar selbst.
|
||||
# false = es wird ein bereits laufender Yggdrasil-Daemon verwendet.
|
||||
manage = true
|
||||
|
||||
# Pfad/Name des Yggdrasil-Binary; nur relevant, wenn manage = true.
|
||||
# Im Container ist yggdrasil unter /usr/local/bin/yggdrasil installiert.
|
||||
binary = "yggdrasil"
|
||||
|
||||
# Peer-URIs (tcp://, tls://, quic://, socks://) für manuelles Peering.
|
||||
# Über das Nachbarschafts-LAN peert Yggdrasil per Multicast automatisch;
|
||||
# explizite Peers braucht man z. B. über WLAN-Brücken hinweg.
|
||||
peers = []
|
||||
|
||||
# Listener-URIs für eingehende Peerings (tcp://, tls://, quic://).
|
||||
listen = []
|
||||
|
||||
# Access-Control: 64-stellige Hex-Public-Keys der Nachbarn, die mit uns
|
||||
# peeren dürfen (AllowedPublicKeys). Leere Liste = jeder darf peeren.
|
||||
allow_keys = []
|
||||
|
||||
# true = Multicast-Auto-Peering im LAN deaktivieren.
|
||||
no_multicast = false
|
||||
|
||||
# TUN-Interface: "auto" (Standard), "none" (headless, nur Router-Modus)
|
||||
# oder ein fester Interface-Name.
|
||||
ifname = "auto"
|
||||
|
||||
[exit]
|
||||
# true = dieser Haushalt stellt seinen Uplink als Exit bereit (opt-in).
|
||||
# false = Leech-Modus (Standard hier): der Node empfängt nur, bietet
|
||||
# keinen Exit an — ausdrücklich legitim, niemand wird gedrosselt, nur
|
||||
# fair priorisiert.
|
||||
#
|
||||
# Wer Exit anbieten will: enabled = true setzen UND in `allow` die
|
||||
# Overlay-Adressen der Nachbarn eintragen — enabled = true mit leerer
|
||||
# `allow`-Liste ist ungültig (der Daemon verweigert den Start; Ausnahme:
|
||||
# Dev-Modus mit Loopback-bind).
|
||||
enabled = false
|
||||
|
||||
# Explizite Bind-Adresse. Leer (Standard) = "[<Yggdrasil-Adresse>]:port",
|
||||
# d. h. der Exit lauscht auf der eigenen Overlay-Adresse.
|
||||
# UNGÜLTIG: allow = [] zusammen mit einem nicht-Loopback-bind — der Exit
|
||||
# wäre sonst für beliebig viele Quellen offen (Schutz: ohne Allowlist nur
|
||||
# Loopback, das ist der Dev-Modus).
|
||||
bind = ""
|
||||
|
||||
# TCP-Port des Exit-Dienstes (u16, Standard 8080).
|
||||
port = 8080
|
||||
|
||||
# Overlay-Adressen der Nachbarn, die diesen Exit nutzen dürfen.
|
||||
# Leere Liste = nur Loopback (Dev-Modus); bei nicht-Loopback-bind Pflicht.
|
||||
# Beispiel:
|
||||
# allow = ["200:abcd:ef01::2", "200:abcd:ef01::3"]
|
||||
allow = []
|
||||
|
||||
# Kontingent pro Nachbar: Bytes pro Zeitfenster (u64, Standard 1024 MiB).
|
||||
# 0 = unbegrenzt (kein Kontingent).
|
||||
quota_mib = 1024
|
||||
|
||||
# Länge des Kontingent-Zeitfensters in Stunden (fixed window).
|
||||
window_hours = 24
|
||||
|
||||
# KILL-SWITCH: Wer nichts mehr teilen will, stoppt einfach den Exit bzw.
|
||||
# den Daemon (Container: `docker compose stop`). Damit endet die
|
||||
# Bereitstellung des eigenen Uplinks sofort — der eigene Node fällt auf
|
||||
# den eigenen Internetanschluss zurück. SpiderNet v0 leitet normalen
|
||||
# Verkehr nicht um: nur Downloads, die sn-fetch explizit über das Netz
|
||||
# verteilt, nutzen die gepoolte Bandbreite.
|
||||
Reference in New Issue
Block a user