🌐 Web Application Tunnel

Cloudflare Zero Trust Implementation - Complete Technical Documentation

🎯 Purpose & Use Cases

Primary Purpose

Securely expose internal web applications to the internet without opening firewall ports, providing secure access through Cloudflare's global edge network.

Top 3 Use Cases

  • Public Web Application Hosting
    Securely expose internal web applications to the internet without opening firewall ports
  • Development Environment Access
    Provide external access to development servers and staging environments
  • Internal Tool Distribution
    Share internal dashboards, monitoring tools, and administrative interfaces with authorized users

Key Benefits

  • Zero-trust security model
  • No inbound firewall rules required
  • Global edge network performance
  • Built-in DDoS protection
  • SSL/TLS termination at edge

πŸ“‹ Prerequisites

Required Accounts & Services

  • Cloudflare Account with domain management
  • Cloudflare Zero Trust subscription (free tier available)
  • AWS Account with EC2 instance running Ubuntu
  • Domain registered and managed through Cloudflare
  • WARP Client installed on devices requiring Infrastructure Access

Server Requirements

  • Ubuntu 20.04+ (other Linux distributions supported)
  • cloudflared binary (latest version)
  • OpenSSH Server
  • Web application (nginx, apache, or custom app)
  • sudo access on target server

Network Requirements

  • Server outbound connectivity on port 443 (for tunnel establishment)
  • Web application running on designated port (default: 80)
  • SSH service running on port 22
  • No inbound firewall rules required (all access through tunnels)

πŸ—οΈ Architecture Overview

System Architecture Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLIENT DEVICES β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Web Browser β”‚ β”‚ Web Browser β”‚ β”‚ WARP + SSH Client β”‚ β”‚ β”‚ β”‚ (Any Device) β”‚ β”‚ (Any Device) β”‚ β”‚ (Admin Device) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ HTTPS β”‚ HTTPS β”‚ WARP Tunnel β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLOUDFLARE EDGE NETWORK β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Web App β”‚ β”‚ SSH Browser β”‚ β”‚ SSH Infrastructure β”‚ β”‚ β”‚ β”‚ DNS Route β”‚ β”‚ DNS Route β”‚ β”‚ IP Route β”‚ β”‚ β”‚ β”‚webapp.ztn.*****.comβ”‚ β”‚ssh.ztn.*****.com β”‚ β”‚172.31.***.***/31 β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚Self-hosted App β”‚ β”‚Self-hosted App β”‚ β”‚Infrastructure App β”‚ β”‚ β”‚ β”‚Access Policy β”‚ β”‚Access Policy β”‚ β”‚Access Policy β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ Tunnel 1 β”‚ Tunnel 2 β”‚ Tunnel 3 β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AWS UBUNTU SERVER β”‚ β”‚ 172.31.***.*** β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Tunnel 1 β”‚ β”‚ Tunnel 2 β”‚ β”‚ Tunnel 3 β”‚ β”‚ β”‚ β”‚ Port 8080 β”‚ β”‚ Port 8081 β”‚ β”‚ Port 8082 β”‚ β”‚ β”‚ β”‚ Web App β”‚ β”‚ SSH Browser β”‚ β”‚ SSH Infrastructure β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β–Ό β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Web Server β”‚ β”‚ SSH Daemon β”‚ β”‚ SSH Daemon β”‚ β”‚ β”‚ β”‚ Port 80 β”‚ β”‚ Port 22 β”‚ β”‚ Port 22 β”‚ β”‚ β”‚ β”‚ (nginx/app) β”‚ β”‚ (Browser CA) β”‚ β”‚ (Infrastructure CA) β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Service Interaction Matrix

Component Web App Tunnel SSH Browser Tunnel SSH Infrastructure
Cloudflared Process βœ… Separate βœ… Separate βœ… Separate
DNS Route webapp.ztn.*****.com ssh.ztn.*****.com None
IP Route None None 172.31.***.***/31
Access Policy Self-hosted Self-hosted Infrastructure
Target Service HTTP:80 SSH:22 SSH:22
Authentication Email-based Email + SSH Cert WARP + SSH Cert
Client Requirement Browser Browser WARP + SSH Client

🚦 Detailed Traffic Flow

Web Application Access Flow

Step 1: User Request

  • User opens browser
  • Navigates to https://webapp.ztn.*****.com
  • DNS resolution via Cloudflare

Step 2: Cloudflare Edge Processing

  • DNS resolves to Cloudflare edge IP
  • Request hits Cloudflare proxy
  • Edge identifies associated tunnel (web-app-tunnel)
  • Checks for self-hosted Access application

Step 3: Authentication Flow

  • Self-hosted Access policy evaluation
  • If not authenticated: redirect to login page
  • User enters email: ubuntu@*****.com
  • Email verification (OTP or SSO)
  • Access token issued

Step 4: Request Forwarding

  • Authenticated request forwarded to tunnel
  • Tunnel receives request on web-app-tunnel
  • Tunnel forwards to service: http://localhost:80
  • Web server (nginx/app) processes request

Step 5: Response Flow

  • Web server generates response
  • Response travels back through tunnel
  • Cloudflare edge adds security headers
  • Response cached (if applicable)
  • Browser receives final response
Timeline: ~500ms for authenticated users, ~3-5s for new authentication

βš™οΈ Configuration

Tunnel Configuration

Tunnel Config (~/.cloudflared/tunnels/web-app/config.yml):

tunnel: <web-tunnel-id> credentials-file: /home/ubuntu/.cloudflared/<web-tunnel-id>.json logfile: /home/ubuntu/.cloudflared/logs/web-app.log loglevel: info ingress: - hostname: webapp.ztn.*****.com service: http://localhost:80 - service: http_status:404

Systemd Service

Service File (/etc/systemd/system/cloudflared-web.service):

[Unit] Description=Cloudflare Tunnel - Web Application After=network.target Wants=network.target [Service] Type=simple User=ubuntu Group=ubuntu ExecStart=/usr/local/bin/cloudflared tunnel --config /home/ubuntu/.cloudflared/tunnels/web-app/config.yml run Restart=always RestartSec=5 TimeoutStartSec=0 KillMode=mixed StandardOutput=journal StandardError=journal SyslogIdentifier=cloudflared-web [Install] WantedBy=multi-user.target

Web Server Configuration

Nginx Configuration (/etc/nginx/sites-available/default):

server { listen 80 default_server; listen [::]:80 default_server; root /var/www/html; index index.html index.htm index.nginx-debian.html; server_name _; location / { try_files $uri $uri/ =404; } # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; }

πŸ“ File Structure

Cloudflared Tunnel Files

/home/ubuntu/.cloudflared/ β”œβ”€β”€ logs/ β”‚ β”œβ”€β”€ web-app.log # Web application tunnel logs β”‚ β”œβ”€β”€ ssh-browser.log # SSH browser tunnel logs β”‚ └── ssh-infra.log # SSH infrastructure tunnel logs β”œβ”€β”€ tunnels/ β”‚ β”œβ”€β”€ web-app/ β”‚ β”‚ └── config.yml # Web app tunnel configuration β”‚ β”œβ”€β”€ ssh-browser/ β”‚ β”‚ └── config.yml # SSH browser tunnel configuration β”‚ └── ssh-infra/ β”‚ └── config.yml # SSH infrastructure tunnel configuration β”œβ”€β”€ <web-tunnel-id>.json # Web tunnel credentials β”œβ”€β”€ <ssh-browser-tunnel-id>.json # SSH browser tunnel credentials └── <ssh-infra-tunnel-id>.json # SSH infrastructure tunnel credentials

Web Project Files

/var/www/html/ # Default nginx/apache document root β”œβ”€β”€ index.html # Main web application β”œβ”€β”€ assets/ # Static assets (CSS, JS, images) β”œβ”€β”€ api/ # API endpoints (if applicable) └── config/ # Application configuration # Alternative locations: /home/ubuntu/web-app/ # Custom application directory /opt/webapp/ # System-wide application directory

Systemd Service Files

/etc/systemd/system/ β”œβ”€β”€ cloudflared-web.service # Web tunnel service β”œβ”€β”€ cloudflared-ssh-browser.service # SSH browser tunnel service └── cloudflared-ssh-infra.service # SSH infrastructure tunnel service

πŸ“ˆ Scaling & Management

Adding a New Tunnel to Current Server

Step 1: Plan the New Service

# Example: Adding a database management tunnel NEW_SERVICE="db-admin" NEW_HOSTNAME="db.ztn.oskarcode.com" NEW_PORT="8080" # phpMyAdmin or similar

Step 2: Create and Configure Tunnel

# Create new tunnel cloudflared tunnel create ${NEW_SERVICE}-tunnel NEW_TUNNEL_ID=$(cloudflared tunnel list | grep "${NEW_SERVICE}-tunnel" | awk '{print $1}') # Create directory structure mkdir -p ~/.cloudflared/tunnels/${NEW_SERVICE} # Create configuration cat > ~/.cloudflared/tunnels/${NEW_SERVICE}/config.yml << EOF tunnel: $NEW_TUNNEL_ID credentials-file: /home/ubuntu/.cloudflared/${NEW_TUNNEL_ID}.json logfile: /home/ubuntu/.cloudflared/logs/${NEW_SERVICE}.log loglevel: info ingress: - hostname: ${NEW_HOSTNAME} service: http://localhost:${NEW_PORT} - service: http_status:404 EOF # Configure DNS route cloudflared tunnel route dns $NEW_TUNNEL_ID $NEW_HOSTNAME

Step 3: Create Systemd Service

# Create service file sudo tee /etc/systemd/system/cloudflared-${NEW_SERVICE}.service > /dev/null << EOF [Unit] Description=Cloudflare Tunnel - ${NEW_SERVICE} After=network.target [Service] Type=simple User=ubuntu Group=ubuntu ExecStart=/usr/local/bin/cloudflared tunnel --config /home/ubuntu/.cloudflared/tunnels/${NEW_SERVICE}/config.yml run Restart=always RestartSec=5 StandardOutput=journal StandardError=journal SyslogIdentifier=cloudflared-${NEW_SERVICE} [Install] WantedBy=multi-user.target EOF # Enable and start service sudo systemctl daemon-reload sudo systemctl enable cloudflared-${NEW_SERVICE} sudo systemctl start cloudflared-${NEW_SERVICE}

Horizontal Scaling Best Practices

Load Balancing Multiple Servers

# Use multiple tunnels with same hostname for load balancing # Example: Multiple web servers behind same domain # Server 1 cloudflared tunnel route dns web-tunnel-1 webapp.ztn.oskarcode.com # Server 2 cloudflared tunnel route dns web-tunnel-2 webapp.ztn.oskarcode.com # Cloudflare will automatically load balance between tunnels

Resource Management

# Monitor resource usage per tunnel systemctl status cloudflared-* htop -p $(pgrep cloudflared) # Implement resource limits # Add to systemd service files: [Service] MemoryLimit=256M CPUQuota=50%

πŸš€ Future Plans

Phase 1: Cloudflare Zero Trust Gateway Integration

Objective

Enhance security monitoring and control by implementing advanced Gateway features for comprehensive traffic inspection and policy enforcement.

Implementation Strategy
  • Gateway Proxy: Enable TCP proxy for SSH traffic and HTTPS proxy for web traffic
  • SSH Command Logging: Full command capture with optional session recording
  • Advanced Network Policies: Time-based, location-based, and device posture restrictions
  • Web Traffic Inspection: Malware detection, data loss prevention, content filtering
Timeline: 8 weeks implementation with enhanced security monitoring

Phase 2: Google Cloud Identity Integration

Objective

Replace email-based authentication with enterprise-grade Google Cloud Identity integration for improved security and user management.

Key Features
  • Centralized User Management: Google Admin Console integration
  • Enterprise MFA: Google Authenticator integration
  • Automated Provisioning: SCIM-based user synchronization
  • Group-based Access: Dynamic group membership
Timeline: 10 weeks with enterprise identity standards

Phase 3: Advanced Security and Monitoring

Objective

Implement comprehensive security monitoring, alerting, and incident response capabilities.

Features to Implement
  • Behavioral Analytics: User behavior analysis and anomaly detection
  • SIEM Integration: Splunk, ELK Stack, or Azure Sentinel
  • Incident Response: Automated and manual response procedures
  • System Monitoring: Resource utilization and performance metrics

Phase 4: Infrastructure as Code (IaC)

Objective

Automate the entire infrastructure deployment and management using Terraform and configuration management tools.

Implementation Components
  • Terraform Infrastructure: Version-controlled infrastructure deployment
  • Ansible Configuration: Automated configuration management
  • Disaster Recovery: Infrastructure recreation capabilities
  • Standardized Configurations: Consistent setups across all servers

πŸ”§ Common Issues & Solutions

Issue 1: Empty SSH Certificate Public Key

Problem:

curl -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID/ca" # Returns: "public_key": ""

Solution:

# Delete existing certificate curl -X DELETE "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID/ca" # Regenerate certificate curl -X POST "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID/ca" # Verify public key is populated curl -X GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID/ca"

Issue 2: Tunnel Name/ID Mismatch

Problem:

cloudflared tunnel info ssh-ec2 # Returns info for different tunnel (aws-tunnel)

Solution:

# List all tunnels to identify correct names and IDs cloudflared tunnel list # Use tunnel ID instead of name for reliability cloudflared tunnel info <tunnel-id> # Clean up orphaned tunnels cloudflared tunnel delete <unused-tunnel-id>

Issue 3: Service Start Failures

Problem:

sudo systemctl start cloudflared-web # Job failed. See "systemctl status cloudflared-web" for details.

Solution:

# Check service status and logs sudo systemctl status cloudflared-web sudo journalctl -u cloudflared-web -n 50 # Validate configuration cloudflared tunnel --config ~/.cloudflared/tunnels/web-app/config.yml validate # Check file permissions ls -la ~/.cloudflared/tunnels/web-app/config.yml ls -la ~/.cloudflared/*.json # Fix permissions if needed chmod 600 ~/.cloudflared/*.json chmod 644 ~/.cloudflared/tunnels/*/config.yml