Avatar image home | reference architectures | about about me |
message send message

Doing C# with onprem hosting and Cloudlfare Tunnels - day 1

• Blog posts are my own thoughts and opinions

Hero image for Doing C# with onprem hosting and Cloudlfare Tunnels - day 1

How do I use Cloudflare to safely self host a .NET application on prem and tunnel services safely to my on prem server, that my cloudflare workers can talk to, in a way that the internet and bots cannot access at all, so that I can sleep safely at night?

Disclaimer

This is part of my day 1 series that I am doing to push the limits of what I can achieve with onprem cheap servers, .NET and Cloudflare. This is not for production, and is purely for experimental study purposes. Each blog post (how to) will be published before I actually implement anything and will be followed up with a link to a reference architecture of anything I implement. i.e. Instructions below were generated by Gemini (the title of this post is the prompt); your results will vary and be different. All normal AI warnings apply, follow steps below at your own risk, not for production, do not swollow, do not eat these instructions, do not operate any heavy machinery or fly a commercial aeroplane with passengers whilst following any of these instructions ... kapich?

Also; the real value of these posts won't be the content that the AI spits out, anyone can do that, it will be the amendments and corrections I add after I test these steps myself. (i.e. human in the loop)

Overview (good luck!)

The solution is to use Cloudflare Tunnel (formerly Argo Tunnel) with Cloudflare Access to create a secure, outbound-only connection from your on-premises server to Cloudflare's network. This ensures:

  1. No inbound ports need to be opened on your firewall

  2. No public IP exposure - your server is invisible to the internet

  3. Cloudflare Workers can communicate with your on-prem service via the tunnel

  4. Zero Trust security - only authenticated/authorized requests reach your server

Architecture Components

1. Cloudflare Tunnel (cloudflared)

Cloudflare Tunnel creates an outbound-only connection from your on-prem server to Cloudflare's edge network. The tunnel:

2. Cloudflare Access (Zero Trust)

Cloudflare Access provides authentication and authorization:

3. Cloudflare Workers

Your Workers can communicate with the on-prem service via:

Implementation Steps

Step 1: Install cloudflared on Your On-Prem Server

Windows:

# Download and install cloudflared
# Or use Chocolatey: choco install cloudflared

Linux:

# Download latest release
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64
chmod +x cloudflared-linux-amd64
sudo mv cloudflared-linux-amd64 /usr/local/bin/cloudflared

macOS:

brew install cloudflared

Step 2: Authenticate cloudflared

cloudflared tunnel login

This opens a browser to authenticate with your Cloudflare account and grants the tunnel permission to create routes.

Step 3: Create a Tunnel

# Create a named tunnel
cloudflared tunnel create bookify-onprem

# This creates a tunnel and generates a UUID
# Save the tunnel UUID - you'll need it for configuration

Step 4: Configure the Tunnel

Create a configuration file (e.g., config.yml):

tunnel: <your-tunnel-uuid>
credentials-file: /path/to/credentials.json

ingress:
  # Route traffic to your .NET application
  - hostname: api.yourdomain.com
    service: http://localhost:5000  # Your .NET app's local address
  
  # Catch-all rule (must be last)
  - service: http_status:404

Important: Your .NET application should bind to localhost or a private IP, NOT to 0.0.0.0 or a public interface.

Step 5: Configure Cloudflare Access (Zero Trust)

  1. Go to Cloudflare Zero Trust Dashboard

  2. Configure Application Settings:

  3. Configure Access Policies:

  4. Protect the Tunnel Route:

Step 6: Run the Tunnel

# Run the tunnel
cloudflared tunnel run bookify-onprem

# Or run with config file
cloudflared tunnel --config config.yml run

For Production (Windows Service):

# Install as Windows service
cloudflared service install
cloudflared service start

For Production (Linux Systemd):

# Create systemd service file: /etc/systemd/system/cloudflared.service
[Unit]
Description=Cloudflare Tunnel
After=network.target

[Service]
Type=simple
User=cloudflared
ExecStart=/usr/local/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

# Enable and start
sudo systemctl enable cloudflared
sudo systemctl start cloudflared

Step 7: Configure Your .NET Application

appsettings.json:

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5000"
      }
    }
  },
  "AllowedHosts": "api.yourdomain.com"
}

Program.cs (minimal example):

var builder = WebApplication.CreateBuilder(args);

// Only bind to localhost
builder.WebHost.UseUrls("http://localhost:5000");

// Add your services
builder.Services.AddControllers();
// ... other services

var app = builder.Build();

// Configure middleware
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Step 8: Configure Cloudflare Workers to Access On-Prem Service

In your Cloudflare Worker, use the service token to authenticate:

export default {
  async fetch(request, env) {
    // Use service token for authentication
    const response = await fetch('https://api.yourdomain.com/your-endpoint', {
      headers: {
        'CF-Access-Client-Id': env.CF_ACCESS_CLIENT_ID,
        'CF-Access-Client-Secret': env.CF_ACCESS_CLIENT_SECRET,
        'Content-Type': 'application/json'
      },
      method: 'POST',

Worker Environment Variables:

Security Best Practices

1. Network Isolation

2. Cloudflare Access Policies

3. Application Security

4. Tunnel Security

5. Monitoring and Logging

Additional Considerations

Performance

High Availability

Cost

Alternative: Cloudflare Private Network

For even more security, consider using Cloudflare's Private Network feature, which creates a private network between your Workers and on-prem resources without any public internet exposure.

Verification Checklist

Troubleshooting

Tunnel won't connect:

Workers can't reach on-prem service:

Access denied errors:

Summary

This architecture provides: ✅ Zero inbound exposure - no ports open to internet ✅ Secure communication - encrypted end-to-end ✅ Access control - Zero Trust authentication ✅ Worker integration - Service tokens for machine-to-machine ✅ Peace of mind - Your server is invisible to bots and attackers

Your on-prem .NET application is now safely accessible only through Cloudflare's secure tunnel, with no direct internet exposure.

Updates and Corrections

Updates and corrections might go here, or I might try to squeeze them inline perhaps strikethrough and replacement with a highlighter, if they're minor. If it's a total cluster-***** I might just delete this whole post and rewrite the whole thing later, we'll see what day 2 brings. 😂


Disclaimer: These views and opinions are those of the author and do not constitute professional advice. Neither Alan Hemmings nor Goblinfactory Ltd (if mentioned) shall be liable for any reliance on this content.