本帖最后由 Test 于 2026-10-9 19:31 编辑
There are often situations where you want to expose web services running on your office or home LAN to the outside world with HTTPS, without opening ports or using a static IP. You can achieve this for free using Cloudflare Tunnel (cloudflared).This time, I created a configuration where two web services on a separate host (192.168.5.120) are exposed externally via separate subdomains from a single Ubuntu 22.04 machine. Ultimately, I built and set it up as a persistent service using the dashboard method (Web GUI management). I am leaving these notes, including the points where I actually got stuck.
Configuration Overview
smpl0001.example.com ──┐
├─ Cloudflare ─ Tunnel ─ Ubuntu22(cloudflared)
smpl0002.example.com ──┘ ├─→ 192.168.5.120:9000
└─→ 192.168.5.120:9001
Key Points: No router port forwarding is required at all (cloudflared establishes an outbound connection from the inside) HTTPS certificates are automatically issued and renewed by Cloudflare The origin IP is hidden by Cloudflare, which is also great for security
Prerequisites
You own a custom domain and its nameservers are set to Cloudflare A Cloudflare account (Free plan is fine) One Ubuntu 22.04 machine that can reach the target services within the LAN
Subdomain Method vs. Subpath Method
I initially considered path separation like "service.example.com/direa/", but the conclusion is that the subdomain method is overwhelmingly easier. Reasons: Although cloudflared's ingress has a path matching feature, it does not rewrite (strip) the path You end up needing to insert an extra layer of reverse proxy like nginx locally Furthermore, the backend application also requires modifications to "run under a subpath" (absolute paths for CSS/JS, redirect destinations, Cookie Paths, WebSocket paths, etc.)
Retrofitting existing applications to support subpaths is difficult, so unless there is a special reason, you should use subdomains.
CLI Method vs. Dashboard Method
There are two ways to manage cloudflared tunnels.
Although I initially tried to proceed with the CLI method, the token command for "Install cloudflared connector" displayed on the dashboard was overwhelmingly easier, so I ultimately used the dashboard method to make it a resident service. It is a huge advantage that adding hostnames in the future can be completed entirely via the web without needing SSH login.
1. Install cloudflared
Install it from the official Cloudflare apt repository. - sudo mkdir -p --mode=0755 /usr/share/keyrings
复制代码
At this point, the systemd service has not been registered yet. It will be registered using the token in the next step.
2. Create a tunnel in the Cloudflare dashboard
The Cloudflare screen layout was updated around 2024-2025, and it is currently located in the following place.
How to get to the dashboard (latest UI)
It is now referred to as "Connectors." Previously it was "Networks → Tunnels," but in the current UI, the tunnel concept is included within Connectors.
Tunnel creation
Once created, the "Install and run a connector" screen appears, showing the installation command for Ubuntu. This contains a long token (starting with eyJhIjoi...).
3. Make the connector resident using the token
Since the cloudflared binary is already installed via apt, it is sufficient to execute only the latter part of the command displayed on the dashboard (from service install onwards). - sudo cloudflared service install eyJhIjoiM2JlMzdmYW...(ダッシュボードの長いトークン)
复制代码
This automatically performs the following: The token is saved under /etc/cloudflared/ The systemd service cloudflared.service is registered Auto-start enabled & started immediately
Verification:
- [font=YakuHanJPs, Arial, Meiryo, sans-serif][size=16px]sudo systemctl status cloudflared[/size][/font]
- [font=YakuHanJPs, Arial, Meiryo, sans-serif][size=16px]sudo journalctl -u cloudflared -f[/size][/font]
复制代码
If the log shows 4 instances of 'Registered tunnel connection', the connection is successful (4 connections = for high availability). To be sure, check if the service is running correctly using the token method: - sudo systemctl cat cloudflared | grep ExecStart
复制代码- ExecStart=/usr/bin/cloudflared --no-autoupdate tunnel run --token eyJ...
复制代码
If --token is included, it is running in dashboard mode.
4. Register the hostname to expose (The latest UI trap)
This was a point where it was easy to get lost due to UI changes. How to get there (Latest UI)
Networks → Connectors and click the relevant Connector Open the 'Published application routes' tab on the Connector details screen Add using the '+ Add a published application route' button
It used to be a tab named 'Public Hostnames', but in the current UI, it has been renamed to 'Published application routes'. If you are looking at old articles and wandering around looking for 'Public Hostnames', look here. Input details
[/url]When you click Save, a CNAME like the following will be automatically added to the Cloudflare DNS tab. [url=https://assets.st-note.com/img/1777967672-zfw3snmkArB8lygSR01Q72GP.png?width=2000&height=2000&fit=bounds&quality=85]Restarting the server side is not required. It is reflected immediately.
5. Operation check
Query the authoritative DNS directly to check if the record can be resolved. - dig @1.1.1.1 smpl0001.example.com
复制代码
Expected result: - ;; ANSWER SECTION:
- smpl0001.example.com. 300 IN A 104.21.x.x
- smpl0001.example.com. 300 IN A 172.67.x.x
复制代码
The 104.21.x.x / 172.67.x.x range are Cloudflare edge IPs, so this is proof that Proxied (orange cloud) is working. The actual origin (home/office IP) remains hidden and is delivered via the tunnel.
Notes on common pitfalls
1. DNS_PROBE_FINISHED_NXDOMAIN error occurs
Common causes: Typo in the subdomain (I wasted time on this. I was querying smple0001 instead of smpl0001, and I kept running dig until I noticed the extra 'e') Missing registration in Published application routes Domain name servers are not yet set to Cloudflare (verify with dig NS example.com +short) Local/router DNS cache is stale
To isolate the issue, querying the authoritative server directly using dig @1.1.1.1 is the quickest way. If only the SOA is returned and there is no ANSWER, it means the record does not exist.
2. Output returns only SOA
- example.com. 1800 IN SOA adele.ns.cloudflare.com. ...
复制代码
3. Browser/OS DNS cache
If you cannot open the site even though DNS should have propagated: Mac: sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder Windows: ipconfig /flushdns Chrome: Clear host cache at chrome://net-internals/#dns Switching your phone to 4G/5G allows you to quickly determine if it is a router/ISP cache issue
4. Terminology differences between old articles and current UI
Since the terminology differs from older articles found via Google, if you get lost in the UI, look for "Connectors" or "Published application routes".
5. On the Node.js application side
Since access is via Cloudflare, if you are using Express, you should include the following so that req.ip and req.protocol are retrieved correctly. - app.set('trust proxy', true);
- // CF-Connecting-IP / X-Forwarded-Proto を見るようになる
复制代码
Convenient operational aspects
Adding hostnames → Click "+ Add" and Save in the web dashboard. No SSH login required Removing hostnames → Delete on the same screen. DNS records are also automatically cleaned up. HTTPS certificates → Cloudflare is fully automated. No need to worry about Let's Encrypt renewals. Access restrictions → You can retroactively apply Google login enforcement, etc., via Zero Trust → Access. Perfect for internal tools. Connecting from a new location → Create a new Connector on the Connectors screen and install it on another machine using the token.
Since you can attach multiple hostnames to a single tunnel (connector), unless you have very specific requirements, one tunnel + multiple hostnames is all you need for operation.
Recommended Cloudflare settings
It is recommended to enable the following in the dashboard. Summary
If you want to expose multiple web services within your LAN, Cloudflare Tunnel + subdomains is the gold standard. With the dashboard method, you just need to run 'service install ' on the server to complete the setup as a resident service. Adding or removing hostnames is completed entirely via the Web GUI; no SSH required. No port forwarding required, HTTPS is automatic, origin is hidden, and it works within the free tier. The UI names have changed, so remember "Connectors" and "Published application routes". If you get stuck, troubleshoot with 'dig @1.1.1.1' and be careful with the spelling of your subdomains (a lesson learned).
Sub-path routing (/direa/) is theoretically possible, but it requires local nginx + app base path support, which is a hassle. Simply creating subdomains was the right choice. I hope this is helpful to someone. 2026年5月5日 01:03
来自圈子: Demo俱乐部 |