I’ve been wanting an “SSO lab” for experimenting with Single Sign-On (SAML and OIDC) setups. My solution is a Keycloak instance running on Fly.io. This post is a brief tutorial for self-hosting your own Keycloak instance.
It’s not exactly a production-ready deployment strategy, but it works well enough for experimentation. A Postgres database is used for data persistence.
Some advantages of Fly hosting:
- Use the standard Keycloak Docker image.
- Automatic Postgresql database provisioning.
- Automatic HTTPS with TLS termination.
- Easy custom domain setup — or you can use the automatically-assigned
- Both the application and the database can be configured for scale-to-zero.
Start by launching the app (substitute
my-keycloak with a unique app name):
APP_NAME="my-keycloak" flyctl launch \ --name "$APP_NAME" \ --image "quay.io/keycloak/keycloak:22.0.1" \ --env "KEYCLOAK_ADMIN=admin" \ --env "KC_HOSTNAME=$APP_NAME.fly.dev" \ --env "KC_PROXY=edge" \ --env "KC_DB=postgres" \ --env "KC_DB_URL_HOST=$APP_NAME-db.fly.dev" \ --env "KC_DB_URL_PORT=5432" \ --env "KC_DB_USERNAME=postgres" \ --no-deploy
Then, add a Postgres database:
flyctl postgres create
When prompted to pick a deployment option, choose “Development” for the lowest-cost option.
When asked, name the DB application
my-keycloak-db (again, substituting your unique app name for the
The output will include a database password. Save it somewhere safe, like a password manager.
Next, create a random password for logging into the Keycloak admin dashboard:
KEYCLOAK_ADMIN_PASSWORD="$(openssl rand -base64 32)" echo "Password: $KEYCLOAK_ADMIN_PASSWORD"
Put this in the password manager too.
Then push the secrets to Fly:
flyctl secrets set \ "KEYCLOAK_ADMIN_PASSWORD=$KEYCLOAK_ADMIN_PASSWORD" \ "KC_DB_PASSWORD=<DB Password>"
Then add this to the created
[experimental] cmd = ["start"]
The Keycloak Docker image is set up with a custom script
kc.sh as the
So, when the container starts, it’ll run something like:
Finally, Fly’s smallest instance size has 256 MB of memory; not quite enough to run Keycloak.
swap_size_mb = 512
swap_size_mb key doesn’t go into any subsection of the
fly.toml; it’s declared at the top, alonside
Before we can launch the app, we need to create a
keycloak database in the cluster.
First, SSH into your Postgres instance:
flyctl ssh console --app my-keycloak-db
Then launch psql (you’ll be prompted for the DB password you saved earlier):
psql -h localhost -p 5432 -U postgres
Then run this SQL statement:
CREATE DATABASE keycloak;
At this point, we’re ready to deploy the app — but first, let’s take a quick detour and set up a custom domain (e.g.
If you don’t want a custom domain, skip the following section.
Custom domain setup
Configure a CNAME record with value
my-keycloak.fly.dev in your DNS provider (again, replacing
my-keycloak with your unique app name).
flyctl certs create my-domain.example.com
Also, update the
KC_HOSTNAME variable in your
KC_HOSTNAME = "my-domain.example.com"
Okay; it’s deployment time. Run the following:
And make sure your scale is set correctly:
flyctl scale count 1
This is the maximum scale; if you have auto-scaling enabled, this doesn’t prevent scale-to-zero. But it will prevent scale-to-two.
Once deployed, you should be able to visit
https://my-domain.example.com — or, if you skipped the custom domain setup,
https://my-keycloak.fly.dev — and see a splash screen:
Try clicking the
Administration Console link.
If the admin login screen just spins without loading, check whether your
KC_HOSTNAME is correct. Also, use
flyctl logs to see if Keycloak is logging any error messages.
You should be able to login with credentials:
$KEYCLOAK_ADMIN_PASSWORD(from your password manager)
Once logged in, you’ll see a screen like this:
At this point, We’re done! 🎉
Keycloak instances take a few seconds to start, and admin dashboard sessions are lost when instances are scaled down.
Overall, scale-to-zero can be frustrating if you’re using the app heavily.
To temporarily prevent scale-to-zero, you can set the minimum machine count to 1 in the
http.service section of the
min_machines_running = 1
flyctl deploy to apply the change.
Note, the database will still scale to zero after an hour of inactivity; this doesn’t seem to be disruptive in my experience, so there’s no reason to disable it.
For starters, I’d recommend enabling MFA on your admin user.
Then, follow the steps of the Keycloak Docker quickstart guide, starting with the Create a Realm step. This will walk you through:
- Creating a new realm.
- Adding a user to the realm.
- Creating an OpenID Connect client.
If you have issues, check the logs for your application:
You can also check the application status:
And the status of your custom domain certs:
flyctl certs show my-domain.example.com