---
title: "Install Cloudflared on OPNsense"
description: "How to install and configure Cloudflare Tunnel (cloudflared) on OPNsense firewall for secure remote access."
canonical_url: "https://hannoeru.me/posts/install-cloudflared-opnsense"
---

> Index of every page on this site: [llms.txt](https://hannoeru.me/llms.txt)

## Overview

Cloudflare Tunnel (formerly Argo Tunnel) allows you to securely connect your internal services to the internet without opening inbound ports on your firewall. This guide shows how to install and configure cloudflared on OPNsense, which is based on FreeBSD.

## Why Use Cloudflare Tunnel

- **Security**: No inbound ports need to be opened
- **DDoS Protection**: Built-in protection from Cloudflare
- **SSL/TLS**: Automatic SSL certificates
- **Access Control**: Integration with Cloudflare Access
- **Performance**: Global Cloudflare network acceleration

## Prerequisites

- OPNsense firewall with shell access
- Cloudflare account with a domain
- Basic knowledge of OPNsense administration

## Installation

> **Note**: Cloudflare's official cloudflared releases don't support FreeBSD. We'll use a community-maintained fork at [https://github.com/kjake/cloudflared](https://github.com/kjake/cloudflared) that provides FreeBSD binaries compatible with OPNsense.

SSH to your OPNsense router and download the FreeBSD binary:

```bash
# Create directory for cloudflared
mkdir -p /usr/local/bin

# Download the latest FreeBSD binary (version 2025.8.0)
fetch -o /usr/local/bin/cloudflared https://github.com/kjake/cloudflared/releases/download/2025.8.0/cloudflared-freebsd14-amd64

# Make it executable
chmod +x /usr/local/bin/cloudflared

# Verify installation
cloudflared --version
```

## Choose Your Setup Method

**Method 1 (Recommended)**: Token-based setup - Simpler, uses Cloudflare Dashboard<br />

**Method 2**: Configuration file setup - More control, requires CLI tunnel creation

## Method 1: Token-based Setup (Recommended)

This method is simpler and more secure as it uses tokens generated from the Cloudflare Dashboard.

### Getting Your Tunnel Token

1. Go to [Cloudflare Zero Trust Dashboard](https://one.dash.cloudflare.com/)
2. Navigate to **Access** > **Tunnels**
3. Create a new tunnel or select an existing one
4. Click **Configure** and copy the tunnel token from the installation command

### Service Configuration

#### 1. Create RC Script

Create `/usr/local/etc/rc.d/cloudflared`:

```bash
#!/bin/sh

# PROVIDE: cloudflared
# REQUIRE: NETWORKING SERVERS
# KEYWORD: shutdown

. /etc/rc.subr

name="cloudflared"
rcvar="cloudflared_enable"
logfile="/var/log/cloudflared.log"
pidfile="/var/run/cloudflared.pid"
procname="/usr/local/bin/cloudflared"

load_rc_config $name

: ${cloudflared_enable:="NO"}
: ${cloudflared_mode:="tunnel"}

# Load token from secure file
if [ -f /usr/local/etc/cloudflared/token ]; then
    token=$(cat /usr/local/etc/cloudflared/token)
    command_args="${cloudflared_mode} --token ${token}"
else
    command_args="${cloudflared_mode}"
fi

command="/usr/sbin/daemon"
command_args="-o ${logfile} -p ${pidfile} -f ${procname} ${command_args}"

run_rc_command "$1"
```

#### 2. Set Permissions

Make the script executable:

```bash
chmod 755 /usr/local/etc/rc.d/cloudflared
```

#### 3. Store Token Securely

Create a secure location for your Cloudflare tunnel token:

```bash
# Create directory
mkdir -p /usr/local/etc/cloudflared

# Store your tunnel token (replace with actual token)
echo "your-tunnel-token-here" > /usr/local/etc/cloudflared/token

# Secure the token file
chmod 600 /usr/local/etc/cloudflared/token
```

#### 4. Configure RC

> **Important:** Do **not** add these lines to `/etc/rc.conf`. OPNsense regenerates `/etc/rc.conf` from `config.xml` on boot and on every config apply, so hand-added lines are silently dropped. Use the per-service file `/etc/rc.conf.d/cloudflared` instead:

```bash
mkdir -p /etc/rc.conf.d
cat > /etc/rc.conf.d/cloudflared <<'EOF'
cloudflared_enable="YES"
cloudflared_mode="--no-autoupdate tunnel run --post-quantum"
EOF
```

> Note: this file may be reset by a firmware install/upgrade — re-create it afterwards if the service fails to start on boot.

#### 5. Start the Service

```bash
# Start the service
service cloudflared start

# Check status
service cloudflared status

# View logs
tail -f /var/log/cloudflared.log
```

---

## Method 2: Configuration File Setup

This method uses CLI commands to create tunnels and configuration files. More complex but offers more granular control.

### Tunnel Creation

#### 1. Authenticate with Cloudflare

```bash
# Login to Cloudflare (this will open a browser for authentication)
cloudflared tunnel login
```

This creates a certificate file at `/root/.cloudflared/cert.pem`.

#### 2. Create a Tunnel

```bash
# Create a new tunnel (replace 'opnsense-tunnel' with your preferred name)
cloudflared tunnel create opnsense-tunnel

# List your tunnels to verify
cloudflared tunnel list
```

This creates a tunnel credentials file at `/root/.cloudflared/<tunnel-id>.json`.

### Configuration

#### 1. Create Configuration File

Create the cloudflared configuration file:

```bash
mkdir -p /usr/local/etc/cloudflared
```

Create `/usr/local/etc/cloudflared/config.yml`:

```yaml
tunnel: opnsense-tunnel
credentials-file: /root/.cloudflared/<tunnel-id>.json

ingress:
  # Route web traffic to OPNsense web interface
  - hostname: opnsense.yourdomain.com
    service: https://127.0.0.1:443
    originServerName: opnsense.yourdomain.com
  
  # Route SSH traffic
  - hostname: ssh.yourdomain.com
    service: ssh://127.0.0.1:22
  
  # Default rule (required)
  - service: http_status:404
```

Replace `<tunnel-id>` with your actual tunnel ID and `yourdomain.com` with your domain.

#### 2. Configure DNS

Add DNS records to point to your tunnel:

```bash
# Add DNS records
cloudflared tunnel route dns opnsense-tunnel opnsense.yourdomain.com
cloudflared tunnel route dns opnsense-tunnel ssh.yourdomain.com
```

### Service Configuration

#### 1. Create RC Script

Create `/usr/local/etc/rc.d/cloudflared`:

```bash
#!/bin/sh

# PROVIDE: cloudflared
# REQUIRE: NETWORKING SERVERS
# KEYWORD: shutdown

. /etc/rc.subr

name="cloudflared"
rcvar="cloudflared_enable"
logfile="/var/log/cloudflared.log"
pidfile="/var/run/cloudflared.pid"
procname="/usr/local/bin/cloudflared"

load_rc_config $name

: ${cloudflared_enable:="NO"}
: ${cloudflared_mode:="--config /usr/local/etc/cloudflared/config.yml tunnel run"}

command="/usr/sbin/daemon"
command_args="-o ${logfile} -p ${pidfile} -f ${procname} ${cloudflared_mode}"

run_rc_command "$1"
```

#### 2. Set Permissions

Make the script executable:

```bash
chmod 755 /usr/local/etc/rc.d/cloudflared
```

#### 3. Configure RC

> **Important:** Do **not** add this to `/etc/rc.conf` — OPNsense regenerates it from `config.xml` at boot and the line will be lost. Use the per-service file instead:

```bash
mkdir -p /etc/rc.conf.d
cat > /etc/rc.conf.d/cloudflared <<'EOF'
cloudflared_enable="YES"
EOF
```

#### 4. Start the Service

```bash
# Start the service
service cloudflared start

# Check status
service cloudflared status

# View logs
tail -f /var/log/cloudflared.log
```

---

## Testing

Both methods use the same testing approach since they both use the daemon and log to the same location:

```bash
# Check service status
service cloudflared status

# View logs (both methods log here)
tail -f /var/log/cloudflared.log

# Test web access (replace with your actual tunnel domain)
curl -I https://your-tunnel-domain.com

# For Method 1 - remotely-managed (token) tunnels can't be inspected
# from the CLI; check the status in the Cloudflare Zero Trust dashboard:
# https://one.dash.cloudflare.com/ -> Networks -> Tunnels

# For Method 2 - Test tunnel status (requires cert.pem from `tunnel login`)
cloudflared tunnel info opnsense-tunnel
```

## Troubleshooting

### Common Issues

1. **Permission errors**: Ensure cloudflared binary has execute permissions
2. **DNS resolution**: Verify DNS records are properly configured
3. **Certificate issues**: Check that `/root/.cloudflared/cert.pem` exists
4. **Service won't start**: Check configuration file syntax

### Debugging Commands

For token-based setup:

```bash
# Run cloudflared in foreground for debugging
cloudflared --no-autoupdate tunnel --token $(cat /usr/local/etc/cloudflared/token) run --post-quantum

# Check service logs
tail -f /var/log/cloudflared.log

# For token-based (remotely managed) tunnels, check status in the
# Cloudflare Zero Trust dashboard instead — the CLI cannot inspect them
```

For configuration file setup:

```bash
# Run cloudflared in foreground for debugging
cloudflared --config /usr/local/etc/cloudflared/config.yml tunnel run

# Check tunnel connectivity
cloudflared tunnel info opnsense-tunnel

# Validate configuration
cloudflared tunnel ingress validate
```

### Common Token Issues

1. **Invalid token format**: Ensure token is copied correctly without extra characters
2. **File permissions**: Verify `/usr/local/etc/cloudflared/token` has 600 permissions
3. **Service user**: Ensure the daemon can read the token file
4. **Token expiration**: Tokens don't expire but may be revoked - check Cloudflare dashboard

## Security Considerations

- **Token Security**: Store your tunnel token securely with proper file permissions (600)
- **Never share tokens**: Keep your tokens private and rotate them regularly
- **Monitor logs**: Regularly check `/var/log/cloudflared.log` for suspicious activity
- **Update regularly**: Keep cloudflared binary updated to the latest version
- **Use Cloudflare Access**: Implement additional authentication layers
- **Firewall rules**: Apply least-privilege access rules
- **Backup tokens**: Store backup tokens securely in case of emergencies

## Updating cloudflared

To update cloudflared to the latest version from the fork repository:

```bash
# Stop the service
service cloudflared stop

# Check for latest version at https://github.com/kjake/cloudflared/releases
# Download latest version (replace version number as needed)
fetch -o /usr/local/bin/cloudflared https://github.com/kjake/cloudflared/releases/download/2025.8.0/cloudflared-freebsd14-amd64

# Make executable
chmod +x /usr/local/bin/cloudflared

# Start the service
service cloudflared start
```

## References

- [Cloudflare Tunnel Documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/)
- [FreeBSD cloudflared Fork](https://github.com/kjake/cloudflared) - Community-maintained FreeBSD builds
- [OPNsense Documentation](https://docs.opnsense.org/)
- [FreeBSD Handbook](https://docs.freebsd.org/en/books/handbook/)

## Sitemap

See the full [sitemap](https://hannoeru.me/sitemap.md) for all pages.
