
This article discusses how to achieve a complete identity and access management deployment on Ubuntu VPS.
Here’s a complete, start-to-finish procedural guide that integrates everything we’ve built — from deploying ApacheDS through LDAPS, SSSD logins, self-service portal, automation, Keycloak SSO, and unified observability with Grafana/Loki.
All redundant or superseded steps have been removed, and the flow has been consolidated into a single modern IAM deployment stack.
🌐 Complete Identity and Access Management Deployment on Ubuntu VPS
Apache Directory Server + Keycloak + SSPW + Grafana/Loki
To achieve complete identity and access management deployment on Ubuntu VPS, follow the steps below:
-
Base System Setup
sudo apt update && sudo apt upgrade -y sudo apt install wget curl unzip tar openjdk-17-jre-headless ufw ldap-utils -y
Requirements:
- Ubuntu 22.04 LTS VPS, 2 GB RAM min
- Static public hostname (FQDN)
- Ports open: 10389 (ldap), 10636 (ldaps), 8080/8443 (keycloak), 80/443 (https)
-
Install and Configure Apache Directory Server (ApacheDS)
cd /opt && wget https://archive.apache.org/dist/directory/apacheds/dist/2.0.0-M24/apacheds-2.0.0-M24-amd64.deb && chmod +x apacheds-2.0.0-M24-amd64.deb && sudo dpkg -i apacheds-2.0.0-M24-amd64.deb && sudo /etc/init.d/apacheds-2.0.0-M24-default start && sudo update-rc.d apacheds-2.0.0-M24-default defaults 2>/dev/null || sudo update-rc.d apacheds defaults
Verify:
sudo /etc/init.d/apacheds-2.0.0-M24-default status sudo ss -tulpn | grep java
Default DN →
uid=admin,ou=systemChange password via Apache Directory Studio immediately.
-
Secure LDAPS with Let’s Encrypt
sudo apt install certbot -y sudo certbot certonly --standalone -d ldap.example.com
Convert certificates into Java keystore:
DOMAIN="ldap.example.com" PASS="changeit" openssl pkcs12 -export \ -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem \ -inkey /etc/letsencrypt/live/$DOMAIN/privkey.pem \ -out /etc/letsencrypt/live/$DOMAIN/ldaps.p12 \ -name apacheds -password pass:$PASS keytool -importkeystore \ -deststorepass $PASS -destkeypass $PASS \ -destkeystore /etc/letsencrypt/live/$DOMAIN/ldaps.jks \ -srckeystore /etc/letsencrypt/live/$DOMAIN/ldaps.p12 \ -srcstoretype PKCS12 -srcstorepass $PASS -alias apacheds
Configure ApacheDS:
sudo tee -a /var/lib/apacheds-2.0.0-M24/default/conf/wrapper-instance.conf <<EOF apacheds.tls.keystore=/etc/letsencrypt/live/$DOMAIN/ldaps.jks apacheds.tls.keystore.password=$PASS EOF sudo /etc/init.d/apacheds-2.0.0-M24-default restart
Test:
ldapsearch -H ldaps://ldap.example.com:10636 -x -b "ou=system"
-
Integrate Linux Logins with LDAP (SSSD)
sudo apt install sssd sssd-ldap ldap-utils libpam-sss libnss-sss -y sudo nano /etc/sssd/sssd.conf
[sssd] services = nss, pam config_file_version = 2 domains = LDAP [domain/LDAP] id_provider = ldap auth_provider = ldap ldap_uri = ldaps://ldap.example.com:10636 ldap_search_base = dc=example,dc=com ldap_default_bind_dn = uid=admin,ou=system ldap_default_authtok = YOUR_ADMIN_PASSWORD ldap_tls_reqcert = demand ldap_tls_cacert = /etc/ssl/certs/ca-certificates.crt cache_credentials = True enumerate = False
sudo chmod 600 /etc/sssd/sssd.conf sudo systemctl enable --now sssd
Modify
/etc/nsswitch.conf:passwd: files systemd sss group: files systemd sss shadow: files sss
Enable PAM modules:
sudo pam-auth-update
SSH test with LDAP user.
-
Deploy Self-Service Password Portal (SSPW)
sudo apt install apache2 php php-ldap php-mbstring php-xml unzip -y cd /var/www/html sudo wget https://ltb-project.org/archives/self-service-password_1.7.3-1_all.deb sudo dpkg -i self-service-password_1.7.3-1_all.deb -d sspw sudo chown -R www-data:www-data sspw
Configure virtual host:
sudo tee /etc/apache2/sites-available/sspw.conf < ServerName ldap-portal.example.com DocumentRoot /var/www/html/sspw AllowOverride All Require all granted EOF sudo a2ensite sspw sudo a2enmod rewrite ssl sudo apt install certbot python3-certbot-apache -y sudo certbot --apache -d ldap-portal.example.com sudo systemctl reload apache2Edit
/var/www/html/sspw/conf/config.inc.php:$ldap_url = "ldaps://ldap.example.com"; $ldap_binddn = "uid=admin,ou=system"; $ldap_bindpw = "YOUR_ADMIN_PASSWORD"; $ldap_base = "dc=example,dc=com"; $use_tokens = true; $mail_attribute = "mail"; $mail_smtp_host = "smtp.example.com"; $mail_from = "no-reply@example.com";
Portal ready at
https://ldap-portal.example.com -
LDAP User + SSH Key Automation
Create
/usr/local/bin/create-ldap-user.sh:#!/bin/bash USER="$1"; UID="$2"; SSHKEY="$3" cat < /tmp/$USER.ldif dn: uid=$USER,ou=users,dc=example,dc=com objectClass: inetOrgPerson objectClass: posixAccount objectClass: ldapPublicKey cn: $USER sn: $USER uid: $USER uidNumber: $UID gidNumber: 1001 homeDirectory: /home/$USER loginShell: /bin/bash sshPublicKey: $SSHKEY LDIF ldapadd -x -H ldaps://ldap.example.com:10636 \ -D "uid=admin,ou=system" -w ADMIN_PASSWORD -f /tmp/$USER.ldif
sudo chmod +x /usr/local/bin/create-ldap-user.sh
SSH pulls keys via
sss_ssh_authorizedkeys:AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys AuthorizedKeysCommandUser root
Restart SSH.
-
Deploy Keycloak and Integrate with ApacheDS
cd /opt curl -O https://github.com/keycloak/keycloak/releases/download/24.0.4/keycloak-24.0.4.zip unzip keycloak-24.0.4.zip mv keycloak-24.0.4 keycloak sudo useradd -r -s /bin/false keycloak sudo chown -R keycloak:keycloak /opt/keycloak sudo -u keycloak /opt/keycloak/bin/kc.sh build
Run with HTTPS (use the same Let’s Encrypt keystore):
sudo -u keycloak /opt/keycloak/bin/kc.sh \ start --hostname keycloak.example.com \ --https-port 8443 \ --https-key-store-file /etc/letsencrypt/live/ldap.example.com/ldaps.jks \ --https-key-store-password changeit
Create admin:
/opt/keycloak/bin/kc.sh create admin --user admin --password StrongPass123!
Access
https://keycloak.example.com:8443/adminAdd LDAP Federation
User Federation → Add Provider → LDAP
Field Value Connection URL ldaps://ldap.example.com:10636Bind DN uid=admin,ou=systemUsers DN ou=users,dc=example,dc=comEdit Mode READ_ONLY Sync Registrations ON → Test Connection, then Sync All Users
-
Enable MFA & SSO Integration
In Keycloak:
Realm Settings → Authentication → Policies → OTP → Required
Integrate client apps (OIDC or SAML):
Nextcloud, GitLab, Jenkins, Grafana, Proxmox, etc.
-
Unified Observability & Audit Dashboard
Install Grafana + Loki + Promtail
sudo apt install adduser libfontconfig1 -y wget https://dl.grafana.com/oss/release/grafana_11.1.0_amd64.deb sudo dpkg -i grafana_11.1.0_amd64.deb sudo systemctl enable --now grafana-server
Deploy Loki and Promtail (collect Keycloak & ApacheDS logs) using configs from previous section.
Add Loki datasource in Grafana →
http://localhost:3100.Import Dashboard JSON
Import the JSON we generated earlier:
📄 “IAM Overview: Keycloak + ApacheDS (LogQL/Loki)”
Provides panels for:
- Login success/failure rates
- MFA prompts
- Admin events
- LDAP bind/add/modify/delete
- Top clients & IPs
- Recent logs feed
-
Lifecycle Automation CLI
Add quick management scripts:
iam-create-user.sh→ creates LDAP user + Keycloak roleiam-disable-user.sh→ disables login + terminates sessions
These can later power a FastAPI/OIDC-protected “IAM Portal”.
✅ Outcome
Capability Provided By Central directory & LDAPS ApacheDS Linux/SSH LDAP auth SSSD Self-service password reset SSPW Centralized SSO (OIDC/SAML) Keycloak MFA, role & realm mapping Keycloak Unified dashboards & alerts Grafana + Loki CLI / API lifecycle automation Scripts (Ansible-ready)
🚀 Maintenance
systemctl restart apacheds-defaultafter renew-hook converts certs- Regular
certbot renew pg_dumpfor Keycloak DB (if Postgres)- Backup
/etc/loki,/var/lib/loki,/opt/keycloak/conf - Alerting rules in Grafana for brute-force, admin spikes, expired certs
You now have a complete, production-ready IAM stack:
ApacheDS → LDAPS → Keycloak → SSPW → Grafana/Loki → Automation, secure, observable, and centrally managed.
Conclusion
You now know how to achieve a complete identity and access management deployment on Ubuntu VPS.









