-
Couldn't load subscription status.
- Fork 869
Description
Feature Request: Add Shadowsocks over WebSocket (SS over WSS) Support
Fork where changes were made: https://github.com/unredacted/outline-server
Summary
Add support for tunneling Shadowsocks traffic over WebSocket connections to enhance censorship resistance and improve connectivity in restrictive network environments.
Motivation
Current Limitations
The current Outline Server implementation only supports direct Shadowsocks connections, which can be problematic in several scenarios:
- Deep Packet Inspection (DPI): Modern censorship systems can detect and block Shadowsocks traffic patterns
- Corporate Firewalls: Many enterprise networks only allow HTTP/HTTPS traffic through proxies
- Network Restrictions: Some networks block non-standard ports or protocols
- Protocol Fingerprinting: Direct Shadowsocks connections have identifiable characteristics
Proposed Solution
I've implemented a complete solution that adds WebSocket transport support while maintaining backward compatibility. The implementation allows servers to support both traditional Shadowsocks connections and WebSocket-tunneled connections simultaneously.
Key Features
- Flexible Configuration: Each access key can optionally enable WebSocket transport
- Dual Protocol Support: Separate paths for TCP and UDP over WebSocket
- Dynamic Client Configuration: Automatically generates appropriate client configs
- Backward Compatible: Servers without WebSocket keys continue using the legacy format
- Mixed Mode Operation: Supports both WebSocket and traditional clients simultaneously
API Changes
New WebSocket configuration options for access keys:
{
"name": "User with WebSocket",
"websocket": {
"enabled": true,
"tcpPath": "/tcp",
"udpPath": "/udp",
"domain": "example.com",
"tls": true
}
}Configuration Format
The implementation automatically generates the appropriate outline-ss-server configuration:
When WebSocket keys exist:
web:
servers:
- id: outline-ws-server
listen:
- '127.0.0.1:8080'
services:
- listeners:
- type: tcp
address: '[::]:443'
- type: udp
address: '[::]:443'
keys:
- id: '0'
cipher: chacha20-ietf-poly1305
secret: <secret>
- listeners:
- type: websocket-stream
web_server: outline-ws-server
path: /tcp
- type: websocket-packet
web_server: outline-ws-server
path: /udp
keys:
- id: '1'
cipher: chacha20-ietf-poly1305
secret: <secret>Client Configuration
WebSocket-enabled keys return dynamic YAML configuration:
transport:
$type: tcpudp
tcp:
$type: shadowsocks
endpoint:
$type: websocket
url: 'wss://example.com/tcp'
cipher: chacha20-ietf-poly1305
secret: <secret>
udp:
$type: shadowsocks
endpoint:
$type: websocket
url: 'wss://example.com/udp'
cipher: chacha20-ietf-poly1305
secret: <secret>Implementation Details
Components Modified
- API Schema (
api.yml): Added WebSocketConfig schema - Data Model (
access_key.ts): Extended interfaces for WebSocket support - Manager Service (
manager_service.ts): Added validation and dynamic config generation - Access Key Repository (
server_access_key.ts): Stores WebSocket configuration - Shadowsocks Server (
outline_shadowsocks_server.ts): Generates WebSocket-aware configs - Dependencies: Updated to outline-ss-server v1.9.2 with WebSocket support
Reverse Proxy Setup
The WebSocket server runs on a separate port (8080) and requires reverse proxy configuration with nginx example below:
location /tcp {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /udp {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}This can also be fronted by using something like Cloudflare Tunnel.
Testing
The implementation has been thoroughly tested with:
- Creating WebSocket-enabled access keys via API
- Generating proper server configurations for mixed environments
- Client connections using dynamic access key configurations
- Simultaneous traditional and WebSocket client connections
- Multi-platform Docker image builds (amd64/arm64)
Future Enhancements
- Configurable WebSocket Port: Currently hardcoded to 8080
- Custom Headers: Support for additional WebSocket headers
- Path Randomization: Generate random paths for enhanced security
Contribution
I have a working implementation in my fork that I'm ready to contribute. The code:
- Maintains backward compatibility
- Follows existing code patterns and conventions
- Includes proper error handling and validation
- Has been tested in production environments
Would the team be interested in reviewing a pull request for this feature? I'm happy to make any adjustments to align with the project's goals and standards.