Skip to content

Repository files navigation

WSG - Wings SFTP Gateway

WSG is a small SSH/SFTP gateway for Pterodactyl Wings nodes.

Put one public SFTP endpoint in front of many Wings nodes, then route each login to the correct node. This is useful when the nodes are reachable over private infrastructure such as Tailscale, WireGuard, a private VLAN, or another reverse-tunnel/backbone network.

The gateway does not replace Wings authentication. Clients still log in with the normal Pterodactyl SFTP username and password. WSG forwards the connection to the selected Wings node and lets Wings decide whether the login is valid.

Typical Topology

Internet
  |
  | sftp.example.com:2022
  v
WSG gateway
  |
  | private network / VPN / tunnel backbone
  |
  +-- wings-atlanta:2022
  +-- wings-boston:2022
  +-- wings-frankfurt:2022

A common deployment is:

  • Run WSG on one public edge server.
  • Connect all Wings nodes and the WSG server to the same private network, for example Tailscale.
  • Expose only WSG to users.
  • Keep Wings SFTP ports private or firewall them to the backbone.
  • Point the panel/user-facing SFTP hostname at WSG.

This gives you one stable SFTP endpoint while keeping node-to-node connectivity off the public internet.

Username Format

WSG expects Pterodactyl-style SFTP usernames:

username.serveruuid

Example:

admin.a1b2c3d4

The suffix is the first 8 hex characters of the server UUID. WSG uses it to find the target node. The password is still checked by Wings.

Deployment With GHCR

The published image is available from GitHub Container Registry:

docker pull ghcr.io/langduamc/wsg:latest

Run it with a mounted config and persistent host key directory:

docker run -d \
  --name wsg \
  --restart unless-stopped \
  -p 2022:2022 \
  -v $(pwd)/gateway.toml:/app/gateway.toml:ro \
  -v $(pwd)/data:/app/data \
  ghcr.io/langduamc/wsg:latest \
  wsg /app/gateway.toml

Use a fixed image tag in production if you do not want automatic updates when latest changes:

docker pull ghcr.io/langduamc/wsg:main

Build From Source

cargo build --release
./target/release/wsg gateway.toml

Requirements when running outside Docker:

  • Rust 1.85 or newer
  • ssh-keygen from OpenSSH on PATH
  • TCP access from WSG to each Wings node SFTP port

Configure Networking

Tailscale Example

Install and join Tailscale on the WSG server and every Wings node.

On the WSG server:

sudo tailscale up

On each Wings node:

sudo tailscale up

Use the node's Tailscale DNS name or Tailscale IP in gateway.toml:

[node.a1b2c3d4]
sftp = "wings-atlanta.tailnet-name.ts.net:2022"

[node.e5f6a7b8]
sftp = "100.92.10.44:2022"

Firewall suggestion:

  • Public internet can reach WSG on 2022.
  • WSG can reach Wings nodes on their SFTP port over Tailscale.
  • Public internet cannot reach Wings SFTP directly.

Reverse Tunnel Or Private Backbone

If nodes sit behind NAT, terminate your tunnel/backbone so WSG can dial a stable private address for each Wings SFTP service.

Examples of valid sftp values:

[node.a1b2c3d4]
sftp = "10.10.0.12:2022"

[node.e5f6a7b8]
sftp = "boston.internal.example:2022"

WSG only needs normal TCP connectivity to the backend SFTP address.

Configuration Modes

WSG has two ways to map a server UUID suffix to a Wings node.

Static Node Config

Use this when you want explicit routing in gateway.toml and do not want WSG to call the panel API.

In static mode, each [node.<server_uuid_prefix>] key should be the 8-character server UUID suffix that users place after the username. The api value still needs to exist in the TOML file, but it is not used when api_key is empty.

api = "https://panel.example.com"
api_key = ""

[listen]
bind = "0.0.0.0"
port = 2022

[ssh]
host_key_path = "data/host_key"
max_auth_tries = 6
auth_rejection_time_secs = 3

[node.a1b2c3d4]
sftp = "wings-atlanta.tailnet-name.ts.net:2022"

[node.e5f6a7b8]
sftp = "wings-boston.tailnet-name.ts.net:2022"

[logging]
level = "info"

[rate_limit]
connections_per_sec = 5.0
auth_per_minute = 30
burst_size = 10

Static mode is selected when api_key is empty.

Panel API Config

Use this when WSG should resolve the server UUID through the Pterodactyl Application API.

api = "https://panel.example.com"
api_key = "ptla_your_application_api_key"

[listen]
bind = "0.0.0.0"
port = 2022

[ssh]
host_key_path = "data/host_key"
max_auth_tries = 6
auth_rejection_time_secs = 3

[cache]
capacity = 5000
ttl_secs = 60

[logging]
level = "info"

[rate_limit]
connections_per_sec = 5.0
auth_per_minute = 30
burst_size = 10

The panel API key must be an Application API key that can read servers and node data.

Configuration Reference

Key Default Description
api required Panel base URL. Used in Panel API mode.
api_key "" Application API key. Empty enables static node mode.
[listen].bind "0.0.0.0" Address WSG listens on.
[listen].port 2022 Public SFTP port served by WSG.
[ssh].host_key_path "data/host_key" SSH host key path. Generated on first start if missing.
[ssh].max_auth_tries 6 Maximum SSH auth attempts per connection.
[ssh].auth_rejection_time_secs 3 Delay before rejecting failed auth attempts.
[node.<server_uuid_prefix>].sftp none Backend Wings SFTP address for static mode. The table key should be the same 8-character suffix used in the login username.
[cache].capacity 5000 Panel lookup cache size.
[cache].ttl_secs 60 Panel lookup cache TTL in seconds.
[logging].level "info" Log filter, for example info, debug, or wsg=debug.
[rate_limit].connections_per_sec 5.0 Per-IP connection rate limit.
[rate_limit].auth_per_minute 30 Per-IP and username auth attempt limit.
[rate_limit].burst_size 10 Token bucket burst size.

Operational Notes

  • Persist /app/data or the configured host key path. If the host key changes, SFTP clients will see a host key warning.
  • Put WSG behind your normal firewall/security group. Only expose the SFTP port you intend users to access.
  • Backend sftp addresses should be reachable from WSG before starting the service.
  • Public key login is passed through to Wings as SSH public key/none auth. Whether it works depends on your Wings setup.
  • Shell, exec, and PTY requests are rejected. This gateway is for SFTP.

License

MIT

About

Wings SFTP Gateway - Multi node reverse proxy

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages