This project provides a Docker-based solution to manage SSH tunnels using autossh and a YAML configuration file. This setup allows you to easily expose local services to a remote server through an SSH tunnel or map remote services to a local port, making it convenient to access services behind a firewall.
- Dockerized: Environment encapsulated with Docker, making it easy to deploy and manage.
- Non-root User: Run container as a non-root user to enhance security.
- YAML Configuration: Define multiple SSH tunnel mappings using the
config.yamlfile and support automatic service reload upon configuration changes. - Autossh: Automatically maintain SSH connection to ensure tunnels remain active.
- Dynamic UID/GID Support: Set container user's UID and GID dynamically using
PUIDandPGIDenvironment variables to match host user permissions. - Multi-architecture Support: Supports all Alpine base architectures, including
linux/amd64,linux/arm64/v8,linux/arm/v7,linux/arm/v6,linux/386,linux/ppc64le,linux/s390x, andlinux/riscv64. - Flexible Direction Configuration: Support exposing local services to a remote server (
local_to_remote) or mapping remote services to a local port (remote_to_local). - Automatic Reload: Detect changes in
config.yamland automatically reload the service configuration. - Web-Based Configuration: Manage tunnels and configuration updates via a web panel.
- CLI Tool (autossh-cli): Command-line interface for managing tunnels, viewing status, and controlling individual tunnels.
- HTTP API: RESTful API for programmatic tunnel control, enabling integration with other tools and automation.
- Individual Tunnel Control: Start, stop, and manage each tunnel independently without affecting others.
- Docker and Docker Compose are installed on the local machine.
- SSH keys are set up for accessing the remote host.
The packaged Docker images are available on Docker Hub:
Feel free to use it and provide feedback!
For most users, you only need to download the Docker Compose file.
Option A: Download files directly
Create a new directory and download the required files:
mkdir autossh-tunnel
cd autossh-tunnel
# Download docker-compose.yaml (includes both autossh tunnel and web panel services)
curl -O https://oaklight.github.io/autossh-tunnel-dockerized/compose.yaml
# Create config directory
mkdir config
# Option 1: Download sample config (if you want to configure manually)
curl -o config/config.yaml.sample https://oaklight.github.io/autossh-tunnel-dockerized/config/config.yaml.sample
cp config/config.yaml.sample config/config.yaml
# Option 2: Create empty config (if you want to use web panel for configuration)
touch config/config.yamlNote: The
compose.yamlfile includes both the autossh tunnel service and the web panel service. The web panel is optional - you can disable it by commenting out thewebservice section in the compose file if you prefer manual configuration.
Option B: Clone the repository (for developers)
If you want to modify the source code or build locally:
git clone https://github.com/Oaklight/autossh-tunnel-dockerized.git
cd autossh-tunnel-dockerizedEnsure your SSH keys are located in the ~/.ssh directory. This directory should contain:
- Private key files (e.g.,
id_ed25519,id_rsa) - SSH configuration file (
config) - Known hosts file (
known_hosts)
Important: This project heavily relies on the
~/.ssh/configfile for SSH connection configuration. The SSH config file allows you to define connection parameters such as hostnames, usernames, ports, and key files for each remote host. Without proper SSH config setup, the tunnels may fail to establish connections.
For detailed SSH config file setup instructions, please refer to: SSH Configuration Guide
You have two options for configuring your SSH tunnels:
Edit the config/config.yaml file to define your SSH tunnel mappings.
Basic Example:
tunnels:
# Expose local service to a remote server
- remote_host: "user@remote-host1"
remote_port: 22323
local_port: 18120
direction: local_to_remote
# Map remote service to a local port
- remote_host: "user@remote-host2"
remote_port: 8000
local_port: 8001
direction: remote_to_localAdvanced Configuration: Specifying Bind Addresses
If you want to bind the remote port or local service to a specific IP address, you can use the ip:port format:
tunnels:
# Specify remote bind address
- remote_host: "user@remote-host1"
remote_port: "192.168.45.130:22323" # Bind to specific IP on remote
local_port: 18120
direction: local_to_remote
# Specify local bind address
- remote_host: "user@remote-host1"
remote_port: 22323
local_port: "192.168.1.100:18120" # Bind to specific IP locally
direction: local_to_remote
# Specify both remote and local bind addresses
- remote_host: "user@remote-host1"
remote_port: "192.168.45.130:22323"
local_port: "192.168.1.100:18120"
direction: local_to_remoteIf you're using the web panel (included in compose.yaml):
- Start with an empty
config/config.yamlfile - Access the web interface at
http://localhost:5000after starting the services - Configure tunnels through the visual interface
Tips:
- The web panel automatically backs up your configuration to
config/backups/every time you save changes- You may need to manually delete old backup files to prevent disk space issues
- The
config/config.yamlfile must exist (even if empty) for the autossh tunnel service to work properly
Before running the containers, make sure to set the correct PUID and PGID values to match your host user's UID and GID.
Check your user's UID and GID:
idSetting methods:
Method 1: Set environment variables
export PUID=$(id -u)
export PGID=$(id -g)Method 2: Edit the compose.yaml file directly
environment:
- PUID=1000
- PGID=1000docker compose up -d# Build
docker compose -f compose.dev.yaml build
# Run
docker compose -f compose.dev.yaml up -dCheck container status:
docker compose psView logs:
docker compose logs -fAccess the Web panel (if enabled):
http://localhost:5000
The project supports two interpretation modes for tunnel direction configuration:
The default mode interprets direction from a service exposure perspective:
local_to_remote: Expose a local service to remote (uses SSH-R, remote listens)remote_to_local: Bring a remote service to local (uses SSH-L, local listens)
The SSH-standard mode aligns with SSH native terminology:
local_to_remote: SSH Local forwarding (uses SSH-L, local listens)remote_to_local: SSH Remote forwarding (uses SSH-R, remote listens)
Set the TUNNEL_DIRECTION_MODE environment variable in your compose.yaml:
environment:
- TUNNEL_DIRECTION_MODE=default # Default (current behavior)
# - TUNNEL_DIRECTION_MODE=ssh-standard # SSH-standard modeNote: The default mode maintains backward compatibility with existing configurations. Choose
ssh-standardif you prefer SSH's native terminology.
Once the containers are running:
- Local to Remote tunnels (default mode): Access local services via the specified port on the remote server (e.g.,
remote-host1:22323) - Remote to Local tunnels (default mode): Access remote services through the local port (e.g.,
localhost:8001)
The project provides both CLI and HTTP API interfaces for advanced tunnel management.
# List all configured tunnels
autossh-cli list
# View tunnel running status
autossh-cli status
# Start a specific tunnel
autossh-cli start-tunnel <hash>
# Stop a specific tunnel
autossh-cli stop-tunnel <hash>
# Start all tunnels
autossh-cli start
# Stop all tunnels
autossh-cli stop| Method | Endpoint | Description |
|---|---|---|
| GET | /list |
Get list of all configured tunnels |
| GET | /status |
Get running status of all tunnels |
| POST | /start |
Start all tunnels |
| POST | /stop |
Stop all tunnels |
| POST | /start/<hash> |
Start a specific tunnel |
| POST | /stop/<hash> |
Stop a specific tunnel |
For detailed API documentation, see: Tunnel Control API Documentation
When enabling the -R parameter, remote ports are by default bound to localhost. If you want to access the tunnel via other IP addresses on the remote server, you need to enable the GatewayPorts option in the remote server's sshd_config:
# Edit /etc/ssh/sshd_config
GatewayPorts clientspecified # Allow clients to specify binding address
GatewayPorts yes # Or bind to all network interfacesRestart the SSH service:
sudo systemctl restart sshdEnabling GatewayPorts may expose services to the public. Ensure to take appropriate security measures, such as configuring firewall or enabling access control.
Ensure the .ssh directory and its contents have the appropriate permissions:
chmod 700 .ssh
chmod 600 .ssh/*If you encounter permission issues when running Docker commands, make sure your user is in the docker group:
sudo usermod -aG docker $USERCheck Docker container logs for any errors:
docker compose logs -fFor more troubleshooting tips, see the full documentation.
This project is licensed under the MIT License. See the LICENSE file for details.
- autossh for maintaining SSH connections.
- Docker for containerization.
- Alpine Linux for the lightweight base image.
- Go for the web panel backend.
- Material for MkDocs for the documentation theme.
Contributions to the project are welcome via issues or pull requests. Happy tunneling!
