~bigbes/shroud

ref: 5afb3bad1be8eb82352dde56e6836a0a8ea4ef7f shroud/README.md -rw-r--r-- 6.0 KiB
5afb3bad — Eugene Blikh feat: add optional shadowsocks and outline smart dialer config 2 months ago

#shroud

Single-binary Go replacement for the Outline VPN server stack. Replaces the original 3-process deployment (Node.js shadowbox + outline-ss-server + Prometheus) with one Go binary that uses outline-ss-server as a library.

Optionally includes AmneziaWG support with HTTP/3 QUIC cover traffic on port 443.

#Features

  • Single binary — no Node.js, no child processes, no sidecar Prometheus
  • Shadowbox-compatible REST API — drop-in replacement for existing Outline clients
  • Hot-reload — adding/removing keys swaps cipher lists and listeners without downtime
  • AmneziaWG — obfuscated WireGuard VPN with automatic TLS certificates and HTTP/3 cover server
  • Built-in metrics — Prometheus endpoint with optional node_exporter collectors (Linux)
  • CLI management — manage keys and server config without a running server
  • Atomic state persistence — single YAML file with safe write-via-rename

#Quick Start

#Build from source

go build ./cmd/shroud/

#Run

# Start the server
./shroud -c config.example.yaml

# With verbose logging
./shroud -c config.yaml -v

#Install on Ubuntu/Debian

curl -fsSL https://sourcecraft.dev/bigbes/shroud/raw/branch/main/install.sh | sudo bash

The installer builds from source, creates a systemd service, configures firewall rules, and prints the management API URL on completion.

#CLI Usage

# Server management (no running server required)
./shroud server info -c config.yaml
./shroud server set-port 50000 -c config.yaml
./shroud server set-hostname vpn.example.com -c config.yaml
./shroud server set-name "My VPN" -c config.yaml

# Access key management (no running server required)
./shroud key list -c config.yaml
./shroud key add -n "user1" -c config.yaml
./shroud key add -n "user2" -p 51234 --cipher chacha20-ietf-poly1305 -c config.yaml
./shroud key remove 1 -c config.yaml
./shroud key rename 1 "new-name" -c config.yaml

# Shell completions
./shroud completion bash
./shroud completion zsh

#Configuration

See config.example.yaml for the full configuration reference.

server:
  name: "My Outline Server"
  hostname: "example.com"

api:
  listen_addr: ":443"

metrics:
  listen_addr: "127.0.0.1:8082"
  node_exporter_collectors:
    - cpu
    - meminfo
    - loadavg
    - filesystem
    - diskstats
    - netdev

shadowsocks:
  default_port: 0                      # 0 = pick random available port
  default_cipher: chacha20-ietf-poly1305
  replay_history: 10000

amneziawg:
  enabled: false
  listen_port: 443
  address: "10.14.0.0/24"
  domain: "vpn.example.com"            # For automatic Let's Encrypt certs

state_file: state.yaml

#REST API

All management endpoints live under /<secret>/ prefix. The secret is auto-generated on first run and printed to the log.

Method Endpoint Description
GET /<secret>/server Server info
PUT /<secret>/name Rename server
GET /<secret>/access-keys List all keys
POST /<secret>/access-keys Create key
GET /<secret>/access-keys/{id} Get key
PUT /<secret>/access-keys/{id} Upsert key
DELETE /<secret>/access-keys/{id} Delete key
PUT /<secret>/access-keys/{id}/name Rename key
PUT /<secret>/access-keys/{id}/data-limit Set data limit
DELETE /<secret>/access-keys/{id}/data-limit Remove data limit
PUT /<secret>/server/port-for-new-access-keys Set default port
PUT /<secret>/server/hostname-for-access-keys Set hostname
PUT /<secret>/server/access-key-data-limit Set default data limit
DELETE /<secret>/server/access-key-data-limit Remove default data limit
GET /<secret>/metrics/enabled Check metrics status
PUT /<secret>/metrics/enabled Toggle metrics
GET /<secret>/metrics/transfer Per-key byte transfer
GET /<secret>/access-keys/{id}/awg-config Download AmneziaWG config
GET /<secret>/access-keys/{id}/outline-config Download Outline Smart Dialer config

Public endpoints (no auth):

Method Endpoint Server Description
GET /metrics Metrics Prometheus scrape target
GET /healthz Metrics Health check

#Architecture

cmd/shroud/main.go     CLI entry point, cobra commands, signal handling
        |
        +-> internal/config/    YAML config loading and validation
        +-> internal/store/     YAML file persistence (atomic write via rename)
        +-> internal/ssserver/  Wraps outline-ss-server as a library
        +-> internal/metrics/   Prometheus registry + TransferTracker
        +-> internal/api/       REST API handlers (shadowbox-compatible)
        +-> internal/awgserver/ AmneziaWG server + HTTP/3 QUIC cover

The Shadowsocks proxy is imported as a Go library — not run as a subprocess. When keys change, SyncKeys() rebuilds cipher lists and hot-swaps listeners. The integration surface is ~100 lines in internal/ssserver/server.go.

#Main Dependencies

Dependency Version Purpose
outline-ss-server v1.9.3-rc2 Shadowsocks proxy (used as library)
outline-sdk v0.0.21 Outline transport primitives
amneziawg-go v1.0.4 DPI-resistant WireGuard implementation
prometheus/client_golang v1.23.2 Go Prometheus client and registry
prometheus/node_exporter v1.10.2 OS-level metrics collectors (Linux)

#Building with version info

go build -ldflags='-X main.version=1.0.0' ./cmd/shroud/

#Testing

go test ./...