Securing Private Network Access with Cloudflare Tunnel
For many, Cloudflare provides an essential suite of network security tools that their organization integrates with deeply. One such tool is "Cloudflare Tunnel " - a secure way to connect resources to Cloudflare without a publicly routable IP address.
When deploying sensitive applications to Cycle, Cloudflare Tunnel can be leveraged to ensure all traffic is routed through Cloudflare before reaching your environment's load balancer. This extra layer of security provides quite a few benefits:
- Less susceptible to attacks that would attempt to bypass Cloudflare and target load balancers/applications directly.
- DDoS Mitigation
- Zero-Trust access without requiring a VPN
- Potentially better integration with existing organization infrastructure
Prerequisites
In order to configure Cloudflare Tunnel for use with an environment on Cycle, you'll need to set up the following:
- A Cloudflare account - Cloudflare Tunnel itself is free, though some advanced features may be paid
- A DNS zone configured at Cloudflare
- A Cycle account with a hub configured.
In this guide, we'll be using the Cycle Portal to set everything up, but this would also be achievable using the API .
Setting up Cloudflare
First, we need to set up the "Zero Trust" dashboard. Log into your Cloudflare account, and select "Access" from the sidebar. For some, this may also show up as "Zero Trust" If it's not configured, go through the setup process until you land on the "Zero Trust overview" page:

On the left menu, click "Networks", and then "Tunnels". From here, we can manage our tunnels. Click "Create a tunnel", then choose "Cloudflared"

Name your tunnel something that will help you remember its purpose (like cycle-tunnel
) and hit "save".

You'll see some information about how to connect to this tunnel using the generated token. We'll come back to this page shortly. For now, click "Next" in the bottom right corner, so we can set up the public hostname.
Adding the Public Hostname
Required For Each Domain
The following process will need to be repeated for every domain/subdomain you want to route to your Cycle environment.
We need to tell the tunnel to route traffic to Cycle's Load Balancer over the environment's private network. To do that, fill in the fields for whatever domain you would like requests to be forwarded for.
The real magic is the value set for the Service
section. Here, we tell the tunnel to forward all traffic
for this domain to the environment load balancer, which will handle the requests to forward to the relevant container.
Set the Type
field to HTTP, and the URL
field to env-lb, then click "Save tunnel".

Now, open the tunnel page back up for editing, and keep this page open. We'll need the token when we set up the actual tunnel container on Cycle.
Deploying the Tunnel Container On Cycle
The next step is to deploy the Cloudflare Tunnel container on Cycle. This container will set up an egress connection from the Cycle environment back to Cloudflare. From there, Cloudflare will forward all inbound requests to the tunnel domain through that connection and into the Cycle environment. Then, the container will forward that request to the Cycle Load Balancer, with all of the necessary headers for the load balancer to understand its final destination container.
Import the cloudflared Container Image
On Cycle, click "Images" in the left menu, then "Sources". On the top, click "Create". (Or, click here ).
Fill in the form like this:

We're importing the container from Docker Hub, so nothing special is necessary to set up this image source.
Deploy the Cloudflare Container
On Cycle, navigate to the environment you'd like the tunnel to have access to, by clicking "Environments" in the left menu, and then choosing the environment from the list.
Next, in the top right corner, click "Deploy Container", and fill in the form to match this:

The public network can be set to "Egress Only", since the container just needs to create a tunnel back to cloudflare. No inbound requests will be made from the public internet into the tunnel.
Authenticate the Cloudflare Container
Next, we need to authenticate the cloudflared
container. Switch back to the Cloudflare tab from earlier, and select the
"Docker" environment, and copy the command.

Now, on Cycle, return to our cloudfared
container, and navigate to the 'Config' tab on the left inside
the container dialog. Under Runtime
, find the Command
section, and the override
option for path & args.
Configure your override to look like this:

This will allow the container to authenticate back to Cloudflare.
Configure DNS on Cycle
Now, switch back to your Cycle tab.
Configure Other Containers
If you don't have any other containers set up in this environment, you should set them up now. Configure the network to accept traffic over port 80:80 (or whatever port your container serves traffic over).
It is important to NOT configure any ports for 443
(https) traffic. All
https traffic is handled and terminated by the tunnel.
Next, for each container in the environment we want accessible over tunnel, we need to train Cycle's load balancer to route traffic to it for the domain you want. Traffic from the tunnel will hit the load balancer, which will then forward it to our target container for that domain.
Head over to DNS > Zones on the left. Click "Create" up top to create a new DNS zone.
This DNS zone needs to match the one you have configured on Cloudflare. Set it up as a Non-Hosted Zone. A Non-Hosted Zone doesn't require verification, and Cycle just uses it to train the load balancer how to route traffic.

After you've finished creating the zone, add a LINKED record to the zone by clicking "Add Record" in the top right and selecting
LINKED from the dropdown. Set up your specified domain (again, matching the domain in Cloudflare). If you're using the root, enter @
in the "Name" field.
DO NOT enable TLS. Cloudflare will handle TLS for us.
Point it to whatever container you'd like that domain to resolve to within the environment containing the tunnel.

Give it a Whirl
Congratulations! If everything was configured correctly, your domain should now be resolving to the target container. But instead of hitting the environment load balancer directly, it's passing through Cloudflare and into the tunnel to get there instead!
Adding Extra Security
In the next release of the Cycle platform, we'll be introducing the ability to configure the load balancer to only bind to private IPs, which in tandem with the tunnel above, will prevent any access to containers in the environment without first going through Cloudflare.