個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Content automation and downloader agent
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗The Nabbed agent runs on your own hardware. The Nabbed cloud decides what to download; the agent downloads it natively (usenet and BitTorrent, no external client) using provider credentials the cloud cannot read.
docker run -d --name nabbed-agent --restart unless-stopped \
-e NABBED_API_URL=https://api.nabbed.example \
-v nabbed-data:/data \
-v "$PWD/downloads:/downloads" \
-p 6881:6881 -p 6881:6881/udp \
--read-only --tmpfs /tmp --cap-drop ALL --security-opt no-new-privileges \
ghcr.io/getnabbed/agent:0.1
docker logs -f nabbed-agent # shows the pairing code on first start
Open the link in the log, enter the code, and the agent is paired. It keeps
its credentials in /data, so that volume must persist; never put them in
an environment variable or a Docker secret, because the refresh token
rotates.
The image is linux/amd64, linux/arm64 and linux/arm/v7, based on
distroless with no shell, and runs as uid 65532. A bind-mounted
downloads directory must be writable by that uid
(sudo chown -R 65532:65532 downloads), or run the container with
--user "$(id -u):$(id -g)".
A ready-to-use Compose file applies the same hardening:
curl -O https://raw.githubusercontent.com/getnabbed/agent/main/contrib/docker/compose.yaml
docker compose up -d && docker compose logs -f agent
The Helm chart runs agents as a StatefulSet, one paired agent per replica, with shared library folders mounted from NFS or any other volume:
helm install nabbed ./helm/nabbed-agent --namespace nabbed --create-namespace \
--set config.api_url=https://api.nabbed.example
The install notes show how to get each agent's pairing code from
kubectl logs.
Settings come from, in increasing order of precedence: built-in defaults,
an optional YAML file, NABBED_* environment variables, and command-line
flags. Run agent config to print the effective configuration with secrets
redacted.
| Setting | Environment variable | Flag | Default |
|---|---|---|---|
| Config file | NABBED_CONFIG | --config | see below |
api_url | NABBED_API_URL | --api-url | none; needed only to pair |
name | NABBED_NAME | --name | hostname |
data_dir | NABBED_DATA_DIR | --data-dir | platform data dir; /data in Docker |
log.level | NABBED_LOG_LEVEL | --log-level | info |
log.format | NABBED_LOG_FORMAT | --log-format | auto |
tls.ca_file | NABBED_CA_FILE | --ca-file | system roots only |
downloads.dir | NABBED_DOWNLOAD_DIR | --download-dir | <data_dir>/downloads; /downloads in Docker |
downloads.max_concurrent | NABBED_MAX_DOWNLOADS | --max-downloads | 3 |
torrent.port | NABBED_TORRENT_PORT | --torrent-port | 0 (random); 6881 in Docker |
torrent.allow_lan | NABBED_TORRENT_ALLOW_LAN | --torrent-allow-lan | false |
network.allowed_ranges | NABBED_ALLOWED_RANGES | none: torrents and web-app sources stay off the local network (see below) | |
usenet.provider | NABBED_NNTP | --nntp |
Every environment variable also accepts a _FILE variant that names a file
holding the value, for Docker and Kubernetes secrets:
NABBED_NNTP_FILE=/run/secrets/nntp.
The web app chooses where imported files go, but only inside folders you allow on this machine. By default none are allowed, and the web app shows why each library folder was refused. Allow the parents of your libraries:
library:
allowed_roots:
- /media/movies
- /media/tv
Or set NABBED_LIBRARY_ROOTS=/media/movies:/media/tv (;-separated on
Windows). Symlinks are resolved, so a link cannot lead outside. In Docker,
mount your media and allow the mount point, for example
-v /srv/media:/media -e NABBED_LIBRARY_ROOTS=/media.
Imported files are created 0644 and folders 0755, so a media server
running as another user can read them. Tighten them with library.file_mode
and library.dir_mode if your media server shares the agent's user or
group.
Start from contrib/agent.example.yaml.
Unknown keys are an error, so typos fail loudly. The agent looks for it at:
| Platform | Path |
|---|---|
| Docker | /config/agent.yaml (mount a directory read-only at /config) |
| Linux, root or system service | /etc/nabbed-agent/agent.yaml |
| Linux, user | ~/.config/nabbed-agent/agent.yaml |
| macOS | ~/Library/Application Support/Nabbed Agent/agent.yaml |
| Windows | %APPDATA%\Nabbed\Agent\agent.yaml |
A missing file at the default location is fine; a missing file named with
--config is an error. Keep the file owned by you and read-only to the
agent: it will also hold the local policy (allowed library roots, limits)
that the cloud cannot override.
Add usenet providers in the web app. The browser encrypts the credentials
to this agent's key, so the cloud stores them but cannot read them, and the
agent keeps them encrypted on disk. Providers from the web app must use TLS
and a public host, unless you allow the host's address in
network.allowed_ranges (see Local network policy).
Pairing the agent again gives it a new key, so its providers must be
entered again.
A provider on your local network, or one you prefer to keep off the cloud
entirely, can also be set locally with NABBED_NNTP_FILE (preferred) or
NABBED_NNTP:
nntps://user:[email protected]:563?connections=8. Flag values are
visible in process lists, so avoid --nntp for real passwords.
Separate several providers with spaces, in priority order. Each article is
tried on them in turn when one lacks it or serves it damaged. Add
backup=true to a block account so it is used only for those gaps.
connections is the account's limit and is shared by every download; if
the provider allows fewer, the agent notices and uses fewer.
Signed binaries for Linux (amd64, arm64, armv7), macOS and Windows are on
each GitHub release, with a
hardened systemd unit in contrib/systemd/. With a Go toolchain:
go install github.com/getnabbed/agent/cmd/agent@latest
Releases are built reproducibly in GitHub Actions. Checksums and images are signed with cosign using GitHub's OIDC identity (no long-lived keys), and every archive has an SBOM and a SLSA build provenance attestation.
Verify against the exact release workflow and tag, not just the repository: a pattern that accepts any workflow in the repository would also accept one run from an unreviewed branch.
VERSION=1.2.3
IDENTITY="https://github.com/getnabbed/agent/.github/workflows/release.yml@refs/tags/v$VERSION"
ISSUER=https://token.actions.githubusercontent.com
# Archives: build provenance, then the signed checksum file.
gh attestation verify agent_${VERSION}_linux_amd64.tar.gz --repo getnabbed/agent \
--signer-workflow getnabbed/agent/.github/workflows/release.yml
cosign verify-blob checksums.txt --bundle checksums.txt.sigstore.json \
--certificate-identity "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \
--certificate-github-workflow-trigger push
sha256sum --ignore-missing -c checksums.txt
# Container image.
cosign verify ghcr.io/getnabbed/agent:$VERSION \
--certificate-identity "$IDENTITY" --certificate-oidc-issuer "$ISSUER" \
--certificate-github-workflow-trigger push
Release 0.1.0 was published before the repository moved to getnabbed.
Its image is ghcr.io/wilderness-cloud/agent:0.1.0, and it verifies with
wilderness-cloud/agent in place of getnabbed/agent in the identity and
the gh attestation flags.
agent pair --api-url https://api.nabbed.example # shows a code to approve in the web app
agent run # connects; pairs first if needed
agent status # identity, gateway, state (no secrets)
agent config # effective configuration (secrets redacted)
Exit code 3 means the agent was revoked or its credentials expired and it
must be paired again with agent pair --force.
Logs go to stderr. auto (the default) writes compact human-readable text
on a terminal and one JSON object per line otherwise, which is what Docker
and systemd capture. Set NO_COLOR to disable colour. At debug level each
record also carries its source file and line.
Downloads go to the download directory, at most downloads.max_concurrent
at once. BitTorrent listens on torrent.port and does not seed after
completion; forwarding that port improves speeds but is optional.
Torrent metadata comes from public indexers and peers, so it is untrusted. By default the agent will not contact anything on your local network on a torrent's behalf: peers, DHT nodes, trackers and web seeds with private, loopback, link-local (including cloud metadata), CGNAT, local-use NAT64 or multicast addresses are refused, checked after DNS so a hostname cannot sneak one through. Usenet sources from the web app are held to the same rule, since anyone with the agent's public key can seal one.
To let both reach particular machines, such as a seedbox, a tracker or a usenet server on your LAN, list their addresses or networks:
network:
allowed_ranges:
- 192.168.1.20 # one address
- 192.168.10.0/24 # a network
- fd00:1::/64
or NABBED_ALLOWED_RANGES="192.168.1.20, 192.168.10.0/24" (commas or
spaces). Only this file or the environment can set it; the web app cannot.
An IPv4 range also covers the same addresses written as IPv6
(::ffff:192.168.1.20, or 64:ff9b::c0a8:114 through NAT64). On an
IPv6-only network that reaches IPv4 through a local-use NAT64 prefix,
allow that prefix, for example 64:ff9b:1::/48. A range with bits set past
its length, such as 192.168.1.20/24, is refused, since it is unclear
whether one address or the network was meant. Web-app sources must still
use a public name (one that resolves into an allowed range works) or the
address itself: names such as nas.lan or nas.local are always refused.
Set torrent.allow_lan: true only if you deliberately seed or fetch from
any machine on your LAN; it applies to torrents only.
Import into the library is not implemented yet: completed downloads stay in the download directory and are reported as failed at the import step.
See design 0003 for how credentials, sessions and token refresh work.
Requires Go 1.27.3 or newer and golangci-lint.
make build # build ./bin/agent
make test # run tests with the race detector
make lint # run golangci-lint
make vuln # govulncheck: known vulnerabilities in called code
make proto # regenerate pkg/proto from proto/ (buf)
make docker # build the container image from source
make snapshot # local GoReleaser build of every archive, unsigned
make all # lint, test, build
Releases are built by GoReleaser when a v* tag
is pushed. See CONTRIBUTING.md for the contribution
workflow.
Every merge to main that passes CI publishes a dev image, for testing and
debugging unreleased changes. Dev images are not releases: don't run them
for anything you rely on.
docker pull ghcr.io/getnabbed/agent:main # newest main
docker pull ghcr.io/getnabbed/agent:main-<sha12> # one commit
helm upgrade --install nabbed-agent oci://ghcr.io/getnabbed/charts/nabbed-agent \
--set image.tag=main --set image.pullPolicy=Always
The agent reports its version as 0.0.0-main.<sha12>. Dev images are signed
by the CI workflow on main, not the release workflow:
cosign verify ghcr.io/getnabbed/agent:main \
--certificate-identity https://github.com/getnabbed/agent/.github/workflows/ci.yml@refs/heads/main \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
| none (temporary, see below) |
library.allowed_roots | NABBED_LIBRARY_ROOTS | none: no library folders allowed (see below) |
library.file_mode | NABBED_LIBRARY_FILE_MODE | 0644 |
library.dir_mode | NABBED_LIBRARY_DIR_MODE | 0755 |