๐ก๏ธ Tutorial: Secure SSH Access over Cloudflare Tunnel (Docker Optional)
# ๐ก๏ธ 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](https://dash.cloudflare.com)
* 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 under `systemd` 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` or `systemd` 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