How to create Argo Tunnel

Create Argo Tunnel to expose internal service and securely access it over the internet.

Initial Cloudflare configuration

Enable Tiered Caching + Smart Routing on the Traffic tab.

Review billing for Argo as this service is not free and relates directly to the bandwidth used between Cloudflare and your visitors. I recommend to use separate domain to keep things clean.

Cloudflare - Traffic

Create firewall rule to block access to this domain, you can later use Cloudflare Access, but this is out of scope of this article.

Cloudflare - Firewall

This rule will ensure that you can access specified subdomain using whitelisted IP address.

Prepare virtual machine and perform initial test

Ensure that wget is installed.

$ sudo apt install wget

Download package using wget.

Check out downloads page for packages intended for other operating systems or achritectures.
$ wget https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb  
--2019-08-15 00:02:31--  https://bin.equinox.io/c/VdrWdbjqyF/cloudflared-stable-linux-amd64.deb
Resolving bin.equinox.io (bin.equinox.io)... 34.206.130.40, 52.7.169.168, 54.236.200.27, ...
Connecting to bin.equinox.io (bin.equinox.io)|34.206.130.40|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 12899838 (12M) [application/octet-stream]
Saving to: 'cloudflared-stable-linux-amd64.deb'

cloudflared-stable-linux-amd64.deb    100%[===================>]  12.30M  1.18MB/s    in 12s

2019-08-15 00:02:43 (1.07 MB/s) - 'cloudflared-stable-linux-amd64.deb' saved [12899838/12899838]

Install cloudflared package.

$ sudo dpkg -i cloudflared-stable-linux-amd64.deb 
Selecting previously unselected package cloudflared.
(Reading database ... 32739 files and directories currently installed.)
Preparing to unpack cloudflared-stable-linux-amd64.deb ...
Unpacking cloudflared (2019.8.1) ...
Setting up cloudflared (2019.8.1) ...

Obtain a tunnel certificate for specific domain.

$ cloudflared tunnel login
Please open the following URL and log in with your Cloudflare account:

https://dash.cloudflare.com/argotunnel?callback=https%3A%2F%2Flogin.cloudflarewarp.com%2FJns82aKlwRicY%3D

Leave cloudflared running to download the cert automatically.
INFO[0050] Waiting for login...                         
You have successfully logged in.
If you wish to copy your credentials to a server, they have been saved to:
/home/milosz/.cloudflared/cert.pem

Cloudflare - Argo - Authorize domain

Cloudflare - Argo - Authorize domain dialog

Create tunnel using a cloudflare.sleeplessbeastie.eu hostname and hello-world HTTP server to verify that connection can be established.

$ cloudflared tunnel --hostname cloudflare.sleeplessbeastie.eu --hello-world
WARN[0000] Cannot determine default configuration path. No file [config.yml config.yaml] in [~/.cloudflared ~/.cloudflare-warp ~/cloudflare-warp /usr/local/etc/cloudflared /etc/cloudflared]
INFO[0000] Version 2019.8.1
INFO[0000] GOOS: linux, GOVersion: go1.12.7, GoArch: amd64
INFO[0000] Flags hello-world=true hostname=cloudflare.sleeplessbeastie.eu proxy-dns-upstream="https://1.1.1.1/dns-query, https://1.0.0.1/dns-query"
INFO[0000] cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/argo-tunnel/reference/service/ 
INFO[0000] hello-world set
INFO[0000] Starting metrics server addr="127.0.0.1:37317"
INFO[0000] Starting Hello World server at 127.0.0.1:41269 
INFO[0000] Proxying tunnel requests to https://127.0.0.1:41269 
INFO[0002] Connected to CDG
INFO[0002] Each HA connection's tunnel IDs: map[0:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg] 
INFO[0002] Route propagating, it may take up to 1 minute for your new route to become functional 
INFO[0004] Connected to DUB
INFO[0004] Each HA connection's tunnel IDs: map[0:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 1:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg] 
INFO[0004] Route propagating, it may take up to 1 minute for your new route to become functional 
INFO[0005] Connected to CDG
INFO[0005] Each HA connection's tunnel IDs: map[0:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 1:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 2:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg] 
INFO[0005] Route propagating, it may take up to 1 minute for your new route to become functional 
ERRO[0019] Unable to dial edge error="DialContext error: dial tcp 198.41.200.53:7844: i/o timeout"
INFO[0019] Retrying in 1s seconds
INFO[0022] Connected to DUB
INFO[0022] Each HA connection's tunnel IDs: map[0:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 1:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 2:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg 3:h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg] 
INFO[0022] Route propagating, it may take up to 1 minute for your new route to become functional 

It will automatically create a CNAME DNS entry.

CNAME cloudflare is an alias of h84sxpe0l3g8gc5lx2n95cfk0cf5gylruaq237lav4az80575lsg.cftunnel.com  Automatic

Cloudflare - Argo - Hello world

Create persistent configuration on virtual machine

Create /etc/cloudflared configuration directory.

$ sudo mkdir /etc/cloudflared

Move already stored certificate.

$ sudo mv ~/.cloudflared/cert.pem /etc/cloudflared/

Create /etc/cloudflared/config.yml configuration file.

$ cat /etc/cloudflared/config.yml
hostname: cloudflare.sleeplessbeastie.eu
loglevel: warn
url: http://127.0.0.1
logfile: /var/log/cloudflared.log

Prepare systemd configuration.

$ sudo cloudflared service install
INFO[0000] Using Systemd                                
ERRO[0000] systemctl: Created symlink /etc/systemd/system/multi-user.target.wants/cloudflared.service → /etc/systemd/system/cloudflared.service. 
INFO[0000] systemctl daemon-reload   

Start cloudflared service.

$ sudo systemctl start cloudflared

Enable cloudflared service at boot.

$ sudo systemctl enable cloudflared

Cloudflare - Argo - First run

Enable agent update process on virtual machine

Check out offical download server and update the agent binary if a new version exists.

Start cloudflared-update.timer.

$ sudo systemctl start cloudflared-update.timer

Enable cloudflared-update.timer at boot.

$ sudo systemctl enable cloudflared-update.timer

Check out current cloudflared-update.timer status.

$ sudo systemctl status cloudflared-update.timer
● cloudflared-update.timer - Update Argo Tunnel
  Loaded: loaded (/etc/systemd/system/cloudflared-update.timer; enabled; vendor preset: disabled)
  Active: active (elapsed) since śro 2019-08-14 19:16:31 CEST; 3s ago

sie 14 19:16:31 cloudflare systemd[1]: Stopping Update Argo Tunnel.
sie 14 19:16:31 cloudflare systemd[1]: Started Update Argo Tunnel.
sie 14 19:16:31 cloudflare systemd[1]: Starting Update Argo Tunnel.

Additional information

Firewall configuration

Ensure that virtual machine can access Cloudflare IPs on port 7844, TCP protocol.

Multi-level subdomains

To use multi-level subdomains you need to have them covered using Edge Certificates. Note, Cloudflare will return 403 Forbidden if you omit this step.

Create CNAME DNS entries for additional subdomains.

CNAME wiki.internal.cloudflare	is an alias of cloudflare.sleeplessbeastie.eu
This is why I have used contains operator when I was creating firewall block rule.

The last part is to generate Origin Certificate covering additional subdomains and replace certificate and private key used by the cloudflared application. Note, do not remove Argo tunnel token.

Use the same certificate for local HAProxy serving internal websites, alternatively use origin-server-name or no-tls-verify options.

Systemd service files

cloudflared service definition.

$ cat /etc/systemd/system/cloudflared.service
[Unit]
Description=Argo Tunnel
After=network.target

[Service]
TimeoutStartSec=0
Type=notify
ExecStart=/usr/local/bin/cloudflared --config /etc/cloudflared/config.yml --origincert /etc/cloudflared/cert.pem --no-autoupdate
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

cloudflared-update service definition.

$ cat /etc/systemd/system/cloudflared-update.service
[Unit]
Description=Update Argo Tunnel
After=network.target

[Service]
ExecStart=/bin/bash -c '/usr/local/bin/cloudflared update; code=$?; if [ $code -eq 64 ]; then systemctl restart cloudflared; exit 0; fi; exit $code'

cloudflared-update timer definition.

$ cat /etc/systemd/system/cloudflared-update.timer 
[Unit]
Description=Update Argo Tunnel

[Timer]
OnUnitActiveSec=1d

[Install]
WantedBy=timers.target

References