In the previous article, we managed to make apps on our home server accessible from the internet using Cloudflare Tunnel — no public IP and no port forwarding needed.
Now comes the next problem.
Our apps are accessible from anywhere, which also means anyone who knows the address can try to access them.
For example:
https://portainer.yourdomain.com
https://monitor.yourdomain.com
https://dashboard.yourdomain.com
For public apps, that’s fine.
But what about internal dashboards, monitoring tools, or private applications?
We can add an authentication layer using Cloudflare Access.
The end result:
Internet
│
▼
Cloudflare
│
▼
Cloudflare Access
│
│ Is the user allowed?
│
├── No → Block
│
└── Yes
│
▼
Cloudflare Tunnel
│
▼
Home Server
│
▼
Application
Requests don’t even reach the home server before passing through Cloudflare Access.
What Is Cloudflare Access?
Cloudflare Access is part of Cloudflare Zero Trust that lets us add authentication and authorization in front of an application.
Simply put, Cloudflare becomes the bouncer before requests reach the app.
Without Access:
Browser
↓
Cloudflare
↓
Tunnel
↓
Application
With Access:
Browser
↓
Cloudflare
↓
Access Policy
↓
Authentication
↓
Tunnel
↓
Application
The user must satisfy the policy we define before Cloudflare forwards the request.
The interesting part is the application behind it doesn’t need to be modified at all.
1. When Is Cloudflare Access Useful?
Not every application needs Cloudflare Access.
For apps that are intentionally public:
blog.yourdomain.com
api.yourdomain.com
website.yourdomain.com
Access isn’t necessary.
But for services like:
portainer.yourdomain.com
monitor.yourdomain.com
grafana.yourdomain.com
admin.yourdomain.com
Access is very useful.
Especially if these services are only used by ourselves or a few specific people.
2. Before You Start
Make sure you have:
- A domain using Cloudflare DNS
- An active Cloudflare Tunnel
- An application already accessible via its domain
- A Cloudflare Zero Trust account
For example, we already have:
https://monitor.yourdomain.com
pointing through Cloudflare Tunnel to:
http://192.168.1.10:3001
Before installing Access, make sure this URL is already working.
That way, if something goes wrong later, we know the problem is in the Access configuration, not the Tunnel.
3. Open Cloudflare Zero Trust
Go to the Cloudflare dashboard and open:
Zero Trust
→ Access
→ Applications
Select:
Add an application
For a web application hosted on your home server, choose:
Self-hosted
Self-hosted here doesn’t mean Cloudflare runs the application.
The app still runs on our own server.
Cloudflare only protects access to it.
4. Add the Application Domain
For example, we want to protect:
monitor.yourdomain.com
Enter that hostname as the application domain:
Application name:
Home Server Monitor
Domain:
monitor.yourdomain.com
Cloudflare now knows that requests to this domain must go through Access first.
5. Create an Access Policy
This is the most important part.
We need to define:
Who is allowed in?
Create a new policy, for example:
Policy name:
Allow My Email
Action:
Allow
Then under Include, select:
Emails
Enter your email:
This means only accounts with that email can pass through Cloudflare Access.
Requests from other users will be rejected before reaching the home server.
6. Login via Email OTP
For a personal setup, we don’t need to connect Google, GitHub, Microsoft, or other identity providers right away.
Cloudflare provides a method called:
One-time PIN
The flow is simple.
When accessing:
https://monitor.yourdomain.com
Cloudflare shows a login page.
We enter our email.
Cloudflare then sends a verification code to that email.
Email
↓
One-time PIN
↓
Cloudflare Access
↓
Application
Enter the code, and if the email satisfies the Access Policy, we can access the app.
For a personal home server, this method is comfortable enough.
7. Why Email Policy Matters
Don’t just enable login without restricting who can enter.
If our policy is too broad:
Include:
Everyone
Anyone who authenticates can get in.
For private services, it’s safer to use:
Emails:
[email protected]
Or if used by multiple people:
Cloudflare Access then functions as an authorization layer, not just a login page.
8. Test Cloudflare Access
After saving the policy, open the app using an Incognito or Private Window:
https://monitor.yourdomain.com
You shouldn’t see the application directly.
Cloudflare will show the authentication page first.
The full flow is now:
monitor.yourdomain.com
↓
Cloudflare Edge
↓
Cloudflare Access
↓
Authentication
↓
Access Policy
↓
Cloudflare Tunnel
↓
Home Server
↓
Monitoring App
If you use an email not in the policy, the request will be rejected.
If you use an allowed email, the request is forwarded to the application.
9. Is App Login Still Needed?
For example, Portainer has its own login.
Then we put Cloudflare Access in front of it.
Now users must go through:
Cloudflare Access Login
↓
Portainer Login
Isn’t that redundant?
A little.
But this is exactly defense in depth.
The app’s own login remains its primary authentication.
Cloudflare Access adds an extra layer before the application can even be reached.
So attackers from the internet don’t face Portainer’s login page directly.
They must pass Cloudflare Access first.
10. Protect Internal Dashboards
Now we can do the same for other services.
For example:
portainer.yourdomain.com
grafana.yourdomain.com
monitor.yourdomain.com
npm.yourdomain.com
Instead of all of them being directly available from the internet:
Internet
↓
Application Login
We place Access in front:
Internet
↓
Cloudflare Access
↓
Application Login
This is especially suitable for administrative dashboards.
11. One Policy for Multiple Applications
If you have many internal applications, you don’t need to create different email rules for each.
You can create a consistent policy pattern:
Home Server Admin
Allow:
[email protected]
Then use the same policy across multiple internal applications.
┌── Portainer
│
Cloudflare Access ──┼── Grafana
│
├── Monitoring
│
└── Admin Dashboard
One identity can be used to access several services.
12. What About Wildcards?
For example, you might have been using:
*.home.yourdomain.com
for various home server apps.
You might be tempted to create one wildcard policy and call it done.
Technically this can work, but you still need to think about application classification.
Not all services have the same access level.
For example:
photos.home.yourdomain.com
might be used by family.
While:
portainer.home.yourdomain.com
should only be used by the administrator.
It’s better to separate policies by need than to create one overly broad policy just because it’s more convenient.
13. Cloudflare Access Is Not a Replacement for Firewalls
One important thing.
Cloudflare Access protects this path:
Internet
→ Cloudflare
→ Tunnel
→ Application
But we still need to make sure the application doesn’t have another public path that bypasses Cloudflare.
For example, make sure this is not available:
Internet
→ Public IP
→ Port Forwarding
→ Application
If an attacker can access the application directly via public IP, Cloudflare Access can be completely bypassed.
That’s why one of the benefits of combining Cloudflare Tunnel + Access is we don’t need to open application ports to the internet.
14. Cloudflare Access vs Tailscale
If you’ve been following home server setup for a while, a question might arise:
If we already have Cloudflare Access, do we still need Tailscale?
I think they serve slightly different purposes.
Cloudflare Access is great when you want to access applications through a browser:
https://monitor.yourdomain.com
without needing to connect to a VPN first.
While Tailscale is better suited for private access like:
SSH
Database
Samba
Internal API
Server management
I usually divide it like this:
WEB APPLICATION
↓
Cloudflare Tunnel + Access
and:
PRIVATE NETWORK
↓
Tailscale
With this division, we don’t need to force one technology to handle everything.
15. The Final Home Server Architecture
After three parts of this series, our home server architecture starts to look like this:
Internet
│
▼
Cloudflare
│
┌─────────┴─────────┐
│ │
▼ ▼
Public App Private Web App
│ │
│ Cloudflare Access
│ │
└─────────┬─────────┘
│
▼
Cloudflare Tunnel
│
▼
Home Server
For administrative network access:
Laptop
│
▼
Tailscale
│
▼
Home Server
│
├── SSH
├── Database
└── Internal Services
With this setup, we’re not just making the home server accessible from the internet.
We’re starting to define who can access what.
Conclusion
Cloudflare Tunnel solves the problem:
How can apps on a home server be accessed from the internet without a public IP and port forwarding?
Cloudflare Access answers the next question:
Once it’s accessible from the internet, how do we restrict who can get in?
The combination of both keeps internal services comfortably accessible without directly exposing the server.
For public apps, just use Cloudflare Tunnel.
For dashboards and private apps, add Cloudflare Access.
For SSH, databases, and other internal network access, use a private network like Tailscale.
This way our home server isn’t just accessible from anywhere, but its access is also much more controlled.
This series consists of:
- Making Your Home Server Accessible from Anywhere — why Cloudflare Tunnel is interesting
- Setting Up Cloudflare Tunnel from Scratch — step by step installation
- Securing Your Home Server with Cloudflare Access — this article
COMMENTS & DISCUSSION