Creating an Argo Tunnel Programmatically

With the new addition of the Argo Tunnel endpoints to the public API and the new and improved tunnel architecture, it seemss that everything is in place to create an argo tunnel programmatically.

The new changes released the past months have dramatically simplified tunnel deployment. Our boxes running cloudflared no longer need the uber-privileged api keys or even an origin cert.

We can now automate tunnel provisioning using just the api!

Here are the necessary steps.

  1. Create an API Token that has the “Argo Tunnel” “Edit” ability. If using the API, the permission is
{
  "id": "c07321b023e944ff818fec44d8203567",
  "name": "Argo Tunnel Write"
}
  1. Create a tunnel using the public Argo Tunnel API
curl -X POST "https://api.cloudflare.com/client/v4/accounts/abcdefba6ae611eb94390242ac130002/tunnels" \
     -H "Authorization: Bearer TOKEN" \
     -H "Content-Type: application/json" \
     --data '{"name":"TUNNEL_NAME","tunnel_secret":"long random string here"}'

This will return a json body with an id field, this your tunnel id.

  1. Create the CNAME using the public DNS record api, using the tunnel id from step 1
curl -X POST "https://api.cloudflare.com/client/v4/zones/e42412ba6ae611eb94390242ac130002/dns_records" \
     -H "Authorization: Bearer TOKEN" \
     -H "Content-Type: application/json" \
     --data '{"type":"CNAME","name":"DESIRED_HOSTNAME.example.com","content":"TUNNEL_ID.cfargotunnel.com","proxied":true}'
  1. Create your credentials json file. This file must exist in one of ~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /etc/cloudflared /usr/local/etc/cloudflared
{
  "AccountTag": "YOUR ACCOUNT ID",
  "TunnelSecret": "long random string here",
  "TunnelID": "TUNNEL_ID",
  "TunnelName": "TUNNEL_NAME"
}
  1. Create your config.yml file. It must be in the same directory as the json credentials file.
tunnel: TUNNEL_NAME
url: http://localhost:8000
  1. Start your tunnel using cloudflared
cloudflared tunnel --config config.yml run TUNNEL_ID

NOTE: If you use TUNNEL_NAME instead of TUNNEL_ID during the run command, it will not work, it fails with the misleading error Cannot determine default origin certificate path. No file cert.pem in .... Use the tunnel id.

You can create multiple tunnels on one machine, just create multiple tunnels, json credentials files, and config files.

To securely manage and distribute tunnels steps 1-2 can be done on a secure box strictly manages the cloudflare api keys. The final yml and json file can then be distributed to the servers where it is needed.

The end goal is to create and manage tunnels with terraform, but we’ll need to wait for a terraform resource for the create tunnel endpoint.

Many thanks to the Argo Tunnel team for listening to our feedback and making this possible. Also thanks to the CF Support Team for passing along our feedback and getting it actioned.

5 Likes

The cloudflare_argo_tunnel resource has landed in the Cloudflare terraform provider. Now it is possible to create argo tunnels via pure terraform.

https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/argo_tunnel

resource "cloudflare_argo_tunnel" "default" {
  account_id = var.cloudflare_account_id
  name       = "mytunnel"
  secret     = "32 secure random bytes encoded with base64="
}

resource "cloudflare_record" "tunnel_records" {
  zone_id  = var.cloudflare_zone_id
  name     = "subdomain-for-mytunnel.example.com"
  value    = "${cloudflare_argo_tunnel.default.id}.cfargotunnel.com"
  proxied  = true
  type     = "CNAME"
}


2 Likes

Thanks for sharing :+1:

One thing I had to do here was specifically proxy the created CNAME as using the command you listed had the CNAME with orange cloud proxy disabled

so change to

curl -X POST "https://api.cloudflare.com/client/v4/zones/023e105f4ecef8ad9ca31a8372d0c353/dns_records" \
     -H "Authorization: Bearer TOKEN" \
     -H "Content-Type: application/json" \
     --data '{"type":"CNAME","name":"DESIRED_HOSTNAME.example.com","content":"TUNNEL_ID.cfargotunnel.com","proxied":true}

also API token would need DNS zone permissions too to add CNAME.

1 Like

Thanks, good catch on that oversight. I updated my post to include the proxied param.

2 Likes