Keycloak Production Deployment (Apache reverse proxy, systemd, MariaDB)
0) Overview & Assumptions
- OS: Ubuntu/Debian–like (systemd available)
- Web: Apache (LAMPP is fine)
- DB: MariaDB/MySQL on the same host
- Public host:
auth.holidaylandmark.com
- Local Keycloak install dir:
/opt/auth.holidaylandmark.com
- Keycloak listens only on localhost:8080; Apache serves 80/443
- Your other PHP projects in
/opt/lampp/htdocs
remain unaffected
1) Install prerequisites (once)
sudo apt update
sudo apt install -y openjdk-21-jre-headless mariadb-server apache2
# Optional (if you’ll enable HTTPS now)
sudo apt install -y certbot python3-certbot-apache
Why: Java 21 is recommended; Apache fronts Keycloak; MariaDB stores realms/users.
2) Database: create schema & user (least privilege)
sudo mysql -e "CREATE DATABASE keycloak CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
sudo mysql -e "CREATE USER 'kc_user'@'localhost' IDENTIFIED BY 'REPLACE_Strong_DB_Password!';"
sudo mysql -e "GRANT ALL PRIVILEGES ON keycloak.* TO 'kc_user'@'localhost'; FLUSH PRIVILEGES;"
3) Install Keycloak under /opt (not under htdocs)
If you already extracted Keycloak and placed files under
/opt/auth.holidaylandmark.com
, skip to Step 4.
sudo mkdir -p /opt/auth.holidaylandmark.com
# Copy/unzip your Keycloak distribution into this folder so that:
# /opt/auth.holidaylandmark.com/bin/kc.sh exists
4) Create a dedicated service user and set ownership
id keycloak || sudo useradd --system --home /opt/auth.holidaylandmark.com --shell /usr/sbin/nologin --user-group keycloak
sudo chown -R keycloak:keycloak /opt/auth.holidaylandmark.com
sudo chmod +x /opt/auth.holidaylandmark.com/bin/kc.sh
Why: Run as non-root for security. The
keycloak
user will own only its folder.
5) Configure Keycloak (conf/keycloak.conf)
Create or edit /opt/auth.holidaylandmark.com/conf/keycloak.conf
:
# ---------- Database ----------
db=mariadb
db-url=jdbc:mariadb://127.0.0.1:3306/keycloak
db-username=kc_user
db-password=REPLACE_Strong_DB_Password!
db-pool-initial-size=5
db-pool-min-idle=5
db-pool-max-size=25
db-pool-prefill=true
# ---------- HTTP / Proxy ----------
http-enabled=true
http-port=8080
proxy=edge
proxy-headers=xforwarded
# ---------- Public Hostname ----------
hostname=auth.holidaylandmark.com
hostname-strict=true
hostname-strict-backchannel=true
# If you want Keycloak under a path instead of domain root:
# http-relative-path=/auth
# ---------- Cache/health/logging ----------
cache=local
health-enabled=true
metrics-enabled=true
log-level=INFO
hostname-debug=false
Why:
proxy=edge
because Apache terminates HTTP(S) and talks HTTP to Keycloak locally.
6) Bootstrap the temporary admin (first-time only)
sudo -u keycloak /opt/auth.holidaylandmark.com/bin/kc.sh bootstrap-admin user --username abhishek --password abhi
Tip: After the first login, create a permanent admin and disable/delete this bootstrap account.
7) Create the systemd service (auto-start on boot)
Create /etc/systemd/system/keycloak.service
exactly like your working version:
[Unit]
Description=Keycloak Server
After=network.target mariadb.service mysql.service
[Service]
Type=simple
User=keycloak
Group=keycloak
WorkingDirectory=/opt/auth.holidaylandmark.com
ExecStart=/opt/auth.holidaylandmark.com/bin/kc.sh start --optimized
ExecStop=/opt/auth.holidaylandmark.com/bin/kc.sh stop
Restart=on-failure
RestartSec=5
TimeoutSec=600
Environment="JAVA_OPTS=-Xms512m -Xmx2048m"
# (Optional hardening)
# NoNewPrivileges=true
# ProtectSystem=strict
# ProtectHome=true
# ReadWritePaths=/opt/auth.holidaylandmark.com
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable keycloak
sudo systemctl start keycloak
sudo systemctl status keycloak
Expect Active: active (running). If not, see Troubleshooting at the end.
8) Apache: reverse proxy the domain to localhost:8080
VirtualHost for HTTP (port 80):
<VirtualHost *:80>
ServerName auth.holidaylandmark.com
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "http"
RequestHeader set X-Forwarded-Host "auth.holidaylandmark.com"
RequestHeader set X-Forwarded-Port "80"
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
ProxyTimeout 120
</VirtualHost>
Enable modules/site & reload Apache:
sudo a2enmod proxy proxy_http headers
sudo a2ensite auth.holidaylandmark.com.conf # if you saved as such
sudo systemctl reload apache2 # LAMPP: /opt/lampp/lampp restartapache
Path-based option (to keep a PHP site at
/
and Keycloak under/auth
):
- In
keycloak.conf
:http-relative-path=/auth
- In Apache vhost:
ProxyPass /auth http://127.0.0.1:8080/auth
ProxyPassReverse /auth http://127.0.0.1:8080/auth
9) (Recommended) Enable HTTPS
sudo certbot --apache -d auth.holidaylandmark.com
Ensure the HTTPS vhost forwards correct headers:
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Host "auth.holidaylandmark.com"
RequestHeader set X-Forwarded-Port "443"
10) Verify end-to-end
Service running:
sudo systemctl status keycloak
Keycloak reachable locally:
curl -I http://127.0.0.1:8080/
Open in browser:
http://auth.holidaylandmark.com/admin/master/console/
# or https://... if you enabled TLS
Login with your temp admin:
Username: abhishek
Password: abhi
Create a permanent admin, then disable/delete the bootstrap user.
11) Backups, updates, and operations
Backups
- DB: nightly
mysqldump keycloak
(keep 7–14 days). - Config:
/opt/auth.holidaylandmark.com/conf/
,/etc/systemd/system/keycloak.service
, Apache vhost files.
Logs
- Keycloak:
journalctl -u keycloak -f
- Apache:
/var/log/apache2/access.log
,/var/log/apache2/error.log
Health endpoints (behind proxy): /health/live
, /health/ready
Upgrade Keycloak
sudo systemctl stop keycloak
- Back up
/opt/auth.holidaylandmark.com/
and DB - Extract new Keycloak to a staging folder, copy
conf/
over - Swap folders or update in place
sudo systemctl start keycloak
→ verify
12) Will this break my other LAMPP PHP sites?
No—as long as:
- Keycloak is proxied only on the
auth.holidaylandmark.com
vhost (or/auth
path) - You don’t put a global
ProxyPass / ...
inhttpd.conf
- Your PHP sites continue serving from
/opt/lampp/htdocs
via their own vhosts/DocumentRoots
Troubleshooting (quick reference)
Symptom | Likely Cause | Fix |
---|---|---|
Active: failed (status=217/USER) | keycloak user missing, wrong paths, or no execute bit | Create user, chown -R keycloak:keycloak /opt/auth.holidaylandmark.com , chmod +x bin/kc.sh , check unit paths, daemon-reload |
Apache 503 | Keycloak not running or wrong proxy | systemctl status keycloak ; curl -I 127.0.0.1:8080 ; verify vhost headers and ProxyPass |
Redirects show :8080 | Missing proxy headers or hostname mismatch | In keycloak.conf : hostname=auth.holidaylandmark.com , proxy=edge , proxy-headers=xforwarded ; Apache sends X-Forwarded-* |
“Local access required” banner | Admin not bootstrapped or accessed via non-localhost before first admin | Run kc.sh bootstrap-admin ... , restart; or access via SSH tunnel once |
Port 8080 in use | Another process bound | sudo lsof -i :8080 → kill process or change Keycloak port |
DB errors (e.g., unknown column) | Old/partial schema, insufficient privileges | Use a fresh keycloak DB; ensure user has full privileges; let Liquibase init |
Get detailed logs:
sudo journalctl -u keycloak -b --no-pager -n 200
(Optional) Minimal “golden” commands to re-create quickly
# Create user & own folder
id keycloak || sudo useradd --system --home /opt/auth.holidaylandmark.com --shell /usr/sbin/nologin --user-group keycloak
sudo chown -R keycloak:keycloak /opt/auth.holidaylandmark.com
sudo chmod +x /opt/auth.holidaylandmark.com/bin/kc.sh
# Bootstrap admin (first time only)
sudo -u keycloak /opt/auth.holidaylandmark.com/bin/kc.sh bootstrap-admin user --username abhishek --password abhi
# Install service
sudo systemctl daemon-reload
sudo systemctl enable keycloak
sudo systemctl start keycloak

I’m Abhishek, a DevOps, SRE, DevSecOps, and Cloud expert with a passion for sharing knowledge and real-world experiences. I’ve had the opportunity to work with Cotocus and continue to contribute to multiple platforms where I share insights across different domains:
-
DevOps School – Tech blogs and tutorials
-
Holiday Landmark – Travel stories and guides
-
Stocks Mantra – Stock market strategies and tips
-
My Medic Plus – Health and fitness guidance
-
TrueReviewNow – Honest product reviews
-
Wizbrand – SEO and digital tools for businesses
I’m also exploring the fascinating world of Quantum Computing.