~bigbes/shroud

3394139df40339ebdae50f853d922c14fca77c35 — Eugene Blikh a month ago 999bf1c
docs: update README with VLESS+REALITY, CI/CD site deployment

Add VLESS+REALITY protocol to features, CLI usage, config example,
architecture diagram, and dependencies. Add .sourcecraft CI workflow
to publish install.sh to site branch. Fix install URL to use
bigbes.sourcecraft.dev.

false
3 files changed, 108 insertions(+), 34 deletions(-)

A .sourcecraft/ci.yaml
A .sourcecraft/sites.yaml
M README.md
A .sourcecraft/ci.yaml => .sourcecraft/ci.yaml +51 -0
@@ 0,0 1,51 @@
on:
  push:
    - workflows: [publish-install]
      filter:
        branches: [master]
        paths: ["install.sh"]

workflows:
  publish-install:
    tasks:
      - name: publish-install
        cubes:
          - name: publish
            image: alpine:latest
            env:
              SC_TOKEN: ${{ secrets.SC_TOKEN }}
            script:
              - apk add --no-cache git
              - |
                git config user.name "CI Bot"
                git config user.email "ci@sourcecraft.dev"

              # Set up authenticated remote
              - |
                git remote set-url origin \
                  "https://ci:${SC_TOKEN}@git.sourcecraft.dev/bigbes/shroud.git"

              # Create or update the site branch with install.sh
              - |
                SITE_BRANCH="site"

                # Check if site branch exists remotely
                if git ls-remote --exit-code origin "refs/heads/${SITE_BRANCH}" >/dev/null 2>&1; then
                  git fetch origin "${SITE_BRANCH}"
                  git checkout "${SITE_BRANCH}"
                else
                  git checkout --orphan "${SITE_BRANCH}"
                  git rm -rf .
                fi

                # Copy install.sh from master
                git show "origin/master:install.sh" > install.sh
                git add install.sh

                # Only commit and push if there are changes
                if git diff --cached --quiet; then
                  echo "No install.sh changes to publish"
                else
                  git commit -m "site: update install.sh"
                  git push origin "${SITE_BRANCH}"
                fi

A .sourcecraft/sites.yaml => .sourcecraft/sites.yaml +2 -0
@@ 0,0 1,2 @@
site:
  ref: site

M README.md => README.md +55 -34
@@ 2,63 2,78 @@

Single-binary Go replacement for the [Outline VPN](https://getoutline.org/) server stack. Replaces the original 3-process deployment (Node.js shadowbox + outline-ss-server + Prometheus) with one Go binary that uses [outline-ss-server](https://golang.getoutline.org/tunnel-server) as a library.

Optionally includes [AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/) support with HTTP/3 QUIC cover traffic on port 443.
Supports three protocols: **Shadowsocks**, **[AmneziaWG](https://docs.amnezia.org/documentation/amnezia-wg/)** (obfuscated WireGuard with HTTP/3 cover traffic), and **[VLESS+REALITY](https://github.com/XTLS/REALITY)** (TLS 1.3 camouflage proxy).

## 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
- **AmneziaWG** — DPI-resistant WireGuard VPN with automatic TLS certificates and HTTP/3 cover server
- **VLESS+REALITY** — TLS 1.3 camouflage proxy with auto-detection of decoy servers
- **Multi-protocol keys** — each access key automatically gets credentials for all enabled protocols
- **Built-in metrics** — Prometheus endpoint with optional node_exporter collectors (Linux)
- **CLI management** — manage keys and server config without a running server
- **GeoIP metrics** — per-country and per-ASN traffic stats with auto-updating MMDB databases
- **CLI management** — manage keys, server config, and VLESS targets without a running server
- **Atomic state persistence** — single YAML file with safe write-via-rename

## Quick Start

### Build from source
### Install on Ubuntu/Debian

```bash
go build ./cmd/shroud/
# Shadowsocks only
curl -fsSL https://bigbes.sourcecraft.dev/shroud/install.sh | sudo bash

# Shadowsocks + AmneziaWG
curl -fsSL https://bigbes.sourcecraft.dev/shroud/install.sh | sudo bash -s -- --awg --domain vpn.example.com

# Shadowsocks + VLESS+REALITY (auto-detects decoy server)
curl -fsSL https://bigbes.sourcecraft.dev/shroud/install.sh | sudo bash -s -- --vless
```

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

```bash
# Start the server
./shroud -c config.example.yaml
### Build from source

# With verbose logging
./shroud -c config.yaml -v
```bash
go build ./cmd/shroud/
go build -ldflags='-X main.version=1.0.0' ./cmd/shroud/  # with version
```

### Install on Ubuntu/Debian
### Run

```bash
curl -fsSL https://sourcecraft.dev/bigbes/shroud/raw/branch/main/install.sh | sudo bash
./shroud -c config.example.yaml      # start the server
./shroud -c config.yaml -v           # with verbose logging
```

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

## CLI Usage

```bash
# 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
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
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

# VLESS+REALITY management
shroud vless info -c config.yaml
shroud vless keygen                                          # generate x25519 keypair
shroud vless share 0 -c config.yaml                          # generate share link
shroud vless scan --addr 203.0.113.0/24                      # scan for decoy targets
shroud vless autodetect --write -c config.yaml               # auto-detect best decoy

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

## Configuration


@@ 71,7 86,7 @@ server:
  hostname: "example.com"

api:
  listen_addr: ":443"
  listen_addr: ":8081"

metrics:
  listen_addr: "127.0.0.1:8082"


@@ 92,7 107,14 @@ amneziawg:
  enabled: false
  listen_port: 443
  address: "10.14.0.0/24"
  domain: "vpn.example.com"            # For automatic Let's Encrypt certs
  domain: "vpn.example.com"            # for automatic Let's Encrypt certs

vless:
  enabled: false
  listen_addr: ":443"
  server_names:                        # SNIs accepted by REALITY handshake
    - www.microsoft.com
  dest: "www.microsoft.com:443"        # decoy forward target

state_file: state.yaml
```


@@ 141,6 163,9 @@ cmd/shroud/main.go     CLI entry point, cobra commands, signal handling
        +-> internal/metrics/   Prometheus registry + TransferTracker
        +-> internal/api/       REST API handlers (shadowbox-compatible)
        +-> internal/awgserver/ AmneziaWG server + HTTP/3 QUIC cover
        +-> internal/vless/     VLESS+REALITY proxy server
        +-> internal/reality/   TLS scanner + auto-detection for REALITY decoys
        +-> internal/mmdb/      GeoIP database downloader with auto-update
```

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`.


@@ 152,15 177,11 @@ The Shadowsocks proxy is imported as a Go library — not run as a subprocess. W
| [outline-ss-server](https://golang.getoutline.org/tunnel-server) | v1.9.3-rc2 | Shadowsocks proxy (used as library) |
| [outline-sdk](https://golang.getoutline.org/sdk) | v0.0.21 | Outline transport primitives |
| [amneziawg-go](https://github.com/amnezia-vpn/amneziawg-go) | v1.0.4 | DPI-resistant WireGuard implementation |
| [xtls/reality](https://github.com/XTLS/REALITY) | latest | REALITY protocol for TLS camouflage |
| [quic-go](https://github.com/quic-go/quic-go) | v0.59.0 | QUIC/HTTP3 for AWG cover traffic |
| [prometheus/client_golang](https://github.com/prometheus/client_golang) | v1.23.2 | Go Prometheus client and registry |
| [prometheus/node_exporter](https://github.com/prometheus/node_exporter) | v1.10.2 | OS-level metrics collectors (Linux) |

## Building with version info

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

## Testing

```bash