A lightweight HTTP server written in Go for serving files and directories over HTTP. Perfect for quick file sharing.
- Simple & Fast: Minimal overhead, easy to use
- File & Directory Serving: Serve individual files or entire directories (URL-encoded paths, nested folders, safe rejection of
..segments) - HTTP Range Support: Supports HTTP Range requests (206 Partial Content) for resuming downloads and partial file fetches
- Download Statistics: Track downloads with byte counts, per-client full/partial fetches, and optional activity/event logs
- Customizable Binding: Configure IP address and port
- HTTPS: Optional ephemeral self-signed certificate (
--https) or PEM--cert/--key(TLS and PROXY listener are not combined; see below) - Network Interface Detection: When binding to
0.0.0.0, automatically shows all available IP addresses - File Listing: Automatic HTML file listing at the root path (search, sort, optional QR codes, multi-file archive links when enabled)
- Glob Pattern Support: Use glob patterns to select multiple files
- Hidden File Filtering: Hidden files (starting with
.) are excluded from listings by default - File Hashing: Optional SHA1 hash calculation and display for files in listings
- Customizable Colors: Customize the color scheme of the file listing interface
- Bandwidth Limiting: Optional bandwidth throttling for file transfers
- Rate Limiting: Built-in DoS protection with per-IP request rate limiting (default: 20 req/s)
- Idle Timeout: Automatically shut down the server after a period of inactivity
- Share TTL & Caps: Optional time-to-live shutdown, total byte cap, per-file max download count, IP allow/deny lists
- HTTP Basic Auth: Optional username/password (or either alone)
- Optional WebDAV at
/webdav/(first shared path) - Encrypted downloads (
--encrypt): password-protected payload (AES-GCM over zstd; max 64 MiB per file; no Range) - One-time tokens:
GET /api/one-time-token, then append?token=to a URL (single successful GET) - Multi-file archives (
--single-stream):GET /archive(zstd or tar.gz) and UI checkboxes - Uploads (
--upload):POST /api/uploadwith multipart fieldfiles; optionalsubdir=; progress in the browser - Logging (
--log): Tee server messages to a file as well as stdout - Stats JSON:
GET /api/status; optional mirrorGET /statswith--stats - CLI
shareplane status: Print live stats from a running server (same data as/api/status) - Terminal
--tui: Full-screen live view of/api/status(uses Bubble Tea; use--logto keep server output on disk) - Real-time Progress: See download progress as files are served
- Graceful Shutdown: Print statistics on exit (SIGINT/SIGTERM)
go build -o shareplaneServe a single file:
./shareplane file.txtServe multiple files:
./shareplane file1.txt file2.txt file3.txtServe a directory:
./shareplane /path/to/directoryServe multiple files and directories:
./shareplane file.txt /path/to/dir1 /path/to/dir2-
--port: Port to listen on (default:8080)./shareplane --port 3000 file.txt
-
--url: Public base URL for generated links when behind a reverse proxy (e.g.https://share.example.comorhttp://192.168.1.5:8443). Used for M3U playlists and external-player stream URLs in the web UI. If omitted, the request host is used../shareplane --url https://files.example.com:8443 /path/to/share
-
--prefix/--suffix: Optional strings shown before/after each name in the HTML/API listing only (download URLs and paths are unchanged)../shareplane --prefix "[" --suffix "]" /path/to/share
-
--ip: IP address to bind to (default:0.0.0.0- all interfaces)./shareplane --ip 127.0.0.1 file.txt
When binding to
0.0.0.0, the server will display all available network interfaces and their IP addresses. -
--show-hidden: Show files and directories starting with a dot (.) in file listings (hidden files are hidden by default)./shareplane --show-hidden /path/to/directory
-
--hash: Calculate and display SHA1 hash for files in the listing./shareplane --hash /path/to/directory
-
--max-hash-size: Maximum file size (in bytes) to calculate hash for (0 = no limit, default: 0)./shareplane --hash --max-hash-size 10485760 /path/to/directory # Only hash files up to 10MB -
--bw-limit: Bandwidth limit for file transfers (e.g.,5MB,250KB,5M,1.4G, or plain bytes). No limit if not specified../shareplane --bw-limit 5MB /path/to/directory # Limit to 5MB/s ./shareplane --bw-limit 1.4G /path/to/directory # Limit to 1.4GB/s
-
--rate-limit: Rate limit: maximum requests per second per IP address (default: 20, use 0 to disable). Helps protect against DoS attacks while allowing normal browsing../shareplane --rate-limit 30 /path/to/directory # Allow 30 requests/second per IP ./shareplane --rate-limit 0 /path/to/directory # Disable rate limiting ./shareplane /path/to/directory # Uses default: 20 requests/second per IP
-
--reload: Enable auto-reload: monitor files for changes in real-time using file system notifications (new files, removed files, modified files)./shareplane --reload /path/to/directory
-
--idle: Idle timeout: server shuts down after this period of inactivity. Default: 15m if flag is set without value. Supports units: M (minutes), H (hours), D (days), W (weeks), Mo (months). Examples:15m,1H,4D,1W,1Mo./shareplane --idle file.txt # Default: 15 minutes ./shareplane --idle 30m /path/to/directory # 30 minutes ./shareplane --idle 2H /path/to/directory # 2 hours ./shareplane --idle 1D /path/to/directory # 1 day ./shareplane --idle 1W /path/to/directory # 1 week
-
--colours: Customize the color scheme of the file listing interface. Requires 7 comma-separated colors in this order:- Background (body background)
- Text (heading text)
- Table header Background
- Table header text
- Table Background
- Table filename text (link color)
- Table other text
./shareplane --colours "#000000,#FFFFFF,#FF0000,#FFFFFF,#CCCCCC,#0000FF,#333333" /path/to/directoryColors can be specified as hex codes (with or without
#) or named CSS colors (e.g.,red,blue,white). -
Environment Variables:
PORT: Set the port (same as--port)IP: Set the IP address (same as--ip)
--ttl: Stop the server after a duration from launch (plain number = minutes; or suffixes such asm,h,d,w,mo). Not persisted across restarts.--byte-limit: Stop serving after this many bytes have been transferred (same units as--bw-limit).--max-count: Maximum completed downloads per file (0= unlimited).--whitelist/--blacklist: Comma-separated client IPs or CIDRs (uses proxy-aware IP fromX-Forwarded-For, etc.).--basic-user/--basic-password: HTTP Basic authentication (either may be empty to check only the other).
--https: Listen with an ephemeral self-signed TLS certificate (not written to disk; browsers will warn).--cert/--key: Paths to PEM certificate and private key. If both are set, they take precedence over--https.
When TLS is enabled, the TCP listener uses TLS directly; the HAProxy PROXY protocol wrapper is not applied on that listener.
--qr: Show QR code buttons for direct download links in the listing.--webdav: Expose WebDAV at/webdav/(first shared path only).--encrypt: Password for encrypted download bodies (see implementation limits in--help).--log: Append server log output to a file as well as stdout.--single-stream: EnableGET /archive(formatszstdortar.gz) and archive checkboxes in the HTML UI.--stats: Also serveGET /statswith the same JSON as/api/status(Cache-Control: no-store).--tui: Run an interactive terminal dashboard polling/api/status(server runs in the background; prefer--logto capture server output).--upload: Directory that receives uploaded files (POST /api/upload). Created if missing; merged into listings when not already part of the shared paths.
Prints live stats from a running instance (wraps GET /api/status):
shareplane status
shareplane status --url https://127.0.0.1:8443Uses SHAREPLANE_URL when --url is omitted (default base http://127.0.0.1:8080).
Serve files on a custom port:
./shareplane --port 9000 document.pdf image.jpgServe only on localhost:
./shareplane --ip 127.0.0.1 --port 8080 /path/to/filesUse glob patterns:
./shareplane *.txt *.pdfShow hidden files in listings (hidden files are hidden by default):
./shareplane --show-hidden /path/to/directoryShow SHA1 hashes for files:
./shareplane --hash /path/to/directoryShow SHA1 hashes with size limit (only hash files up to 100MB):
./shareplane --hash --max-hash-size 104857600 /path/to/directoryLimit bandwidth to 5MB/s:
./shareplane --bw-limit 5MB /path/to/directoryCustomize colors with a dark theme:
./shareplane --colours "#1a1a1a,#e0e0e0,#2d2d2d,#ffffff,#252525,#4a9eff,#cccccc" /path/to/directoryCustomize colors with a light blue theme:
./shareplane --colours "#f0f8ff,#1a1a1a,#4a90e2,#ffffff,#ffffff,#0066cc,#333333" /path/to/directoryCustomize colors using named colors:
./shareplane --colours "black,white,red,white,gray,blue,darkgray" /path/to/directoryAccess files:
- Visit
http://localhost:8080/to see a file listing - Access files directly:
http://localhost:8080/filename.txt
Summary of useful routes (many require specific flags; see the in-app Endpoints box on the listing page):
| Path | Description |
|---|---|
/ |
HTML file browser |
/api/files |
JSON listing; optional ?path= |
/api/search |
Search; q= required; optional path= scope |
/api/status |
JSON: version, bytes, per-file and per-client stats, activity, events |
/stats |
Same JSON as /api/status when started with --stats |
/api/downloads |
Per-client IP and per-file full vs partial fetch counts |
/api/events |
JSON event log |
/events |
Server-Sent Events stream |
/verify |
JSON SHA1 for ?file= or ?path= (relative path) |
/manifest.json |
JSON manifest of shared items |
/api/one-time-token |
JSON { "token": "..." } for one-time ?token= access |
/archive |
Multi-file streaming archive when --single-stream (format=zstd or tar.gz, repeat paths=) |
/api/upload |
POST multipart field files; optional ?subdir= when --upload is set |
/webdav/ |
WebDAV root when --webdav |
Files support query modes such as ?mode=download (default), ?mode=preview, ?mode=play, ?mode=stream (see UI). Optional ?token= consumes a one-time token from /api/one-time-token.
The primary JSON API for file listings. This is useful for scripts, tools, and automation.
Returns a JSON response with file listings, totals, and metadata.
Query Parameters:
path(optional): Directory path to list. If not provided, lists all shared files/directories.
Response Format:
{
"files": [
{
"name": "/full/path/to/file.txt",
"displayName": "file.txt",
"size": 1024,
"modTime": "2024-01-01T12:00:00Z",
"hash": "abc123...",
"isDir": false
}
],
"totalSize": 1048576,
"fileCount": 10,
"showHash": true
}Response Fields:
files: Array of file/directory objectsname: Full absolute path (internal use)displayName: Relative path for displaysize: File size in bytesmodTime: Modification time (ISO 8601 format)hash: SHA1 hash (empty if not calculated or disabled)isDir: Boolean indicating if this is a directory
totalSize: Total size of all files in bytes (directories excluded)fileCount: Total number of files (directories excluded)showHash: Boolean indicating if hash calculation is enabled
List all shared files (root):
curl http://localhost:8080/api/filesList files in a specific directory:
curl "http://localhost:8080/api/files?path=subdirectory"Pretty-print JSON response:
curl http://localhost:8080/api/files | jqList files and extract only file names:
curl -s http://localhost:8080/api/files | jq -r '.files[] | select(.isDir == false) | .displayName'Get total size of all files:
curl -s http://localhost:8080/api/files | jq '.totalSize'List files with their sizes (formatted):
curl -s http://localhost:8080/api/files | jq -r '.files[] | "\(.displayName): \(.size) bytes"'Download a file using curl:
curl -O http://localhost:8080/filename.txtDownload with progress bar:
curl -# -O http://localhost:8080/largefile.zipResume a partial download:
curl -C - -O http://localhost:8080/largefile.zipCheck if a file exists (HEAD request):
curl -I http://localhost:8080/filename.txtGet file metadata without downloading:
curl -I http://localhost:8080/filename.txtList files in a nested directory:
curl "http://localhost:8080/api/files?path=docs/subdir"Filter directories only:
curl -s http://localhost:8080/api/files | jq '.files[] | select(.isDir == true) | .displayName'Get files with hashes (when --hash is enabled):
curl -s http://localhost:8080/api/files | jq '.files[] | select(.hash != "") | {name: .displayName, hash: .hash}'Save API response to file:
curl -s http://localhost:8080/api/files -o file_listing.jsonUse API in a script (bash example):
#!/bin/bash
API_URL="http://localhost:8080/api/files"
FILES=$(curl -s "$API_URL" | jq -r '.files[] | select(.isDir == false) | .displayName')
for file in $FILES; do
echo "Processing: $file"
# Your processing logic here
doneReplace HOST with your server (e.g. http://127.0.0.1:8080 or your public URL).
Download a file (save with remote filename):
curl -OJ "HOST/path/to/file.ext"Download to a specific local path:
curl -o "local-name.ext" "HOST/path/to/file.ext"Resume / partial download (Range is supported):
curl -C - -o "file.ext" "HOST/path/to/file.ext"Probe with HEAD (no body):
curl -I "HOST/path/to/file.ext"JSON file listing:
curl -s "HOST/api/files" | jq .
curl -s "HOST/api/files?path=relative/subdir" | jq .Search under a folder:
curl -s "HOST/api/search?q=part" | jq .
curl -s "HOST/api/search?q=part&path=relative/subdir" | jq .SHA1 for a file (path is relative to the share roots):
curl -s "HOST/verify?file=relative/path/file.ext" | jq .Upload (requires --upload DIR):
curl -s -F "files=@./local.txt" "HOST/api/upload"
# Optional subfolder under the upload root (must stay inside it):
curl -s -F "files=@./local.txt" "HOST/api/upload?subdir=incoming"The HTML listing shows an upload control with progress when --upload is set.
When binding to 0.0.0.0, the server will show output like:
Serving on http://0.0.0.0:8080
Available on:
http://192.168.1.100:8080
http://10.0.0.5:8080
http://127.0.0.1:8080
http://localhost:8080The server fully supports HTTP Range requests (RFC 7233), which enables:
- Resuming Downloads: Clients can resume interrupted downloads by requesting specific byte ranges
- Partial Fetches: Clients can request specific portions of files (e.g., for video streaming or large file processing)
- Efficient Transfers: Reduces bandwidth usage when only part of a file is needed
The server automatically handles Range headers and responds with 206 Partial Content when appropriate. This is transparent to users - any HTTP client that supports Range requests will automatically benefit from this feature.
When running behind a reverse proxy (such as frps, nginx, or Cloudflare), the server automatically detects and uses the real client IP address from proxy headers. The server checks the following headers in order:
X-Forwarded-For- Most common header, contains the original client IPX-Real-IP- Common in nginx and other proxiesX-Forwarded- Alternative format for forwarded IPsCF-Connecting-IP- Cloudflare-specific header
If no proxy headers are present, the server falls back to the connection's RemoteAddr. The real client IP is displayed in the download logs, making it easy to track which clients are downloading files even when behind a proxy.
The server tracks download statistics for each file:
- Number of times each file was downloaded
- Total bytes sent for each file
- Total bytes sent for file listings
- Per-client full vs partial fetches (see
/api/downloadsand/api/status)
Use shareplane status or GET /api/status (and optional GET /stats with --stats) for live aggregates while the server is running.
Statistics are also printed when the server is terminated (Ctrl+C or SIGTERM), and when using --tui after you quit the TUI.
See LICENSE file for details.