-
@ Girino Vey!
2025-06-14 19:37:17🛡️ Tutorial: Secure SSH Access over Cloudflare Tunnel (Docker Optional)
🎯 Objective
Set up a Cloudflare Tunnel to securely expose SSH access to your system without revealing your home IP or requiring port forwarding. This enables secure remote access even behind NAT, CGNAT, or dynamic IP environments.
This guide:
- Uses Cloudflare Tunnels to proxy traffic
- Does not expose your home IP address
- Uses Docker + Docker Compose for orchestration (optional)
- Can be adapted to run under systemd directly if preferred
🔧 Prerequisites
- A domain managed via Cloudflare DNS
- SSH server running on your machine (default port
22
) - Temporary access to the
cloudflared
CLI (for tunnel creation) -
Either:
-
Docker and Docker Compose (used in this example), or
- A native
systemd
service (alternative not covered here)
🪜 Step-by-Step Instructions
1. Install and Authenticate
cloudflared
Install
cloudflared
(temporary):bash curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \ -o cloudflared && chmod +x cloudflared && sudo mv cloudflared /usr/local/bin/
Login with your Cloudflare account:
bash cloudflared tunnel login
This will open a browser and link the machine to your Cloudflare zone.
2. Create the Tunnel
Create a named tunnel:
bash cloudflared tunnel create ssh-tunnel
This creates a credential file, e.g.:
~/.cloudflared/5f84da12-e91b-4d2e-b4f0-7ca842f622f1.json
3. Define the Tunnel Routing Configuration
Create the tunnel config:
bash nano ~/.cloudflared/config.yml
Example:
```yaml tunnel: ssh-tunnel credentials-file: /etc/cloudflared/5f84da12-e91b-4d2e-b4f0-7ca842f622f1.json
ingress: - hostname: secure-ssh.example.com service: ssh://localhost:22 - service: http_status:404 ```
Then bind the hostname to the tunnel:
bash cloudflared tunnel route dns ssh-tunnel secure-ssh.example.com
Replace
secure-ssh.example.com
with your own subdomain under Cloudflare management.
4. Prepare File Permissions for Docker Use (Optional)
If using Docker,
cloudflared
runs as a non-root user (UID 65532
), so grant it access to your config and credentials:bash sudo chown 65532:65532 ~/.cloudflared sudo chown 65532:65532 ~/.cloudflared/*
5. Define
docker-compose.yml
(Optional)yaml version: "3.8" services: cloudflared: image: cloudflare/cloudflared:latest container_name: cloudflared-ssh-tunnel restart: unless-stopped volumes: - ${HOME}/.cloudflared:/etc/cloudflared:ro - ${HOME}/.cloudflared:/home/nonroot/.cloudflared:ro command: tunnel run ssh-tunnel network_mode: host
📝 Docker is used here for convenience and automation. You may alternatively run
cloudflared tunnel run ssh-tunnel
directly undersystemd
or a background process.
6. Start the Tunnel
Start the container:
bash cd ~/docker/sshtunnel docker compose up -d docker logs -f cloudflared-ssh-tunnel
You should see
Registered tunnel connection
and other success logs.
7. Connect to the Tunnel from Remote Systems
Option A: Ad-hoc connection with
cloudflared access tcp
bash cloudflared access tcp --hostname secure-ssh.example.com --url localhost:2222
In another terminal:
bash ssh -p 2222 youruser@localhost
Option B: Permanent SSH Configuration
Edit
~/.ssh/config
:ssh Host secure-home HostName secure-ssh.example.com User youruser IdentityFile ~/.ssh/id_rsa ProxyCommand cloudflared access ssh --hostname %h
Then connect with:
bash ssh secure-home
✅ Result
- Secure SSH access via a public domain (e.g.,
secure-ssh.example.com
) - No ports open to the public Internet
- IP address of your machine remains hidden from Cloudflare clients
- Easily extendable to expose other services in future
🔁 Optional Enhancements
- Run as a
systemd
service instead of Docker for lower overhead - Use
autossh
orsystemd
to maintain persistent reverse tunnels - Expand to forward additional ports (e.g., Bitcoin RPC, application APIs)
- Apply strict firewall rules to limit SSH access to
localhost
only