Skip to main content

On This Page

Build your own tunnel in Rust: Expose local sites to the Web with blazing performance

2 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

Build your own tunnel in Rust: Expose local sites to the Web with blazing performance

Tauri applications leverage Cloudflare’s cloudflared to create outbound tunnels, bypassing inbound firewall restrictions. The tool uses QUIC for low-latency connections, falling back to HTTP/2 if needed.

Why This Matters

Traditional inbound firewall rules block external access to local services, requiring complex port forwarding. This approach eliminates that barrier by using outbound-only connections. However, improper process management can leave orphaned cloudflared instances, consuming system resources and exposing unintended services.

Key Insights

Working Example

{
  "tauri": {
    "bundle": {
      "externalBin": ["binaries/cloudflared"]
    },
    "allowlist": {
      "shell": {
        "all": false,
        "execute": true,
        "sidecar": true
      }
    }
  }
}
use std::sync::Mutex;
use tauri::command;
use tauri::api::process::{Command, CommandEvent};

pub struct TunnelState {
  pub child_process: Mutex<Option<tauri::api::process::CommandChild>>,
}

impl Default for TunnelState {
  fn default() -> Self {
    Self {
      child_process: Mutex::new(None),
    }
  }
}
#[command]
pub fn start_tunnel(
  app_handle: tauri::AppHandle,
  port: u16,
  state: tauri::State<TunnelState>,
) -> Result<(), String> {
  let mut state_guard = state.child_process.lock().map_err(|_| "Failed to lock state")?;
  if state_guard.is_some() {
    return Err("Tunnel is already running".into());
  }

  let (mut rx, child) = Command::new_sidecar("cloudflared")
    .map_err(|e| format!("Failed to create sidecar command: {}", e))?
    .args(&["tunnel", "--url", &format!("http://localhost:{}", port)])
    .spawn()
    .map_err(|e| format!("Failed to spawn sidecar: {}", e))?;

  *state_guard = Some(child);

  tauri::async_runtime::spawn(async move {
    let url_regex = regex::Regex::new(r"https://[a-zA-Z0-9-]+\.trycloudflare\.com").unwrap();
    while let Some(event) = rx.recv().await {
      match event {
        CommandEvent::Stderr(line) | CommandEvent::Stdout(line) => {
          println!("[cloudflared]: {}", line);
          if let Some(mat) = url_regex.find(&line) {
            let public_url = mat.as_str().to_string();
            app_handle.emit_all("tunnel-url", public_url).unwrap();
          }
        }
        CommandEvent::Terminated(_) => break,
        _ => {}
      }
    }
  });
  Ok(())
}

Practical Applications

  • Use Case: Exposing local development servers to the internet for collaboration
  • Pitfall: Forgetting to terminate cloudflared processes causes memory leaks and potential security exposure

References:


Continue reading

Next article

From determinants to hill climbing algorithms—how I turned academic math into an interactive learning platform

Related Content