x2ssh is a CLI tool that provides SOCKS5 proxy functionality using SSH as the transport protocol. It enables users to route network traffic through an SSH server without requiring any manual server-side setup beyond a standard SSH installation.
- SOCKS5 Proxy: Application-level proxy for SOCKS5-compatible applications
- VPN Tunnel: System-level tunnel for all TCP and UDP traffic (see VPN.md)
- No raw port forwarding (
-L,-R) - use standard SSH for that - No shell/terminal access - use standard SSH for that
- No SSH server functionality - client only
- Unreliable retry logic: SSH's built-in reconnection is janky and inflexible
- Robust retry policies: Configurable backoff, max attempts, health checks
- Zero server setup: Works with any standard SSH server
- Cross-platform: Linux and Windows support
┌─────────────────────────────────────────────────────────────┐
│ CLIENT │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ CLI App │───▶│ Transport │──▶│ SSH Connection │──┼──▶ SSH Server
│ │ (x2ssh) │ │ Layer │ │ (russh) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ SOCKS5 │ │
│ │ Server │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ SERVER │
│ ┌─────────────┐ │
│ │ SSHD │ (existing SSH server, no setup required) │
│ │ (existing) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
x2ssh [OPTIONS] <USER@HOST>
Modes:
-D, --socks <ADDR> Start SOCKS5 proxy on specified address (e.g., 127.0.0.1:1080)
Connection:
-p, --port <PORT> SSH port [default: 22]
-i, --identity <FILE> Identity file (private key)
Retry Policy:
--retry-max <N> Maximum retry attempts [default: infinite]
--retry-delay <MS> Initial retry delay in ms [default: 1000]
--retry-backoff <N> Backoff multiplier [default: 2]
--retry-max-delay <MS> Maximum retry delay [default: 30000]
--health-interval <MS> Connection health check interval [default: 5000]
Examples:
x2ssh socks -D 127.0.0.1:1080 user@server.com # SOCKS5 proxy
x2ssh socks -D 1080 user@server.com # SOCKS5 proxy (shorthand)
x2ssh vpn user@server.com # VPN tunnel
The transport layer abstracts the SSH connection and provides:
- Connection Pooling: Reuse SSH sessions for multiple channels
- Health Monitoring: Periodic keepalive checks
- Auto-Reconnection: Transparent reconnection on failure
- Channel Management: Multiplex SOCKS5 connections over single SSH session
- Uses SSH's built-in
direct-tcpipchannel type - No server-side component needed
- Each SOCKS5 connection opens a new SSH channel
App → SOCKS5 → x2ssh → SSH channel → Server → Target
Retry Policy:
delay = min(initial_delay * backoff^attempt, max_delay)
Health Checks:
- Send SSH keepalive every
--health-interval - If no response within 3x interval, trigger reconnection
- Notify user of connection state changes
Graceful Reconnection:
- Preserve SOCKS5 connections during brief reconnects (buffering)
- Async I/O: Tokio runtime for all operations
- Zero-Copy: Avoid unnecessary buffer copies
- Connection Multiplexing: Single SSH session for all channels
- Efficient Polling: Use epoll/kqueue/IOCP based on platform
- CLI argument parsing with clap
- SSH connection management (russh)
- Retry policy implementation
- Health monitoring
- SOCKS5 server implementation
- SSH channel forwarding
- DNS resolution handling
- Server-side UDP agent (see VPN.md)
- TUN interface setup (Linux + Windows)
- Packet parsing and forwarding
- Routing configuration
- Agent deployment and lifecycle
- Configuration file support
- Logging and diagnostics
- Performance optimization
- Documentation
Rust:
| Crate | Purpose |
|---|---|
russh |
SSH client implementation |
tokio |
Async runtime with multi-threaded executor |
clap |
CLI argument parsing with derive macros |
fast-socks5 |
SOCKS5 protocol implementation |
tracing |
Structured logging |
tracing-subscriber |
Logging output formatting |
anyhow |
Error handling |
Python (E2E tests):
| Package | Purpose |
|---|---|
pytest |
Test framework |
pytest-asyncio |
Async test support |
testcontainers |
Docker container management |
pysocks |
SOCKS5 client for testing |
ty |
Fast Rust-based type checker |
ruff |
Fast Python linter and formatter |
- Key Management: Support SSH agent, key files, encrypted keys
- Server Verification: Strict host key checking (with option to disable)
- No Secrets in Logs: Sanitize sensitive data from log output
Tests are split into two separate projects:
- Rust Unit Tests: Fast, in-process tests for pure logic (retry calculations, CLI parsing, transport internals)
- Python Integration Tests: Black-box tests using the compiled binary with Docker SSH containers
This separation:
- Keeps Rust code clean (no testcontainers dependency)
- Enables faster Rust builds
- Tests the actual binary behavior, not library internals
- Leverages Python's rich testing ecosystem
# Rust Workspace
proto/ # Shared protocol code
└── src/
└── framing.rs # Length-prefixed packet framing
x2ssh/ # Main binary
└── src/
├── retry.rs # Unit tests for retry logic
├── transport.rs # Unit tests for transport (no Docker needed)
├── socks.rs # SOCKS5 server implementation
├── main.rs # CLI and main application logic
└── lib.rs # Library entry point
x2ssh-agent/ # Server-side VPN agent (deployed over SSH)
└── src/
└── main.rs # Simple TUN bridge (~100 lines)
# Python Integration Tests (separate uv-managed project)
tests/
├── pyproject.toml # uv project configuration
├── ssh_server.py # Docker container wrapper
├── socks5_client.py # SOCKS5 test client
├── tests/
│ └── test_socks5.py # SOCKS5 proxy tests
├── conftest.py # pytest fixtures
└── fixtures/ # Test fixtures
├── Dockerfile # SSH server image with echo server
└── keys/ # Pre-generated test keys
scripts/
├── check.sh # Run all checks (Rust + Python)
├── build-test-image.sh # Build Docker test image
└── generate-test-keys.sh # Generate SSH keys for testing
Unit Tests (Rust):
cargo testIntegration Tests (Python):
# One-time setup
./scripts/build-test-image.sh
# Run from repo root (uses uv workspace)
uv run pytest
uv run ty check # Type check with ty (Rust-based, fast)Full Project Check:
./scripts/check.sh # Run all checks (Rust + Python)
./scripts/check.sh -v # Verbose mode with full outputThe project uses a uv workspace (similar to Cargo workspaces) to manage the Python integration tests:
x2ssh/
├── pyproject.toml # Workspace root configuration
├── uv.lock # Shared lockfile for entire workspace
└── tests/
├── pyproject.toml # Package configuration (member of workspace)
└── src/x2ssh_e2e/ # Package source
Key workspace features:
- Single lockfile (
uv.lockat root) ensures consistent dependencies - Run commands from repo root with
uv run <command> - No need to
cdinto tests directory - Works like
cargo- workspace-aware commands from anywhere in the repo
- Per-test container (isolated, parallel-safe)
- Pre-baked SSH keys for deterministic auth
- Random host port mapping to avoid conflicts
- Auto-cleanup on test completion
To regenerate the test SSH keys in tests/fixtures/keys/:
./scripts/generate-test-keys.shThis creates a deterministic ED25519 key pair for automated testing.