A lightweight SSH-based tunnel server written in Go that enables secure TCP and HTTP forwarding with an interactive terminal interface for managing connections and custom subdomains.
- SSH interactive session with real-time command handling
- Custom subdomain management for HTTP tunnels
- Dual protocol support: HTTP and TCP tunnels
- Real-time connection monitoring
- Go 1.18 or higher
- Valid domain name for subdomain routing
The following environment variables can be configured in the .env file:
| Variable | Description | Default | Required |
|---|---|---|---|
DOMAIN |
Domain name for subdomain routing | localhost |
No |
PORT |
SSH server port | 2200 |
No |
HTTP_PORT |
HTTP server port | 8080 |
No |
HTTPS_PORT |
HTTPS server port | 8443 |
No |
TLS_ENABLED |
Enable TLS/HTTPS | false |
No |
TLS_REDIRECT |
Redirect HTTP to HTTPS | false |
No |
ACME_EMAIL |
Email for Let's Encrypt registration | admin@<DOMAIN> |
No |
CF_API_TOKEN |
Cloudflare API token for DNS-01 challenge | - | Yes (if auto-cert) |
ACME_STAGING |
Use Let's Encrypt staging server | false |
No |
CORS_LIST |
Comma-separated list of allowed CORS origins | - | No |
ALLOWED_PORTS |
Port range for TCP tunnels (e.g., 40000-41000) | 40000-41000 |
No |
BUFFER_SIZE |
Buffer size for io.Copy operations in bytes (4096-1048576) | 32768 |
No |
PPROF_ENABLED |
Enable pprof profiling server | false |
No |
PPROF_PORT |
Port for pprof server | 6060 |
No |
Note: All environment variables now use UPPERCASE naming. The application includes sensible defaults for all variables, so you can run it without a .env file for basic functionality.
The server supports automatic TLS certificate generation and renewal using CertMagic with Cloudflare DNS-01 challenge. This is required for wildcard certificate support (*.yourdomain.com).
Certificate Storage:
- TLS certificates are stored in
certs/tls/(relative to application directory) - User-provided certificates:
certs/tls/cert.pemandcerts/tls/privkey.pem - CertMagic automatic certificates:
certs/tls/certmagic/ - SSH keys are stored separately in
certs/ssh/
How it works:
- If user-provided certificates exist at
certs/tls/cert.pemandcerts/tls/privkey.pemand cover bothDOMAINand*.DOMAIN, they will be used - If certificates are missing, expired, expiring within 30 days, or don't cover the required domains, CertMagic will automatically obtain new certificates from Let's Encrypt
- Certificates are automatically renewed before expiration
- User-provided certificates support hot-reload (changes detected every 30 seconds)
Cloudflare API Token Setup:
To use automatic certificate generation, you need a Cloudflare API token with the following permissions:
- Go to Cloudflare Dashboard
- Click "Create Token"
- Use "Create Custom Token" with these permissions:
- Zone → Zone → Read (for all zones or specific zone)
- Zone → DNS → Edit (for all zones or specific zone)
- Copy the token and set it as
CF_API_TOKENenvironment variable
Example configuration for automatic certificates:
DOMAIN=example.com
TLS_ENABLED=true
CF_API_TOKEN=your_cloudflare_api_token_here
ACME_EMAIL=admin@example.com
# ACME_STAGING=true # Uncomment for testing to avoid rate limitsThe application will automatically generate a new 4096-bit RSA key pair at certs/ssh/id_rsa if it doesn't exist. This makes it easier to get started without manually creating SSH keys. SSH keys are stored separately from TLS certificates.
The application uses a buffer pool with controlled buffer sizes to prevent excessive memory usage under high concurrent loads. The BUFFER_SIZE environment variable controls the size of buffers used for io.Copy operations:
- Default: 32768 bytes (32 KB) - Good balance for most scenarios
- Minimum: 4096 bytes (4 KB) - Lower memory usage, more CPU overhead
- Maximum: 1048576 bytes (1 MB) - Higher throughput, more memory usage
Recommended settings based on load:
- Low traffic (<100 concurrent):
BUFFER_SIZE=32768(default) - High traffic (>100 concurrent):
BUFFER_SIZE=16384orBUFFER_SIZE=8192 - Very high traffic (>1000 concurrent):
BUFFER_SIZE=8192orBUFFER_SIZE=4096
The buffer pool reuses buffers across connections, preventing memory fragmentation and reducing garbage collection pressure.
To enable profiling for performance analysis:
- Set
PPROF_ENABLED=truein your.envfile - Optionally set
PPROF_PORTto your desired port (default: 6060) - Access profiling data at
http://localhost:6060/debug/pprof/
Common pprof endpoints:
/debug/pprof/- Index page with available profiles/debug/pprof/heap- Memory allocation profile/debug/pprof/goroutine- Stack traces of all current goroutines/debug/pprof/profile- CPU profile (30-second sample by default)/debug/pprof/trace- Execution trace
Example usage with go tool pprof:
# Analyze CPU profile
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
# Analyze memory heap
go tool pprof http://localhost:6060/debug/pprof/heapThree Docker Compose configurations are available for different deployment scenarios. Each configuration uses the image git.fossy.my.id/bagas/tunnel-please:latest.
File: docker-compose.root.yml
Advantages:
- Full TCP port forwarding support (ports 40000-41000)
- Direct binding to privileged ports (80, 443, 2200)
- Best performance with no NAT overhead
- Maximum flexibility for all tunnel types
- No port mapping limitations
Use Case: Production deployments where you need unrestricted TCP forwarding and maximum performance.
Deploy:
docker-compose -f docker-compose.root.yml up -dFile: docker-compose.standard.yml
Advantages:
- Runs with unprivileged user (more secure)
- Standard port mappings (2200, 80, 443)
- Simple and predictable networking
- TCP port forwarding disabled (
ALLOWED_PORTS=none)
Use Case: Deployments where you only need HTTP/HTTPS tunneling without custom TCP port forwarding.
Deploy:
docker-compose -f docker-compose.standard.yml up -dFile: docker-compose.tcp.yml
Advantages:
- Runs with unprivileged user (more secure)
- Standard port mappings (2200, 80, 443)
- Limited TCP forwarding (ports 30000-31000)
- Controlled port range exposure
Use Case: Deployments where you need both HTTP/HTTPS tunneling and limited TCP forwarding within a specific port range.
Deploy:
docker-compose -f docker-compose.tcp.yml up -d- Choose your configuration based on your requirements
- Edit the environment variables in the chosen compose file:
DOMAIN: Your domain name (e.g.,example.com)ACME_EMAIL: Your email for Let's EncryptCF_API_TOKEN: Your Cloudflare API token (if using automatic TLS)
- Deploy:
docker-compose -f docker-compose.root.yml up -d
- Check logs:
docker-compose -f docker-compose.root.yml logs -f
- Stop the service:
docker-compose -f docker-compose.root.yml down
All configurations use a named volume certs for persistent storage:
- SSH keys:
/app/certs/ssh/ - TLS certificates:
/app/certs/tls/
To backup certificates:
docker run --rm -v tunnel_pls_certs:/data -v $(pwd):/backup alpine tar czf /backup/certs-backup.tar.gz -C /data .To restore certificates:
docker run --rm -v tunnel_pls_certs:/data -v $(pwd):/backup alpine tar xzf /backup/certs-backup.tar.gz -C /dataUse docker-compose.root.yml for production deployments if you need:
- Full TCP port forwarding capabilities
- Any port range configuration
- Direct port binding without mapping overhead
- Maximum performance and flexibility
This is the recommended configuration for most use cases as it provides the complete feature set without limitations.
Contributions are welcome!
If you'd like to contribute to this project, please follow the workflow below:
- Fork the repository
- Create a new branch for your changes
- Commit and push your updates
- Open a Pull Request targeting the
stagingbranch - Clearly describe your changes and the reasoning behind them
This project is licensed under the Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0) license.
Bagas (fossyy)
- Website: fossy.my.id
- GitHub: @fossyy