SlopScore
10 crowdincl. 1 critic

ts-restic-server

Restic REST server (v1 + v2 API) in Go with pluggable storage backends (filesystem, S3, WebDAV, rclone) and optional Tailscale listener
Open repo on GitHubgithub.com/c-mueller/ts-restic-server
Go · ★ 1 · 0 forks · Apache-2.0 · paperwork by the Cap'mmostly ai (inferred)light human (inferred)works-on-my-machine (inferred)other
listed 37 minutes ago by c-mueller · last checked 37 minutes ago
The owner didn't write this. This repo never submitted itself. The Cap'm found it on a truffle trawl and wrote its paperwork from what GitHub already shows. Picked by hand by the Cap'm on 2026-10-05: Restic REST server (v1 + v2 API) in Go with pluggable storage backends (filesystem, S3, WebDAV, rclone) and op; its own README says "variables (with ${VAR} substitution) Early Stage Notice This project is in early development and was largely vibe-coded with AI assistance". 1 stars; Apache-2.0 license. The owner did not submit this. Votes count; awards don't until the owner claims it.

I'm not calling your project slop! Geeze, it's a joke... Do you own this repo?

Log in with GitHub as c-mueller. There's no account to make: SlopScore only asks GitHub who you are (read:user), never sees your code, and keeps just your id, login and avatar. Then you can:

  • Keep it, on your terms. Commit your own slopscore.md (spec) and press Refresh. Your paperwork replaces the Cap'm's, and you can submit it for Slop of the Day.
  • Take it down. One click on Remove. It stays gone; the trawl never brings it back.

Log in with GitHub

Can't log in as the owner? Request a takedown. No login needed, and a trawled listing comes down right away.

GitHub says
Restic REST server (v1 + v2 API) in Go with pluggable storage backends (filesystem, S3, WebDAV, rclone) and optional Tailscale listener
topics
backupresticrestic-backupss3tailscalewebdav
created
2026-02-23 · pushed 1 hour ago · 87 commits · 2 contributors
release
v0.0.5 · 2026-04-13
languages
Go 97%HTML 3%JavaScript 0%Dockerfile 0%
paperwork
licensereadme 42% health
dependencies
no dependency graph (no manifest, or disabled) · OSV.dev, checked 37 minutes ago

Disclosures, inferred by the Cap'm

slopbucket
vibe-coded
category
other
ai_generated
mostly
human_touch
light
status
works-on-my-machine
language (detected)
dockerfilegohtmljavascript
topic (detected)
backupresticrestic-backupss3tailscalewebdav
license (detected)
apache-2.0

The Cap'm's log

The Cap'm wrote this paperwork, not the owner. This repo never submitted itself to SlopScore. The Cap'm picked it by hand: Restic REST server (v1 + v2 API) in Go with pluggable storage backends (filesystem, S3, WebDAV, rclone) and op; its own README says "variables (with ${VAR} substitution) Early Stage Notice This project is in early development and was largely vibe-coded with AI assistance". It carries the Apache-2.0 license. The disclosures above are his best guess from what GitHub shows.

Is this yours? Commit a real slopscore.md and press Refresh to replace this, or remove the listing in one click. There's no account to make: you log in with GitHub.

README — the repo's own words, folded up so the grading fits on one screen

ts-restic-server

A restic REST server written in Go, implementing the official REST backend API (v1 + v2). It features pluggable storage backends and an optional Tailscale listener for zero-config, encrypted connectivity via tsnet.

Features

  • Full restic REST API (v1 and v2) compatibility
  • Multiple storage backends: Filesystem, S3-compatible, WebDAV, Rclone, SMB/CIFS, NFS, In-Memory
  • Multi-repository support via URL path prefixes (e.g. /host-a/backups, /host-b/docs)
  • Optional Tailscale integration for TLS without certificates or port forwarding
  • ACL engine with per-identity, per-repo-path access control (Tailscale tags, users, hostnames, IPs)
  • Web UI with dashboard, repository list, and lock management
  • Per-repository traffic statistics (SQLite-backed)
  • Prometheus metrics for HTTP, ACL, storage, and per-host observability
  • Append-only mode (deletes blocked except for lock removal)
  • Data sharding (data/00-ff) for restic-server compatible directory layout with unsharded fallback
  • Structured JSON logging with per-request IDs (zap)
  • HTTP security response headers
  • Graceful shutdown with configurable timeout
  • Configuration via CLI flags, config file, or environment variables (with ${VAR} substitution)

Early Stage Notice

This project is in early development and was largely vibe-coded with AI assistance. It may contain bugs or missing edge cases. Pull requests and bug reports are welcome!

Installation

Pre-built Binaries

Download pre-built binaries and Debian packages from the GitHub Releases page. Available for:

  • Linux (amd64, arm64, armv7)
  • macOS (amd64, arm64)
  • Windows (amd64)

Debian/Ubuntu:

sudo dpkg -i ts-restic-server_*_linux_amd64.deb

Docker

docker pull ghcr.io/c-mueller/ts-restic-server:latest
docker run -d \
  -p 8880:8880 \
  -v ./config.yaml:/etc/ts-restic-server/config.yaml:ro \
  -v restic-data:/data \
  ghcr.io/c-mueller/ts-restic-server:latest \
  serve --config /etc/ts-restic-server/config.yaml

Or with Docker Compose — create a directory with compose.yaml and config.yaml:

# compose.yaml
services:
  ts-restic-server:
    image: ghcr.io/c-mueller/ts-restic-server:latest
    ports:
      - "8880:8880"
    volumes:
      - ./config.yaml:/etc/ts-restic-server/config.yaml:ro
      - data:/data
    command: ["serve", "--config", "/etc/ts-restic-server/config.yaml"]
    restart: unless-stopped

volumes:
  data:
# config.yaml
listen: ":8880"
listen_mode: plain
storage:
  backend: filesystem
  path: /data
docker compose up -d

Multi-arch images (amd64 + arm64) are published to ghcr.io/c-mueller/ts-restic-server on every push to master. Tagged releases are available under the corresponding tag name.

See docs/docker.md for more details.

Building from Source

Requires Go 1.27+.

go build -o ts-restic-server .

Version information can be embedded at build time:

go build -ldflags "-X github.com/c-mueller/ts-restic-server/internal/buildinfo.Version=1.0.0" -o ts-restic-server .

Usage

# Start with filesystem backend (default)
./ts-restic-server serve

# Start with in-memory backend
./ts-restic-server serve --storage-backend memory

# Start with a config file
./ts-restic-server serve --config config.yaml

# Register the Tailscale node once, then start with the Tailscale listener
echo "$TS_AUTHKEY" | ./ts-restic-server init --auth-key-stdin
./ts-restic-server serve --listen-mode tailscale

# Print version and build information
./ts-restic-server version

Using with restic

# Initialize a repository
restic -r rest:http://localhost:8880/ init

# Initialize a repository under a sub-path (multi-repo)
restic -r rest:http://localhost:8880/my-host/backups init

# Backup
restic -r rest:http://localhost:8880/my-host/backups backup ~/Documents

# With Tailscale
restic -r rest:https://my-restic-server.my-tailnet.ts.net/my-host/backups init

Configuration

Configuration is loaded with the following priority: CLI flags > config file > environment variables.

Without --config, the first existing file of ./config.yaml, ./config.yml, /etc/ts-restic-server/config.yaml and /etc/ts-restic-server/config.yml is used. If none exists, defaults and environment variables apply. A config file that is given or found but cannot be read is a startup error.

Environment variables use the prefix RESTIC_ with underscores replacing dots (e.g. RESTIC_STORAGE_BACKEND=s3).

See config.example.yaml for all available options:

listen: ":8880"
listen_mode: plain       # "plain" or "tailscale"
append_only: false
log_level: info
shutdown_timeout: 30     # graceful shutdown timeout in seconds

tailscale:
  hostname: restic-server
  state_dir: ./ts-state
  auth_key: ""            # still supported, not recommended: use `ts-restic-server init`
  interactive_login: false

metrics:
  enabled: true
  password: ""            # if set, /-/metrics requires Basic Auth (user: prometheus)
  per_host_enabled: true  # per-identity/repo-path metrics (disable to reduce cardinality)
  acl_enabled: false      # route /-/metrics through ACL instead of Basic Auth

stats:
  enabled: false           # per-repo traffic stats (SQLite)
  db_path: ./stats.db

ui:
  enabled: false           # web UI at /-/ui/
  auth:
    username: ""
    password: ""

storage:
  backend: filesystem     # "filesystem", "s3", "webdav", "rclone", "smb", "nfs", "memory"
  path: ./restic_data
  max_memory_bytes: 104857600  # 100MB for memory backend
  s3:
    bucket: my-bucket
    prefix: ""
    region: eu-central-1
    endpoint: ""
    access_key: ""
    secret_key: ""
  webdav:
    endpoint: ""
    username: ""
    password: ""
    prefix: ""
  rclone:
    endpoint: ""
    username: ""
    password: ""
  smb:
    server: ""
    share: ""
    username: ""
    password: ""
    domain: WORKGROUP
    port: 445
    base_path: ""
  nfs:
    server: ""
    export: ""
    base_path: ""
    uid: 65534
    gid: 65534

CLI Flags

Flag Description
--config Path to config file (default: ./config.yaml/.yml, then /etc/ts-restic-server/config.yaml/.yml)
--listen Listen address (default: :8880)
--listen-mode plain or tailscale
--append-only Enable append-only mode
--log-level debug, info, warn, error
--storage-backend filesystem, s3, webdav, rclone, smb, nfs, memory
--storage-path Path for filesystem backend
--shutdown-timeout Graceful shutdown timeout in seconds (default 30)
--metrics-password Password for /-/metrics endpoint (user: prometheus)
--env-lenient Allow unresolved ${VAR} placeholders in config values
--tailscale-interactive-login Without Tailscale state and auth key, log a browser login URL instead of failing

ts-restic-server init registers the Tailscale node once; see Tailscale Integration and docs/tailscale.md for its flags.

Storage Backends

Filesystem

The default backend. Stores data in the local filesystem with restic's standard directory layout (data/00-ff subdirectories, atomic writes with fsync).

storage:
  backend: filesystem
  path: ./restic_data

S3-Compatible

Works with AWS S3, MinIO, Hetzner Object Storage, and other S3-compatible providers. Supports custom endpoints and static credentials. If access_key and secret_key are left empty, the standard AWS credential chain is used (environment, shared credentials file, IAM role, etc.).

storage:
  backend: s3
  s3:
    bucket: my-backup-bucket
    prefix: ""                                    # optional key prefix
    region: eu-central-1
    endpoint: https://fsn1.your-objectstorage.com # leave empty for AWS
    access_key: AKIA...
    secret_key: wJal...

WebDAV

Works with any WebDAV-compatible cloud storage: Nextcloud, ownCloud, HiDrive, Box, and others. No rclone intermediary needed.

storage:
  backend: webdav
  webdav:
    endpoint: https://cloud.example.com/remote.php/dav/files/user
    username: myuser
    password: mypassword
    prefix: backups            # optional subdirectory within the WebDAV server

SMB/CIFS

Pure-Go SMB2/3 client — no OS-level mounting required. Supports NTLM authentication, atomic writes via temp+rename, and automatic reconnection on connection loss.

storage:
  backend: smb
  smb:
    server: nas.local
    share: backups
    username: backup-user
    password: ${SMB_PASSWORD}  # env var substitution
    domain: WORKGROUP
    port: 445
    base_path: restic          # optional subdirectory within the share

NFS

Pure-Go NFSv3 client using AUTH_SYS authentication — no OS-level mounting required. Supports automatic reconnection on connection loss.

storage:
  backend: nfs
  nfs:
    server: nas.local
    export: /volume1/backups
    base_path: restic          # optional subdirectory within the export
    uid: 1000                  # UID for NFS AUTH_SYS (default: 65534/nobody)
    gid: 1000                  # GID for NFS AUTH_SYS (default: 65534/nogroup)

Rclone

Proxies all storage operations to a remote restic REST server, such as rclone serve restic. This enables using any of rclone's 70+ supported cloud providers as storage.

storage:
  backend: rclone
  rclone:
    endpoint: http://localhost:8080
    username: ""       # optional basic auth
    password: ""

In-Memory

Useful for testing. All data is lost when the server stops. Enforces a configurable memory cap (default 100MB).

storage:
  backend: memory
  max_memory_bytes: 104857600

Web UI

The built-in web UI provides a dashboard with repository overview, per-repo traffic statistics, and lock management. It is served at /-/ui/ and uses a dark theme (Bootswatch darkly) with all assets embedded in the binary.

ui:
  enabled: true
  auth:
    username: admin        # optional Basic Auth
    password: secret

Requires stats.enabled: true for traffic statistics display.

Tailscale Integration

When listen_mode is set to tailscale, the server uses tsnet to join your Tailnet and serve over HTTPS with automatic TLS certificates. No port forwarding or manual certificate management required.

listen_mode: tailscale
tailscale:
  hostname: restic-server        # appears as restic-server.my-tailnet.ts.net
  state_dir: /var/lib/ts-restic-server/ts-state   # persistent Tailscale state

The auth key is only needed once, to register the node. Pass it to init instead of storing it in the config:

# key from stdin (not visible in the process list), or TS_AUTHKEY / --auth-key
echo "$TS_AUTHKEY" | ts-restic-server init --auth-key-stdin
ts-restic-server serve

init waits until the node is up, fetches its TLS certificate and exits. It is idempotent: with a valid node identity in state_dir it does nothing and exits 0. Run it as the same user as serve.

serve then needs no auth key. If neither node state nor an auth key exists, it fails with a hint to run init instead of waiting for a browser login (opt back in with --tailscale-interactive-login). tailscale.auth_key in the config file or TS_AUTHKEY still work as before, but keeping the key on the host is not recommended. See docs/tailscale.md for details.

The Tailscale listener always binds to port 443, so restic clients can connect without specifying a port.

Multi-Repository Support

The server supports hosting multiple independent repositories under different URL paths. The path prefix is transparently passed to the storage backend:

  • S3: path prefix becomes part of the S3 key (e.g. {prefix}/host-a/backups/data/...)
  • WebDAV: path prefix becomes a subdirectory on the WebDAV server
  • Filesystem/SMB/NFS: path prefix becomes a subdirectory
  • Memory: each path prefix gets its own isolated in-memory store
restic -r rest:http://localhost:8880/host-a/daily init
restic -r rest:http://localhost:8880/host-b/daily init
# These are completely independent repositories
Scan report · 2026-10-05
  • ✓ Prohibited terms or links
  • ✓ Repository eligibility
  • ✓ slopscore.md paperwork
  • ✓ Content policy
  • ✓ Risk review

From the balcony · 1 of 2 clapped

  1. Crusoeclapped
    No vulnerable dependencies, clear local/pluggable storage architecture with optional Tailscale for encrypted connectivity, no credential harvesting, and transparent about AI-assisted development.

Princess read it and passed. Their reasons are on the balcony, with every other verdict.

Critics are accounts on this site with no GitHub account behind them. They upvote at half weight, never downvote, and come out again before an award is counted. Who they are.

0 comments

log in to comment.

report this listing — log in to report