How to Self-Host Keycloak Securely with Cloudflare Tunnel

Ever wanted to run your own identity and access management (IAM) system for your home lab or personal projects? Keycloak is a fantastic open-source tool for exactly that. But exposing a critical service like Keycloak to the internet can be daunting. You have to worry about firewall rules, HTTPS certificates, and securing open ports.

What if you could get all the benefits of a public-facing Keycloak instance without ever opening a single port on your router?

This guide will walk you through setting up a secure, self-hosted Keycloak instance on your own Linux server. By using Cloudflare Tunnel, we’ll make Keycloak securely accessible over the internet with a valid HTTPS certificate, all while keeping our network locked down. It’s the ideal setup for a home lab or any small-scale deployment.

How It Works: The Magic of Cloudflare Tunnel

The elegance of this setup lies in its architecture. Instead of you opening a port and forwarding traffic to Keycloak, a lightweight agent on your server establishes a secure, outbound-only connection to Cloudflare’s global network.

Here’s the traffic flow:

User’s Browser → HTTPS → Cloudflare Edge → Encrypted Tunnel → Your Server → HTTP → Keycloak

All traffic from the public internet is handled by Cloudflare, which provides robust security and TLS (HTTPS) encryption. The encrypted tunnel ensures that the connection to your server is completely secure. The only unencrypted part of the journey is the final hop between the tunnel agent and Keycloak inside your own trusted local network—a standard and secure practice.

Step 1: Create a Dedicated User for Keycloak

First things first: never run server applications as the root user. We’ll follow the Principle of Least Privilege by creating a dedicated system user that will only own and run the Keycloak process. This dramatically limits potential damage if the application is ever compromised.

# Create a system user named 'keycloak' with no login shell  
sudo useradd -r -s /bin/false keycloak

# Assuming you've placed Keycloak in /opt/keycloak  
# Set ownership of the directory to your new user  
sudo chown -R keycloak:keycloak /opt/keycloak

Step 2: Configure Keycloak for a Reverse Proxy

Keycloak is smart, but it needs to be told two things: its public-facing address and the fact that it’s operating behind a reverse proxy (our Cloudflare Tunnel). These settings are configured in the /opt/keycloak/conf/keycloak.conf file.

Open the file for editing:

sudo nano /opt/keycloak/conf/keycloak.conf

Now, add the following configuration. Remember to replace the placeholder values with your own!

# --- Database Configuration ---  
# You must configure a production database (e.g., PostgreSQL).  
# Keycloak's 'start' command will not work with the default H2 dev database.  
db=postgres  
db-username=keycloak  
db-password=YOUR_STRONG_DB_PASSWORD  
db-url=jdbc:postgresql://localhost/keycloak

# --- Proxy and Hostname Configuration ---  
# Tells Keycloak to trust the X-Forwarded-* headers from the Cloudflare proxy.  
proxy-headers=xforwarded

# Set this to the public domain you will use with Cloudflare Tunnel.  
hostname=keycloak.yourdomain.com

# Allows Keycloak to bind to an unencrypted HTTP port.  
# This is secure because only the local Cloudflare Tunnel agent will access it.  
http-enabled=true

Step 3: Set Up the Cloudflare Tunnel

With Keycloak ready, it’s time to create the secure tunnel. This will expose Keycloak’s local HTTP port (8080) to the internet as a secure HTTPS service.

  1. Install cloudflared: Follow the official Cloudflare documentation to install the cloudflared agent on your Linux server and authenticate it with your Cloudflare account.
  2. Create the Tunnel: Using the Cloudflare Zero Trust dashboard, create a new tunnel.
  3. Route the Traffic: Create a public hostname in the dashboard (e.g., keycloak.yourdomain.com) and point it to your local Keycloak service by specifying the service URL: http://localhost:8080.

Once saved, any request to https://keycloak.yourdomain.com will be securely routed through the tunnel to your local Keycloak instance. No firewall changes needed!

Step 4: Run Keycloak as a systemd Service

To make our Keycloak instance truly robust, we’ll run it as a systemd service. This ensures it starts automatically on boot and will be restarted if it ever crashes.

Create a new service file:

sudo nano /etc/systemd/system/keycloak.service

Paste in the following configuration. This file tells systemd how to manage the Keycloak process, including which user to run it as.

[Unit]  
Description=Keycloak Identity and Access Management  
After=network.target

[Service]  
Type=idle  
User=keycloak  
Group=keycloak  
ExecStart=/opt/keycloak/bin/kc.sh start  
WorkingDirectory=/opt/keycloak  
Restart=on-failure  
TimeoutStartSec=600

[Install]  
WantedBy=multi-user.target

Notice the ExecStart command is a simple kc.sh start. All our complex configuration is neatly handled by the keycloak.conf file we created earlier.

Finally, let’s enable and start our new service:

# Reload systemd to recognize the new file  
sudo systemctl daemon-reload

# Enable the service to start on boot and start it right now  
sudo systemctl enable --now keycloak.service

# Check its status to make sure everything is running smoothly  
sudo systemctl status keycloak.service

You’re All Set!

Congratulations! You now have a secure, robust, and professionally managed Keycloak instance running in your own environment. It’s accessible from anywhere via a secure HTTPS URL, requires no risky inbound firewall rules, and will manage itself automatically.

You can now manage your service with standard systemctl commands (start, stop, restart) and view its logs anytime with journalctl -u keycloak.service. Happy authenticating! 🚀