A lightweight, authenticated artifact relay service designed for high-security environments.
Project B21 is a secure, authenticated streaming relay written in Go. It enables the retrieval of external artifacts (updates, binaries, patches) into restrictive network environments where direct access to third-party domains is blocked or unstable.
Unlike standard proxies, B21 does not expose a full internet gateway. Instead, it creates a single-purpose, verified tunnel for authorized file transfers using strict "Defense in Depth" mechanisms. Its primary design goal is stealth and minimal footprint.
- π TOTP Authentication - Zero-trust access control using Time-based One-Time Passwords (RFC 6238)
- β‘ Streaming Proxy - Downloads files from any URL using efficient
io.Reader/Writerpipes (constant low RAM usage) - π΅οΈ Stealth Operations - Masks traffic as generic binary data (
application/octet-stream) to bypass file-type filters - β―οΈ Resumable Downloads - Full support for
Rangeheaders, allowing large file transfers to be paused, resumed, or chunked - π Audit Logging - Comprehensive request logging with timestamping and Real IP detection (via
X-Forwarded-For) - π‘οΈ Thread-Safe - Concurrent-safe logging with mutex protection for reliability under load
- π¦ Minimal Dependencies - Compiles into a single, statically-linked binary
- π Connection Testing - Simple GET endpoint to verify server availability
.
βββ .github/
β βββ workflows/
β βββ keygen.yml # CI/CD for key generator deployment
β βββ server.yml # CI/CD for server deployment
βββ cmd/
β βββ keygen.go # Utility to generate TOTP secrets and QR codes
βββ server/
β βββ handlers.go # Core HTTP request logic (Proxy, Logs, Range Support)
βββ totp/
β βββ totp.go # TOTP validation wrapper
βββ utils/
β βββ logger.go # Thread-safe logging utility
βββ .gitattributes # Git configuration for line endings
βββ .gitignore # Git ignore patterns
βββ go.mod # Go module dependencies
βββ main.go # Application entry point
βββ README.md # Documentation (this file)
- Go 1.25.3 or higher (required only for development and building binaries)
- An authenticator app (Google Authenticator, Authy, 1Password, etc.)
- Access to a VPS or external server to host the relay (optional for production)
-
Clone the repository:
git clone https://github.com/Aditya-0011/B21 cd B21 -
Install dependencies:
go mod download
Before running the server, you must generate a secure TOTP secret.
The keygen.go utility generates a TOTP secret and QR code for use with authenticator apps.
Linux / macOS:
ISSUER="B21-Relay" ACCOUNT_NAME="Admin" go run cmd/keygen.goWindows (PowerShell):
$env:ISSUER="B21-Relay"; $env:ACCOUNT_NAME="Admin"; go run .\cmd\keygen.goOutput:
- A Secret Key (save this securely!)
- A QR Code printed in the terminal (scan with your authenticator app)
- A
code.pngfile (backup image)
Configure the server environment before running.
| Variable | Description | Default | Required |
|---|---|---|---|
TOTP_SECRET |
The secret generated in Step 1 | N/A | β Yes |
PORT |
The port the server listens on | 7000 |
β No |
LOG_FILE |
Path to the log file | proxy.log |
β No |
ISSUER |
Server/service name (for keygen only) | Server |
β No |
ACCOUNT_NAME |
Account identifier (for keygen only) | Admin |
β No |
Example:
Linux / macOS:
export TOTP_SECRET="YOUR_SECRET_HERE"
export PORT="8080"
export LOG_FILE="/var/log/b21.log"Windows (PowerShell):
$env:TOTP_SECRET="YOUR_SECRET_HERE"
$env:PORT="8080"
$env:LOG_FILE="C:\logs\b21.log"Run directly with Go:
go run main.goFor stealth deployments, strip debug symbols using -ldflags "-s -w" to reduce binary size.
Linux / macOS:
GOOS=linux GOARCH=arm64 go build -ldflags "-s -w" -o b21 main.goWindows (if development environment is Windows):
$env:GOOS="linux"; $env:GOARCH="arm64"; go build -ldflags "-s -w" -o b21 main.goπ‘ Tip: Adjust
GOOSandGOARCHfor your target platform. Common combinations:
- Linux AMD64:
GOOS=linux GOARCH=amd64- Linux ARM64:
GOOS=linux GOARCH=arm64- Windows AMD64:
GOOS=windows GOARCH=amd64- macOS ARM64:
GOOS=darwin GOARCH=arm64
Simple endpoint to verify server availability.
- Method:
GET - URL:
/ - Authentication: None required
- Response: Current server timestamp in RFC3339 format
Example:
curl https://example.com/Response:
2024-01-15T10:30:45Z
Relays a file from a remote URL to the client. Supports Range headers for resumable downloads.
- Method:
POST - URL:
/ - Headers:
Content-Type: application/json - Authentication: TOTP required
Stealth Behavior: The server forces the response filename to resource.dat and content-type to application/octet-stream to avoid firewall blocking. You must rename the file locally.
Request Body:
{
"url": "https://example-cdn.com/file.zip",
"otp": "123456"
}Example:
# Basic download
curl -X POST https://example.com/ \
-H "Content-Type: application/json" \
-d '{"url":"https://example-cdn.com/file.zip","otp":"123456"}' \
-o downloaded-file.zip
# Download with rate limiting (recommended for stealth)
curl --limit-rate 2M -X POST https://example.com/ \
-H "Content-Type: application/json" \
-d '{"url":"https://example-cdn.com/file.zip","otp":"123456"}' \
-o large-file.zipcURL Options Explained:
--limit-rate 2M- Limit bandwidth to 2MB/s (blends with video traffic patterns)-o filename- Save output to specified file (rename fromresource.dat)
Important: curl's -C - flag does not work with POST requests. To resume an interrupted download, you must manually specify the byte offset.
Quick Resume (Practical Example):
Let's say your some-secret.zip download got interrupted. Here's how to resume:
Windows (PowerShell):
# Step 1: Check your partial file size
$bytes = (Get-Item some-secret.zip).Length
Write-Host "File size: $bytes bytes - Use this in Range header"
# Step 2: Resume download (replace YOUR_BYTE_SIZE with the number from above)
curl --limit-rate 2M -X POST https://example.com/ `
-H "Content-Type: application/json" `
-H "Range: bytes=$bytes-" `
-d "{`"url`":`"https://example-cdn.com/large-file.zip`",`"otp`":`"123456`"}" `
--output some-secret.zipLinux/macOS (Bash):
# Step 1: Check your partial file size
bytes=$(stat -c%s some-secret.zip) # Linux
# bytes=$(stat -f%z some-secret.zip) # macOS
echo "File size: $bytes bytes - Use this in Range header"
# Step 2: Resume download (the $bytes variable is automatically used)
curl --limit-rate 2M -X POST https://example.com/ \
-H "Content-Type: application/json" \
-H "Range: bytes=$bytes-" \
-d '{"url":"https://example-cdn.com/large-file.zip","otp":"123456"}' \
-o some-secret.zipWait, what about overwriting?
-o (output) flag in curl will overwrite your partial file if you don't handle it carefully. Here are two safe approaches:
Option 1: Use a different filename, then combine
Windows (PowerShell):
# Download remaining part to a new file
curl ... -o some-secret-part2.zip
# Then combine files
Get-Content some-secret.zip, some-secret-part2.zip -Encoding Byte | Set-Content some-secret-complete.zip -Encoding ByteLinux/macOS (Bash):
# Download remaining part to a new file
curl ... -o some-secret-part2.zip
# Then combine files
cat some-secret.zip some-secret-part2.zip > some-secret-complete.zipOption 2: Let curl write directly (but backup first)
Windows (PowerShell):
# Make a backup just in case
Copy-Item some-secret.zip some-secret-backup.zip
# Now resume - curl will handle the Range request properly
curl --limit-rate 2M -X POST https://example.com/ `
-H "Range: bytes=123838464-" `
... `
-o some-secret.zipLinux/macOS (Bash):
# Make a backup just in case
cp some-secret.zip some-secret-backup.zip
# Now resume - curl will handle the Range request properly
curl --limit-rate 2M -X POST https://example.com/ \
-H "Range: bytes=123838464-" \
... \
-o some-secret.zipπ‘ Pro Tip: When the server properly supports Range requests (which B21 does), and you specify the exact byte offset that matches your file size, curl should only receive the remaining bytes. However, always keep a backup or use separate files to be safe!
How It Works:
- You check your partial file size (e.g., 50MB = 52428800 bytes)
- You send a
Range: bytes=52428800-header, telling the server to start from byte 52428800 - B21 forwards this Range header to the upstream server
- The upstream server returns only the remaining data with
206 Partial Content - You append this data to your existing file, completing the download
Note: Resume functionality requires the upstream URL to support HTTP Range requests. Most modern CDNs and file servers do.
Response Headers:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=resource.dat
Accept-Ranges: bytes
Content-Length: [file size]
Securely fetches the server's internal activity logs via a non-blocking snapshot.
- Method:
POST - URL:
/logs - Headers:
Content-Type: application/json - Authentication: TOTP required
Request Body:
{
"otp": "123456"
}Example:
curl -X POST https://example.com/logs \
-H "Content-Type: application/json" \
-d '{"otp":"123456"}' \
-o server-logs.txtLog Contents:
The log file contains timestamped entries including:
- Server startup events
- Authentication attempts (success/failure)
- Download requests with IP addresses
- Data transfer statistics
- Errors and exceptions
- Authentication Layer - Every request is validated against the
TOTP_SECRET. No public access is allowed. - Traffic Masking - All outgoing files are masqueraded as generic binary data (
resource.dat/application/octet-stream). - Concurrency Protection - Log files are protected by
utils.LogMutexto prevent race conditions. - Minimal Attack Surface - Only POST/GET requests are accepted. No query parameters or complex headers are parsed.
- IP Logging - Real client IPs are extracted via
X-Forwarded-Forheader (supports reverse proxy scenarios).
The server handles various error scenarios with appropriate HTTP status codes:
| Scenario | HTTP Status | Response | Logged As |
|---|---|---|---|
| Invalid HTTP method | 405 |
"Method not allowed" | [INVALID METHOD] |
| Invalid or expired OTP | 403 |
"Invalid OTP" | [AUTH FAIL] |
| Missing TOTP secret | 500 |
"Server error" | [ERROR] |
| Unable to reach target URL | 502 |
"Failed to reach target" | [ERROR] |
All operations are logged to both console output and the configured log file (default: proxy.log).
[INFO]- Informational messages (connection tests)[PROXY]- Download operations[SUCCESS]- Successful file transfers[AUTH FAIL]- Failed authentication attempts[INVALID METHOD]- Invalid HTTP methods[ERROR]- Server errors[ADMIN]- Log export operations
2024/01/15 10:30:45 [PROXY] Starting download: https://example.com/file.zip (IP: 192.168.1.100)
2024/01/15 10:31:02 [SUCCESS] Transferred 104857600 bytes
The utils.Logger uses a mutex (utils.LogMutex) to ensure thread-safe writes during concurrent requests.
This project uses minimal external dependencies:
github.com/pquerna/otp- TOTP generation and validationgithub.com/boombuler/barcode- QR code generation for TOTP setup (keygen only)github.com/mdp/qrterminal/v3- Terminal QR code rendering (keygen only)
All dependencies are declared in go.mod.
This project includes GitHub Actions workflows for automated deployment:
.github/workflows/server.yml- Builds and deploys the main server binary (b21).github/workflows/keygen.yml- Builds and deploys the key generator utility
Triggers:
- Push tags matching
server*for server deployment - Push tags matching
keygen*for keygen deployment
Example:
# Deploy server
git tag server-v1.0.0
git push origin server-v1.0.0
# Deploy keygen
git tag keygen-v1.0.0
git push origin keygen-v1.0.0- Bandwidth Throttling - Server-side rate limiting to enforce "Low and Slow" traffic profiles automatically
- Client CLI - A dedicated Go CLI tool to handle automated downloads, local file renaming, and seamless resume functionality (no manual Range headers needed)
- Metrics Dashboard - Real-time monitoring of transfer statistics