A Docker container that extends the popular Nginx Proxy Manager with built-in SSH tunneling capabilities. This solution allows you to securely expose your local services through a remote server using SSH reverse tunnels, eliminating the need for public IP addresses or complex firewall configurations.
βΉοΈ Note regarding limitations: There's a caveat regarding the use of this container. It is designed to work with a remote server that has SSH access. The SSH tunnel is established from the container to the remote server, allowing you to expose local services securely. If you need to use lower ports (like 80 or 443) on the remote server, you must ensure that the remote server allows SSH reverse tunneling and that the necessary ports are open. SSH tunneling does not propagate the original IP address of the client, so all requests will appear to come from the remote server's IP or localhost IP. This is a common limitation of SSH reverse tunnels.
- Full Nginx Proxy Manager functionality - Complete web-based proxy management (including SSL certificate management, access control, and more... see Nginx Proxy Manager)
- Automatic SSH tunneling - Establishes and maintains SSH reverse tunnels
- SSL/TLS support - Let's Encrypt integration through tunneled connections
- Self-healing tunnels - Automatic reconnection and health monitoring
- SSH key management - Automatic key generation and deployment
- Password or key-based authentication - Flexible SSH authentication methods
- Configurable monitoring - Customizable health check intervals and failure thresholds
- Docker Compose ready - Easy deployment with provided configuration
- Prerequisites
- Quick Start
- Configuration
- Environment Variables
- Volume Mapping
- SSH Key Management
- Monitoring and Logs
- Troubleshooting
- Security Considerations
- Contributing
- License
- Docker and Docker Compose installed
- A remote server with SSH access (VPS, cloud instance, etc.). Its possible to use the cheapest VPS available, it will no require much (if any) resources.
- SSH access to the remote server (password or key-based)
- Basic understanding of Docker networking and SSH
-
Clone or download this repository to your local machine.
-
Edit the docker-compose.yml file and configure the required environment variables and ports. You can use the comments in the file as a guide. Here is an example of the minimal configuration:
ports:
- '81:81' # Nginx Proxy Manager admin interface
environment:
SSH_SERVER: 'your-server.example.com' # Your remote server hostname/IP
- Start the container:
docker-compose up -d
- Wait for the container to initialize. It may take a few moments for the SSH tunnel to establish and for Nginx Proxy Manager to become available. You can check the logs with:
docker-compose logs -f
-
Access the admin interface at
http://localhost:81
-
Configure Nginx Proxy Manager: Folow the instructions well documented in the Nginx Proxy Manager documentation to set up your proxies, SSL certificates, and other configurations.
β οΈ Important: Change the default admin credentials immediately after first login! π
The container is configured entirely through environment variables in the docker-compose.yml
file (You can use, if you prefer, set a .env
on the root folder of the project to manage your environment variables). This allows you to customize the SSH tunnel settings, Nginx Proxy Manager ports, and other options without modifying the Dockerfile or entrypoint scripts.
The container uses the s6-overlay
(Used by the original Nginx Proxy Manager docker image) for process management and service supervision, ensuring that the SSH tunnel is established before Nginx Proxy Manager starts.
Variable | Default | Description |
---|---|---|
SSH_SERVER |
Required | Remote server hostname or IP address |
SSH_PORT |
22 |
SSH server port |
SSH_USER |
root |
SSH username for authentication |
SSH_PASSWORD |
null |
SSH password (optional if using keys) |
SSH_CHECK_INTERVAL |
60 |
Tunnel health check interval (seconds) |
SSH_MAX_FAILURES |
5 |
Max consecutive failures before error |
LOCAL_HTTP_PORT |
80 |
Local HTTP port to tunnel |
LOCAL_HTTPS_PORT |
443 |
Local HTTPS port to tunnel |
REMOTE_HTTP_PORT |
80 |
Remote HTTP port binding |
REMOTE_HTTPS_PORT |
443 |
Remote HTTPS port binding |
DISABLE_IPV6 |
false |
Disable IPv6 in Nginx if needed |
The following volumes can be mapped for data persistence:
volumes:
- ./data:/data # Nginx Proxy Manager data
- ./letsencrypt:/etc/letsencrypt # SSL certificates
- ./ssh-tunnel/keys:/ssh-tunnel/keys # SSH keys persistence
./data
- Contains all Nginx Proxy Manager configuration, databases, and logs./letsencrypt
- Stores Let's Encrypt SSL certificates./ssh-tunnel/keys
- SSH key storage for tunnel authentication
The container handles SSH key management automatically:
If no SSH keys exist, the container will:
- Generate a new RSA 4096-bit key pair
- Display the public key for manual installation
- Optionally copy the key automatically (if password provided)
You can ssh into the remote server and copy the public key shown in the logs directly into the ~/.ssh/authorized_keys
file or, follow these steps:
- View the generated public key in the container logs
- Copy the key to your remote server:
# On your remote server
echo "ssh-rsa AAAAB3NzaC1yc2EAA..." >> ~/.ssh/authorized_keys
- Set correct permissions:
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
To use existing SSH keys:
- Place your private key as
tunnel_rsa_key
in thessh-tunnel/keys/
directory - Ensure the corresponding public key is installed on the remote server
- Set appropriate file permissions (600 for private key)
View real-time logs to monitor tunnel status:
docker-compose logs -f
The container logs include:
- SSH tunnel connection status
- Health check results
- Automatic reconnection attempts
- Error conditions and warnings
Access detailed Nginx logs in the mapped data volume:
./data/logs/
- Contains all proxy and access logs- Individual host logs are separated by proxy configuration
# Check SSH connectivity from host
ssh -p 22 user@your-server.example.com
# Verify SSH key permissions
ls -la ssh-tunnel/keys/
# Check what's using port 81
netstat -tulpn | grep :81
# Stop conflicting services
sudo systemctl stop apache2 # Example
# Check Docker logs
docker-compose logs -f
# Verify Docker Compose syntax
docker-compose config
Ensure your remote server accepts reverse tunnels:
# In /etc/ssh/sshd_config
GatewayPorts yes
AllowTcpForwarding yes
# Restart SSH service
sudo systemctl restart sshd
Test connectivity between container and remote server:
# From inside the container
docker-compose exec nginx-proxy-manager nc -zv your-server.example.com 22
- Change default credentials immediately after deployment
- Use strong SSH passwords or preferably SSH keys
- Limit SSH access on your remote server (whitelist IPs if possible)
- Regular updates - Keep the base images updated
- Monitor logs for suspicious connection attempts
- Firewall configuration - Only expose necessary ports on remote server
βββββββββββββββββββ SSH Tunnel βββββββββββββββββββ
β Local Docker ββββββββββββββββββββΊβ Remote Server β
β β β β
β βββββββββββββββ β β βββββββββββββββ β
β β Nginx β β HTTP:80 ββββββββ β β Port 80 β β
β β Proxy β β HTTPS:443 βββββββ β β Port 443 β β
β β Manager β β Admin:81 β βββββββββββββββ β
β βββββββββββββββ β β β
β β β Internet β
βββββββββββββββββββ βββββββββββββββββββ
β β²
β Local Access β
βΌ β
βββββββββββββββββββ βββββββββββββββββββ
β Your Apps β β Public Users β
β (localhost) β β (via tunnel) β
βββββββββββββββββββ βββββββββββββββββββ
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is licensed under the GNU General Public License v3.0 (GPL-3.0). See the LICENSE file for details.
- Nginx Proxy Manager - The excellent web-based proxy manager
- jc21/nginx-proxy-manager - Base Docker image
- AutoSSH - Reliable SSH tunnel maintenance
- Nginx Proxy Manager
- Traefik - Alternative reverse proxy
- Cloudflare Tunnel - Alternative tunneling solution
Made with β€οΈ for the self-hosting community