Redis-cli hangs when trying to connect to cloudflared TCP tunnel running in Docker

What is the name of the domain?

still.fyi

What is the issue you’re encountering

Inability to connect redis-cli (on local machine) to cloudflared tunnel running in Docker

What steps have you taken to resolve the issue?

I was attempting to expose a Redis instance running in Docker through a Cloudflare Tunnel (cloudflared) using TCP. My goal was to access Redis remotely via a custom subdomain (xyz.example.com), which had a CNAME record pointing to my tunnel’s .cfargotunnel.com domain. The tunnel was configured with a public hostname in the Cloudflare Zero Trust dashboard, pointing to tcp://redis:6379 on my Docker network.

After confirming that:

  • The tunnel was showing as “Healthy” in the Cloudflare dashboard.
  • The Redis container was accessible locally within the Docker network.
  • The DNS resolution for my custom subdomain returned Cloudflare IPs.

I attempted to connect to Redis using:

cloudflared access tcp -T <UUID>.cfargotunnel.com -L localhost:6173

# In another terminal:
redis-cli -h localhost -p 6173

However, the connection would hang indefinitely without any response. Additionally, if I used the custom subdomain (xyz.example.com) like so:

cloudflared access tcp -T xyz.example.com -L localhost:6173

# In another terminal:
redis-cli -h localhost -p 6173

…I would receive a “no such host” error in the cloudflared logs (but later confirmed that was caused by Cloudflare proxying being enabled on the CNAME, and now the connection hangs indefinitely with either hostname).

Finally, I tried using an exact IP address instead of tcp://redis:6374 for the ingress rule of my tunnel.

At this point, I verified that:

  • My DNS configuration was correct (dig and nslookup confirmed the domain was resolving).
  • The CNAME record was properly pointing to the tunnel (without proxying enabled).
  • Redis was accessible within my Docker network.

I later realized that I had not created any Cloudflare Access application or policy in the Zero Trust dashboard. This made me wonder if the lack of an Access policy was causing Cloudflare to block the TCP connection silently. However, I’m still unclear about a few things:

  • Is what I’m trying to do supported by the Cloudflare free plan? I’ve come across some claims that TCP tunneling might only be available to Cloudflare Spectrum enterprise customers, and I’m not sure if that applies here. (edit: I saw here that this is only true for clientless arbitrary TCP.)
  • Do I need an Access policy for this setup to work? I read through the “Arbitrary TCP” documentation, and step “3. Secure the subdomain with Cloudflare Access” seemed a bit vague. Is creating an Access policy strictly necessary in this case? And if so, do I also need to create an “application” in Access > Applications, or is the Access policy itself sufficient?
  • Do I need to configure anything under Zero Trust > Networks > Routes? I noticed there’s a section for defining private network routes in the Zero Trust dashboard. However, my understanding is that this only applies if I’m using cloudflared in private network mode, rather than as a TCP proxy for a public hostname. Is that correct, or do I need to define something there as well?

I’m hoping to better understand if my current configuration is even supported on the free plan, and if so, what the minimal set of configurations in Cloudflare Zero Trust would look like to get it working.

Okay, it appears I’ve got it working!

  • Ensure CNAME exists with xyz as the name and <UUID>.cfargotunnel.com as the content. Importantly, enable proxying (the orange cloud).
  • Ensure the tunnel is healthy on the “Zero Trust > Networks > Tunnels” page.
  • Connect from the client side with:
    cloudflared access tcp -T xyz.example.com -L localhost:6379
    
  • Connect to Redis with:
    redis-cli -h localhost -p 6174 -a <PASSWORD>
    

Additional notes:

  • Using either tcp://redis:6379 or the exact container IPv4 address works.
  • You do not need a route in “Zero Trust > Networks > Routes”.
  • You do not need an access policy in “Zero Trust > Access > Policies”.

Strangely, this same approach isn’t working with Postgres. Specifically, I’m getting the same “no such host” in my cloudflared access logs as I was getting earlier with the Redis setup.

The only things different are:

  1. Replace redis with postgres
  2. Replace tcp://redis:6379 with tcp://postgres:5432
  3. Replace xyz.example.com with abc.example.com

I checked the cloudflared container logs to confirm that the configuration was updated.

Strangely, the Redis setup had warp-routing.enabled set to true, even though I never explicitly set it. Yet, the Postgres setup did not, despite using the same Pulumi code. So I enabled warp-routing in the Postgres setup, but it hasn’t fixed the issue.

I’ve used dig to verify that both the Redis CNAME record and the Postgres CNAME record are identical. Both have proxying enabled with their content set to the associated <UUID>.cfargotunnel.com hostname.

edit: Okay, it’s working! Hard to say if it was my doing, or if it just takes a while for Cloudflare’s arbitrary TCP tunnel to start accepting connections.

But it seems too much of a coincedence that it worked right after I flushed the DNS cache with sudo killall -HUP mDNSResponder.