Introduction

Keycloak handles the parts of authentication you don’t want to write yourself: login, single sign-on, user and role management, OIDC and SAML. It’s open-source software you run on your own machine, so this tutorial stands it up on an Atlas Cloud VM. Note that Atlas does not manage Keycloak for you; once it’s installed, patching and upkeep are yours.

Prerequisites

You’ll need an Atlas Cloud account with admin rights and a VM with a public IP attached (the Creating your first cloud service guide covers that). Some comfort at the Linux command line helps, since the whole install happens over SSH.

Create a Virtual Machine for Keycloak

If you don’t have a VM yet, work through Creating your first cloud service first. Size it for Keycloak while you’re there: Ubuntu 24.04 LTS, at least 2 CPU cores, 4 GiB of memory, and a 20 GiB root disk. Keycloak and PostgreSQL together are comfortable at that size; smaller and the JVM starts to feel it.

Install Java and Keycloak

SSH into the VM. The next few steps install Java, then Keycloak itself.

1. Update System Packages

sudo apt update && sudo apt upgrade -y

2. Install Java 21

Keycloak runs on the JVM and wants Java 17 or newer. Java 21 is the current LTS, so install that:

sudo apt install openjdk-21-jdk -y
java -version

3. Download and Install Keycloak

# Download Keycloak
wget https://github.com/keycloak/keycloak/releases/download/23.0.0/keycloak-23.0.0.tar.gz
 
# Extract the archive
tar -xzf keycloak-23.0.0.tar.gz
sudo mv keycloak-23.0.0 /opt/keycloak
sudo chown -R $USER:$USER /opt/keycloak

Configure Keycloak

1. Set Up the Bootstrap Admin User

On Keycloak 23, the initial admin account is created on the first start of kc.sh from the KEYCLOAK_ADMIN and KEYCLOAK_ADMIN_PASSWORD environment variables. Set these before the first start, then unset them so the password does not stay in the environment or shell history.

Avoid passing the password as a CLI argument (it is visible in ps and shell history). Generate a strong password, read it from a prompt, and do not reuse this value anywhere else:

cd /opt/keycloak
 
# Generate a strong password and store it somewhere safe (e.g. a secrets manager)
openssl rand -base64 24
 
# Read it interactively rather than placing it on the command line
export KEYCLOAK_ADMIN=admin
read -rs -p "Keycloak admin password: " KEYCLOAK_ADMIN_PASSWORD
export KEYCLOAK_ADMIN_PASSWORD
echo
 
# First start creates the admin account from the env vars above
./bin/kc.sh start-dev --http-port=8080 &
 
# Once the admin user has been created, clear the credentials from the environment
unset KEYCLOAK_ADMIN KEYCLOAK_ADMIN_PASSWORD

The start-dev command above runs over plaintext HTTP and is only for this one-time bootstrap on the VM itself. Do not use start-dev or expose its HTTP port for production admin logins; the systemd service below runs kc.sh start in production mode.

2. Configure Keycloak for Production

Create a configuration file:

nano /opt/keycloak/conf/keycloak.conf

Add the following configuration:

# Database configuration
# Generate your own DB password (e.g. `openssl rand -base64 24`) and do not reuse it.
db=postgres
db-url=jdbc:postgresql://localhost:5432/keycloak
db-username=keycloak
db-password=<CHANGE_ME>
 
# Network configuration
http-port=8080
https-port=8443
hostname=keycloak.your-domain.com

One thing trips people up here: there’s no production-mode toggle in keycloak.conf. You get production mode by launching with kc.sh start instead of start-dev, which is what the systemd unit below does. The hostname and HTTPS lines above are the actual production settings.

Keycloak ships with an embedded H2 database that’s fine for a quick look but not for anything real. For production, back it with PostgreSQL:

sudo apt install postgresql postgresql-contrib -y
sudo -u postgres psql

Then, inside the PostgreSQL shell, create the database and a user for it. Reuse the same password you put in db-password earlier (the one you generated, not the placeholder):

CREATE USER keycloak WITH PASSWORD '<CHANGE_ME>';
CREATE DATABASE keycloak OWNER keycloak;
GRANT ALL PRIVILEGES ON DATABASE keycloak TO keycloak;
\q

Start Keycloak Service

Running kc.sh by hand is fine for testing, but you want Keycloak to come back up after a reboot and restart if it crashes. A systemd unit handles both.

1. Create a Systemd Service

Create the unit file:

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

Paste in the following. It runs Keycloak in production mode (kc.sh start) as a dedicated user, with generous start and stop timeouts since the JVM can take a while:

[Unit]
Description=Keycloak Server
After=network.target
 
[Service]
Type=idle
User=keycloak
Group=keycloak
ExecStart=/opt/keycloak/bin/kc.sh start
TimeoutStartSec=600
TimeoutStopSec=600
 
[Install]
WantedBy=multi-user.target

2. Create Keycloak User

The unit runs as a keycloak system account rather than root or your login user, so create it and hand it ownership of the install directory:

sudo useradd -r -s /bin/false keycloak
sudo chown -R keycloak:keycloak /opt/keycloak

3. Enable and Start the Service

Reload systemd so it sees the new unit, enable it to start at boot, start it now, and check that it came up cleanly:

sudo systemctl daemon-reload
sudo systemctl enable keycloak
sudo systemctl start keycloak
sudo systemctl status keycloak

Configure Firewall

The admin console must not face the open internet. Lock the firewall down to a network you control, swapping 203.0.113.0/24 for your own admin CIDR:

# Replace 203.0.113.0/24 with the CIDR you administer Keycloak from
sudo ufw allow from 203.0.113.0/24 to any port 8443 proto tcp
sudo ufw reload

Open only the HTTPS port, 8443. Port 8080 is plaintext and only exists for the one-time bootstrap on the VM, so leave it closed to the outside. No fixed admin CIDR to point at? Skip the firewall rule entirely and tunnel in over SSH instead:

# From your workstation, forward local port 8443 to the VM over SSH
ssh -L 8443:localhost:8443 user@your-vm-ip

Access Keycloak Admin Console

Reach the console over HTTPS, never plain HTTP, since a plaintext login hands your admin credentials to anyone watching the wire. Point your browser at https://your-vm-ip:8443, or https://localhost:8443 if you went the SSH-tunnel route. Click “Administration Console” and sign in with the admin account you bootstrapped earlier. That drops you into the console where the rest of the configuration happens.

Basic IAM Configuration

The walkthrough below sets up a minimal but working configuration: a realm to isolate your app, a couple of users and roles, and a client for the app to authenticate against.

1. Create a New Realm

A realm is a self-contained space for your users, roles, and clients; the default “Master” realm is meant for managing Keycloak itself, so make a fresh one. Hover over “Master” at the top left, click “Add realm”, give it a name like “my-app”, and create it.

2. Create Users

Under “Users” in the left menu, click “Add user” and fill in the details. For example:

Save, then open the “Credentials” tab to set the user’s password.

3. Create Roles

Roles are how you group permissions. Open “Roles”, click “Add Role”, and name it something meaningful such as “admin”, “user”, or “readonly”. Save and repeat for each role you need.

4. Assign Roles to Users

Back under “Users”, pick a user and open the “Role mapping” tab. Choose the roles you want from “Available Roles” and add them.

5. Create a Client Application

A client is the application that delegates login to Keycloak. Go to “Clients”, click “Create”, and configure it:

Save it. Then set “Access Type” to “confidential” for a server-side app that can keep a secret, or “public” for a single-page or mobile app that can’t.

Next Steps

Keycloak is now running and holds your users, roles, and a client. From here you can wire real applications to it over OpenID Connect or SAML, add social login through providers like Google or GitHub, turn on multi-factor authentication, or federate against an existing LDAP or Active Directory directory.

The Keycloak documentation goes deep on all of these once you need them.