Cloudflare Tunnel Complete Guide for Intranet Penetration

Project Background Websites deployed in an internal network need to be accessed from the external internet, but you don’t want to expose public IPs or purchase cloud servers. Cloudflare Tunnel provides a secure and free solution. Prerequisites Have a Cloudflare account Own a domain (hosted on Cloudflare) Debian server (internal network environment) 1. Cloudflare Dashboard […]


Project Background

Websites deployed in an internal network need to be accessed from the external internet, but you don’t want to expose public IPs or purchase cloud servers. Cloudflare Tunnel provides a secure and free solution.

Prerequisites

  • Have a Cloudflare account
  • Own a domain (hosted on Cloudflare)
  • Debian server (internal network environment)

1. Cloudflare Dashboard Configuration

1. Login to Cloudflare Dashboard

  1. Visit https://dash.cloudflare.com
  2. Select your domain
  3. Navigate to “Access” → “Tunnels”

2. Create New Tunnel

  1. Click “Create a Tunnel”
  2. Enter tunnel name (e.g., my-internal-server)
  3. Select “Cloudflared” as connection method
  4. Choose your operating system (Debian)
  5. Copy the generated installation command (similar to the one below)

3. Configure Host

After creating the tunnel, add Host configuration:

  • Subdomain: Enter subdomain name (e.g., data)
  • Service: Enter internal service address (e.g., http://localhost:80)
  • Path: (Optional) specific path

2. Debian Server Configuration

1. Install cloudflared

# Download the latest version of cloudflared
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb

# Install
sudo dpkg -i cloudflared-linux-amd64.deb

# Verify installation
cloudflared --version

2. Connect Tunnel

Run the connection command copied from the Cloudflare dashboard:

cloudflared tunnel run

3. Set as System Service (Recommended)

# Create systemd service file
sudo cloudflared service install

# Start service
sudo systemctl start cloudflared

# Enable on boot
sudo systemctl enable cloudflared

# Check status
sudo systemctl status cloudflared

3. LNMP Environment Configuration (Important)

⚠️ Key Notice

When configuring internal virtual hosts, do not add SSL certificate configuration to avoid conflicts with SSL certificates assigned by Cloudflare.

1. LNMP Virtual Host Configuration

Using LNMP Script to Add Virtual Host

# Add virtual host (recommended method)
lnmp vhost add

LNMP vhost add Interactive Steps:

  1. Enter domain: data.yourdomain.com
  2. Enter website directory: /home/wwwroot/data.yourdomain.com
  3. Choose whether to add rewrite rules: choose as needed
  4. Choose whether to add logs: choose as needed
  5. Choose whether to add SSL: choose n (do not add)This is the key step!
  6. Whether to add IPv6: choose as needed

Alternative Method (using script file):

# Enter lnmp installation directory (if you downloaded the archive version)
cd /root/lnmp2.1

# Add virtual host
./vhost.sh
# Or use standard command
lnmp vhost add

Manual Nginx Virtual Host Configuration

Configuration files created by LNMP are typically in

/usr/local/nginx/conf/vhost/domain.conf:

server {
listen 80;
server_name data.yourdomain.com;
root /home/wwwroot/data.yourdomain.com;
index index.php index.html;

# LNMP auto-generated configurations
include rewrite/wordpress.conf;
include enable-php-pathinfo.conf;

# Do not add SSL related configurations
# Do not have listen 443 ssl;
# Do not have ssl_certificate etc.

location / {
try_files $uri $uri/ /index.php?$args;
}

location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/tmp/php-cgi.sock; # LNMP defaults to socket
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
try_files $uri =404;
}
}

2. Port Management in LNMP Environment

LNMP Advantages:

  • All virtual hosts share port 80
  • Differentiate different domains through server_name
  • Support multiple domains running simultaneously

Example Configuration:

# First site: WordPress
server {
listen 80;
server_name data.yourdomain.com;
root /home/wwwroot/data.yourdomain.com;
index index.php index.html;
# ... other configurations
}

# Second site: Other application
server {
listen 80;
server_name api.yourdomain.com;
root /home/wwwroot/api.yourdomain.com;
index index.php index.html;
# ... other configurations
}

# Third site: Admin panel
server {
listen 80;
server_name admin.yourdomain.com;
root /home/wwwroot/admin.yourdomain.com;
index index.php index.html;
# ... other configurations
}

3. LNMP 2.1 Common Commands

# View all virtual hosts
ls /usr/local/nginx/conf/vhost/

# LNMP service management
lnmp restart # Restart all services
lnmp nginx restart # Restart only Nginx
lnmp mysql restart # Restart only MySQL
lnmp php-fpm restart # Restart only PHP-FPM

# Directly use systemctl
systemctl restart nginx
nginx -t # Check if configuration is correct
nginx -s reload # Reload configuration

4. Delete Virtual Host (LNMP 2.1)

# Delete virtual host
lnmp vhost del
# Select domain to delete: data.yourdomain.com
# Confirm deletion

5. Restart LNMP Services

# Restart entire LNMP
lnmp restart

# Or restart Nginx individually
systemctl restart nginx

4. Cloudflare DNS Configuration

  1. Return to Cloudflare Dashboard
  2. Navigate to “DNS” → “Records”
  3. Confirm your subdomain (e.g., data.yourdomain.com) has a CNAME record pointing to Cloudflare

5. Verify Configuration

  1. Wait for Tunnel to connect successfully (usually takes 1-2 minutes)
  2. Visit https://data.yourdomain.com
  3. You should see your internal website

6. Advanced Configuration

1. Multi-Service Configuration in LNMP Environment

In LNMP environment, since all sites use port 80, Cloudflare Tunnel configuration is simpler:

# Edit configuration file
sudo nano /etc/cloudflared/config.yml
tunnel:
credentials-file: /etc/cloudflared/.json

ingress:
- hostname: data.yourdomain.com # WordPress site
service: http://localhost:80 # All point to port 80
- hostname: api.yourdomain.com # API site
service: http://localhost:80 # All point to port 80
- hostname: admin.yourdomain.com # Admin panel
service: http://localhost:80 # All point to port 80
- service: http_status:404 # Other paths return 404

Principle Explanation:

  • Cloudflare Tunnel forwards requests to internal port 80
  • LNMP Nginx identifies different domains through server_name
  • Each virtual host configuration handles its own domain requests
  • All sites share the same port but are routed by Nginx

2. Expand LNMP Sites Example

# Add second site
lnmp vhost add
# Enter: api.yourdomain.com
# Choose not to add SSL

# Add third site
lnmp vhost add
# Enter: admin.yourdomain.com
# Choose not to add SSL

# View all site configurations
ls /usr/local/nginx/conf/vhost/
# Output:
# - data.yourdomain.com.conf
# - api.yourdomain.com.conf
# - admin.yourdomain.com.conf

3. Security Configuration

# Add firewall rules (only allow cloudflared outbound)
sudo ufw allow out 53
sudo ufw allow out 80
sudo ufw allow out 443
sudo ufw allow out 7844 # cloudflared tunnel protocol
sudo ufw enable

7. Troubleshooting

1. Tunnel Cannot Connect

# View logs
sudo journalctl -u cloudflared -f

# Re-authenticate
cloudflared tunnel login

2. Website Not Accessible

  • Check if internal service is running normally
  • Check firewall settings
  • Confirm Cloudflare DNS configuration is correct

3. SSL Certificate Conflicts

If certificate errors occur:

  1. Confirm internal web server has no SSL configuration
  2. Check if Cloudflare SSL mode is “Full”
  3. Restart internal web server

8. Monitoring and Maintenance

1. View Connection Status

# View active connections
cloudflared tunnel info

# Real-time logs
sudo journalctl -u cloudflared -f

2. Update cloudflared

# Update to latest version
sudo apt update && sudo apt upgrade cloudflared

# Restart service
sudo systemctl restart cloudflared

Summary

Through Cloudflare Tunnel, you can:

  • Securely expose internal services to the internet
  • Get free SSL certificates
  • Hide real IP addresses
  • Get Cloudflare protection and optimization

Remember the most critical point: Do not configure SSL certificates on internal servers, let Cloudflare handle all HTTPS traffic.