Access MySQL server through Cloudflare Zero-Trust Tunnel

# Create and access cloudflare tunnel to remote mysql server (cli)

Cloudflare had pretty good and simple UI dashboard, that can be used to create and manage tunnels, but this post shows how to do it from the cli.

This base example below is straight-forward, stript out of details and can give you idea of how Cloudflare tunnels can be used for other implementations and services.



# Preparation:

# Install cloudflared cli tool:

https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/


# If you have warp-cli installed and started, you should disable it temporary:

$ warp-cli disconnect
$ warp-cli delete 

# Make sure WebSockets are enabled in

dash.cloudflare.com -> [ZoneName] -> Network


# If you use mysql inside docker container:

Make sure to use host networking mode. Mysql container service should be accessible from the host. To do that use:

docker-compose:

services:
    mysql:
        image: mysql:5.7.40
        container_name: my-mysql
        network_mode: host
        ...
    ...

docker cli:

docker run ... --network host ... --name my-mysql


# 1. Authenticate cloudflared with an Cloudflare account and choose a zone:

$ cloudflared tunnel login

The command will open new browser tab and require you to login in Cloudflare dashboard with your username and password. After that, you have to choose a zone to authorize agains.

On success, certificate will be generated and saved inside your .cloudflared directory, which is usually in your user root: /home/username/.cloudflared/cert.pem



# 2. Create new tunnel

cloudflared tunnel create my-mysql-tunnel

In your .cloudflared folder, you should now see a .json file, which represents newly created tunnel id.

ls .cloudflared/
4554bd9a-62b2-4d9a-bf3t-dgbv8605c5zb.json  cert.pem

Also, in Cloudflare Zero-Trust Dashboard, you should see your new tunnel.



# 3. Create configuration file

This is needed for the tunnel to know, what will be server through it and how to access it.

Create new /home/username/.cloudflared/config.yml file:

url: tcp://localhost:3306
tunnel: 4554bd9a-62b2-4d9a-bf3t-dgbv8605c5zb
credentials-file: /home/username/.cloudflared/4554bd9a-62b2-4d9a-bf3t-dgbv8605c5zb.json

As you can see in url parameter, the tunnel access point is to my locally accessible 3306 (mysql server default port). Important to notice is the tcp:// protocol used.



# 4. Create DNS record for this tunnel

It is clear, that you will want to access the mysql instance remotely vie the tunnel. For this you need to create new DNS record in the zone, you choosed earlier:

cloudflared tunnel route dns my-mysql-tunnel mysql.domain.com

or using the tunnel ID

cloudflared tunnel route dns 4554bd9a-62b2-4d9a-bf3t-dgbv8605c5zb mysql.domain.com

If you now go to Cloudflare Dashboard, in your selected zone DNS section, you will see new CNAME record created.



# 5. Start the tunnel

cloudflared tunnel --config /home/username/.cloudflared/config.yml run 4554bd9a-62b2-4d9a-bf3t-dgbv8605c5zb

shorthand command:

cloudflared tunnel run my-mysql-tunnel


# Almost done: to access the tunnel remotely, on the client machine, run:

cloudflared access tcp --hostname mysql.domain.com --url localhost:3366

Where:

--hostname: is the DNS record, address of the tunnel --url: local port to be used on the clients side of the tunnel

Now, cloudflared uses tcp protocol to connect to a tunnel, located at mysql.domain.com and makes it available locally on port localhost:3366



# Finally, connect to the remove mysql server via the tunnel:

mysql -h localhost -P3366 --protocol=tcp -u root -p