|
| 1 | +--- |
| 2 | +title: Create a tunnel (API) |
| 3 | +pcx_content_type: how-to |
| 4 | +sidebar: |
| 5 | + order: 2 |
| 6 | +--- |
| 7 | + |
| 8 | +import { Tabs, TabItem } from "~/components"; |
| 9 | + |
| 10 | +Follow this guide to set up a Cloudflare Tunnel using the API. |
| 11 | + |
| 12 | +## 1. Create an API token |
| 13 | + |
| 14 | +[Create an API token](/fundamentals/api/get-started/create-token/) with the following permissions: |
| 15 | + |
| 16 | +| Type | Item | Permission | |
| 17 | +| ------- | ---------------- | ---------- | |
| 18 | +| Account | Cloudflare Tunnel | Edit | |
| 19 | +| Zone | DNS | Edit | |
| 20 | + |
| 21 | +## 2. Create a tunnel |
| 22 | + |
| 23 | +Make a `POST` request to the [Cloudflare Tunnel](/api/resources/zero_trust/subresources/access/subresources/applications/methods/create/) endpoint: |
| 24 | + |
| 25 | +```sh |
| 26 | +curl 'https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel' \ |
| 27 | +--header 'Content-Type: application/json' \ |
| 28 | +--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ |
| 29 | +--data '{ |
| 30 | + "name": "api-tunnel", |
| 31 | + "config_src": "cloudflare" |
| 32 | +}' |
| 33 | +``` |
| 34 | + |
| 35 | +```sh output |
| 36 | +{ |
| 37 | + "success": true, |
| 38 | + "errors": [], |
| 39 | + "messages": [], |
| 40 | + "result": { |
| 41 | + "id": "c1744f8b-faa1-48a4-9e5c-02ac921467fa", |
| 42 | + "account_tag": "699d98642c564d2e855e9661899b7252", |
| 43 | + "created_at": "2025-02-18T22:41:43.534395Z", |
| 44 | + "deleted_at": null, |
| 45 | + "name": "example-tunnel", |
| 46 | + "connections": [], |
| 47 | + "conns_active_at": null, |
| 48 | + "conns_inactive_at": "2025-02-18T22:41:43.534395Z", |
| 49 | + "tun_type": "cfd_tunnel", |
| 50 | + "metadata": {}, |
| 51 | + "status": "inactive", |
| 52 | + "remote_config": true, |
| 53 | + "credentials_file": { |
| 54 | + "AccountTag": "699d98642c564d2e855e9661899b7252", |
| 55 | + "TunnelID": "c1744f8b-faa1-48a4-9e5c-02ac921467fa", |
| 56 | + "TunnelName": "api-tunnel", |
| 57 | + "TunnelSecret": "bTSquyUGwLQjYJn8cI8S1h6M6wUc2ajIeT7JotlxI7TqNqdKFhuQwX3O8irSnb==" |
| 58 | + }, |
| 59 | + "token": "eyJhIjoiNWFiNGU5Z..." |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +Copy the `id` and `token` values shown in the output. You will need these values to configure and run the tunnel. |
| 65 | + |
| 66 | +The next steps depend on whether you want to [connect an application](#3a-connect-an-application) or [connect a network](#3b-connect-a-network). |
| 67 | + |
| 68 | +## 3a. Connect an application |
| 69 | + |
| 70 | +Before you connect an application through your tunnel, you must: |
| 71 | + |
| 72 | +- [Add a website to Cloudflare](/fundamentals/setup/manage-domains/add-site/). |
| 73 | +- [Change your domain nameservers to Cloudflare](/dns/zone-setups/full-setup/setup/). |
| 74 | + |
| 75 | +Follow these steps to connect an application through your tunnel. If you are looking to connect a network, skip to the [Connect a network section](#3b-connect-a-network). |
| 76 | + |
| 77 | +1. Make a [`PUT` request](/api/resources/zero_trust/subresources/tunnels/subresources/cloudflared/subresources/configurations/methods/update/) to route your local service URL to a public hostname. For example, |
| 78 | + |
| 79 | + ```sh |
| 80 | + curl --request PUT \ |
| 81 | + 'https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel/c1744f8b-faa1-48a4-9e5c-02ac921467fa/configurations' \ |
| 82 | + --header 'Content-Type: application/json' \ |
| 83 | + --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ |
| 84 | + --data '{ |
| 85 | + "config": { |
| 86 | + "ingress": [ |
| 87 | + { |
| 88 | + "hostname": "app.example.com", |
| 89 | + "service": "http://localhost:8001", |
| 90 | + "originRequest": {} |
| 91 | + }, |
| 92 | + { |
| 93 | + "service": "http_status:404" |
| 94 | + } |
| 95 | + ] |
| 96 | + } |
| 97 | + }' |
| 98 | + ``` |
| 99 | + |
| 100 | + :::note |
| 101 | + If you add a multi-level subdomain (more than one level of subdomain), you must [order an Advanced Certificate for the hostname](/cloudflare-one/faq/troubleshooting/#i-see-this-site-cant-provide-a-secure-connection). |
| 102 | + ::: |
| 103 | + |
| 104 | + Your ingress rules must include a catch-all rule at the end. In this example, `cloudflared` will respond with a 404 status code when the request does not match any of the previous hostnames. |
| 105 | + |
| 106 | +2. [Create a DNS record](/api/resources/dns/subresources/records/methods/create/) for your application: |
| 107 | + ```sh |
| 108 | + curl https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records \ |
| 109 | + --header 'Content-Type: application/json' \ |
| 110 | + --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ |
| 111 | + --data '{ |
| 112 | + "type": "CNAME", |
| 113 | + "proxied": true, |
| 114 | + "name": "app.example.com", |
| 115 | + "content": "c1744f8b-faa1-48a4-9e5c-02ac921467fa.cfargotunnel.com" |
| 116 | + }' |
| 117 | + ``` |
| 118 | + |
| 119 | + This DNS record allows Cloudflare to proxy `app.example.com` traffic to your Cloudflare Tunnel (`<tunnel-id>.cfargotunnel.com`). |
| 120 | + |
| 121 | +This application will be publicly available on the Internet once you [run the tunnel](#4-install-and-run-the-tunnel). To allow or block specific users, [create an Access application](/cloudflare-one/applications/configure-apps/self-hosted-public-app/). |
| 122 | + |
| 123 | +## 3b. Connect a network |
| 124 | + |
| 125 | +To connect a private network through your tunnel, [add a tunnel route](/api/resources/zero_trust/subresources/networks/subresources/routes/methods/create/): |
| 126 | + |
| 127 | +```sh |
| 128 | +curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/teamnet/routes \ |
| 129 | +--header 'Content-Type: application/json' \ |
| 130 | +--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ |
| 131 | +--data '{ |
| 132 | + "network": "172.16.0.0/16", |
| 133 | + "tunnel_id": "c1744f8b-faa1-48a4-9e5c-02ac921467fa", |
| 134 | + "comment": "Example private network route" |
| 135 | +}' |
| 136 | +``` |
| 137 | + |
| 138 | +To configure Zero Trust policies and connect as a user, refer to [Connect private networks](/cloudflare-one/connections/connect-networks/private-net/cloudflared/). |
| 139 | + |
| 140 | +## 4. Install and run the tunnel |
| 141 | + |
| 142 | +Install `cloudflared` on your server and run the tunnel using the `token` value obtained in [2. Create a tunnel](#2-create-a-tunnel). You can also get the tunnel token using the [Cloudflare Tunnel token](/api/resources/zero_trust/subresources/tunnels/subresources/cloudflared/subresources/token/methods/get/) endpoint. |
| 143 | + |
| 144 | +<Tabs> <TabItem label="Windows"> |
| 145 | + |
| 146 | +1. [Download and install](/cloudflare-one/connections/connect-networks/downloads/#windows) `cloudflared`. |
| 147 | + |
| 148 | +2. Open Command Prompt as administrator. |
| 149 | + |
| 150 | +3. Run the following command: |
| 151 | + |
| 152 | + ```txt |
| 153 | + cloudflared.exe service install <tunnel-token> |
| 154 | + ``` |
| 155 | + |
| 156 | +</TabItem> <TabItem label="macOS"> |
| 157 | + |
| 158 | +1. [Download and install](/cloudflare-one/connections/connect-networks/downloads/#macos) `cloudflared`. |
| 159 | + |
| 160 | +2. Run the following command: |
| 161 | + |
| 162 | + ```sh |
| 163 | + sudo cloudflared service install <tunnel-token> |
| 164 | + ``` |
| 165 | + |
| 166 | +</TabItem> <TabItem label="Linux"> |
| 167 | + |
| 168 | +1. [Download and install](https://pkg.cloudflare.com/index.html) `cloudflared`. |
| 169 | + |
| 170 | +2. Run the following command: |
| 171 | + |
| 172 | + ```sh |
| 173 | + sudo cloudflared service install <tunnel-token> |
| 174 | + ``` |
| 175 | + |
| 176 | +</TabItem> <TabItem label="Docker"> |
| 177 | + |
| 178 | +1. Open a terminal window. |
| 179 | + |
| 180 | +2. Run the following command: |
| 181 | + |
| 182 | + ```sh |
| 183 | + docker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token <tunnel-token> |
| 184 | + ``` |
| 185 | +</TabItem> </Tabs> |
| 186 | + |
| 187 | +## 5. Verify tunnel status |
| 188 | + |
| 189 | +To check if the tunnel is serving traffic: |
| 190 | + |
| 191 | +```sh |
| 192 | +curl https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/cfd_tunnel/c1744f8b-faa1-48a4-9e5c-02ac921467fa \ |
| 193 | +--header 'Content-Type: application/json' \ |
| 194 | +--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" |
| 195 | +``` |
| 196 | + |
| 197 | +```sh output |
| 198 | +{ |
| 199 | + "success": true, |
| 200 | + "errors": [], |
| 201 | + "messages": [], |
| 202 | + "result": { |
| 203 | + "id": "c1744f8b-faa1-48a4-9e5c-02ac921467fa", |
| 204 | + "account_tag": "699d98642c564d2e855e9661899b7252", |
| 205 | + "created_at": "2025-02-18T22:41:43.534395Z", |
| 206 | + "deleted_at": null, |
| 207 | + "name": "example-tunnel", |
| 208 | + "connections": [ |
| 209 | + { |
| 210 | + "colo_name": "bos01", |
| 211 | + "uuid": "2xz99mfm-a59e-4924-gyh9-z9vafaw6k0i2", |
| 212 | + "id": "2xz99mfm-a59e-4924-gyh9-z9vafaw6k0i2", |
| 213 | + "is_pending_reconnect": false, |
| 214 | + "origin_ip": "10.1.0.137", |
| 215 | + "opened_at": "2025-02-19T19:11:12.101642Z", |
| 216 | + "client_id": "4xh4eb3f-cz0j-2aso-hu6i-36207018771a", |
| 217 | + "client_version": "2025.2.0" |
| 218 | + }, |
| 219 | + { |
| 220 | + "colo_name": "phl01", |
| 221 | + "uuid": "axe2socu-2fb5-3akx-b860-898zyes3cs9q", |
| 222 | + "id": "axe2socu-2fb5-3akx-b860-898zyes3cs9q", |
| 223 | + "is_pending_reconnect": false, |
| 224 | + "origin_ip": "10.1.0.137", |
| 225 | + "opened_at": "2025-02-19T19:11:12.006297Z", |
| 226 | + "client_id": "4xh4eb3f-cz0j-2aso-hu6i-36207018771a", |
| 227 | + "client_version": "2025.2.0" |
| 228 | + }, |
| 229 | + { |
| 230 | + "colo_name": "phl01", |
| 231 | + "uuid": "9b5y0wm9-ca7f-ibq6-8ff4-sm53xekfyym1", |
| 232 | + "id": "9b5y0wm9-ca7f-ibq6-8ff4-sm53xekfyym1", |
| 233 | + "is_pending_reconnect": false, |
| 234 | + "origin_ip": "10.1.0.137", |
| 235 | + "opened_at": "2025-02-19T19:11:12.004721Z", |
| 236 | + "client_id": "4xh4eb3f-cz0j-2aso-hu6i-36207018771a", |
| 237 | + "client_version": "2025.2.0" |
| 238 | + }, |
| 239 | + { |
| 240 | + "colo_name": "bos01", |
| 241 | + "uuid": "g6cdeiz1-80f5-3akx-b18b-3y0ggktoxwkd", |
| 242 | + "id": "g6cdeiz1-80f5-3akx-b18b-3y0ggktoxwkd", |
| 243 | + "is_pending_reconnect": false, |
| 244 | + "origin_ip": "10.1.0.137", |
| 245 | + "opened_at": "2025-02-19T19:11:12.110765Z", |
| 246 | + "client_id": "4xh4eb3f-cz0j-2aso-hu6i-36207018771a", |
| 247 | + "client_version": "2025.2.0" |
| 248 | + } |
| 249 | + ], |
| 250 | + "conns_active_at": "2025-02-19T19:11:12.004721Z", |
| 251 | + "conns_inactive_at": null, |
| 252 | + "tun_type": "cfd_tunnel", |
| 253 | + "metadata": {}, |
| 254 | + "status": "healthy", |
| 255 | + "remote_config": true |
| 256 | + } |
| 257 | +} |
| 258 | +``` |
| 259 | + |
| 260 | +A healthy tunnel will have four connections to Cloudflare's network. |
0 commit comments