This post will cover the detailed step by step process to deploy Keycloak in a production environment using AWS EC2 Server. We will use Docker containers and Maria DB as the database. For securing the portal, we will use NGINX and certbot to generate Letsencrypt certificate.
The steps can be broken down as following:
- Create a domain/subdomain to be used for Keycloak
- Create the EC2 Server in AWS with the correct inbound rule set
- Install NGINX and Certbot and configure it for Keycloak domain
- Install Docker and configure it to run without “sudo”
- Create docker-compose.yml file
- Bring up the container and validate everything
1. Create a Domain or Subdomain to be used for Keycloak
I have created an Elastic IP in AWS to be used for Keycloak. We are using a subdomain for an existing domain by creating an “A” record. Please refer to the following image for reference.
2. Create the EC2 Server in AWS Console
Login to your AWS account and create an Amazon EC2 Server. Please make sure to size it based on the expected load. The recommended minimum hardware is 2 core CPU & 4 GB RAM which we will use for this deployment.
Please make sure to allow inbound TCP ports 22, 443 and 8081 that we will be using in this deployment. Next map the Elastic ip address to the newly created Keycloak Server. Once the server is up, perform the package upgrade using following command
sudo apt update && sudo apt upgrade
sudo apt update && sudo apt upgrade
Go ahead and reboot the server as required.
3. Install NGINX and configure it for Keycloak domain
Now we will install the NGINX
$ sudo apt install nginx
Type Y when prompted. Once the installation is completed, validate the NGINX Version using following command
$ nginx -v
nginx version: nginx/1.18.0 (ubuntu)
$ sudo systemctl status nginx
Last command should give you output like the following, which confirms that our NGINX is up and running
Next we will enable and configure the UFW to allow NGINX and ssh for remote connectivity.
$ sudo ufw status
Status: inactive
$ sudo ufw allow "Nginx Full"
Rules updated
Rules updated (v6)
$ sudo ufw allow ssh
Rules updated
Rules updated (v6)
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
$ sudo ufw reload
Firewall reloaded
$ sudo ufw status
Status: active
To Action From
-- ------ ----
Nginx Full ALLOW Anywhere
22/tcp ALLOW Anywhere
Nginx Full (v6) ALLOW Anywhere (v6)
22/tcp (v6) ALLOW Anywhere (v6)
Next we will install certbot for Letsencrypt certificate creation and automated renewal
$ sudo apt install certbot python3-certbot-nginx
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
python3-acme python3-certbot python3-configargparse python3-icu python3-josepy
python3-parsedatetime python3-requests-toolbelt python3-rfc3339
python3-zope.component python3-zope.event python3-zope.hookable
Suggested packages:
python-certbot-doc python3-certbot-apache python-acme-doc
python-certbot-nginx-doc
The following NEW packages will be installed:
certbot python3-acme python3-certbot python3-certbot-nginx
python3-configargparse python3-icu python3-josepy python3-parsedatetime
python3-requests-toolbelt python3-rfc3339 python3-zope.component
python3-zope.event python3-zope.hookable
0 upgraded, 13 newly installed, 0 to remove and 0 not upgraded.
Need to get 993 kB of archives.
After this operation, 5077 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Click on Y to continue. Once the installation is successfully completed, next step will be to create out certificate. Run the following commands and provide all the required information.
$ sudo certbot --nginx -d keycloak.securityfocal.com -d www.keycloak.securityfocal.com
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
(Y)es/(N)o: Y
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
(Y)es/(N)o: Y
Account registered.
Requesting a certificate for keycloak.securityfocal.com and www.keycloak.securityfocal.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/keycloak.securityfocal.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/keycloak.securityfocal.com/privkey.pem
This certificate expires on 2025-02-28.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.
Deploying certificate
Successfully deployed certificate for keycloak.securityfocal.com to /etc/nginx/sites-enabled/default
Successfully deployed certificate for www.keycloak.securityfocal.com to /etc/nginx/sites-enabled/default
Congratulations! You have successfully enabled HTTPS on https://keycloak.securityfocal.com
and https://www.keycloak.securityfocal.com
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
sudo certbot renew --dry-run
Next we will do a dry run to validate if auto renewal is working as expected
$ sudo certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Account registered.
Simulating renewal of an existing certificate for keycloak.securityfocal.com and www.keycloak.securityfocal.com
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/keycloak.securityfocal.com/fullchain.pem (success)
Next we will configure NGINX for our deployment.
$ sudo unlink /etc/nginx/sites-enabled/default
$ cd /etc/nginx/sites-available/
$ sudo vi keycloak.securityfocal.conf
We will use following configuration for our Keycloak Deployment. Please make sure to change the configuration parameters as per your environment.
server {
listen 80;
server_name keycloak.securityfocal.com www.keycloak.securityfocal.com;
rewrite ^https://keycloak.securityfocal.com permanent;
}
server {
listen 443 ssl;
server_name keycloak.securityfocal.com www.keycloak.securityfocal.com;
ssl_certificate /etc/letsencrypt/live/keycloak.securityfocal.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/keycloak.securityfocal.com/privkey.pem;
ssl_session_cache builtin:1000 shared:ssl:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://65.0.171.3:8081;
}
}
Save and close the file (:wq). Complete the NGINX configuration
$ sudo ln -s /etc/nginx/sites-available/keycloak.securityfocal.conf /etc/nginx/sites-enabled/keycloak.securityfocal.conf
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo systemctl restart nginx
Next we will install Docker and Docker compose. So to do that we will set up Docker’s apt
repository.
# Add Docker's official GPG key:
sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
4. Install Docker and configure it to run without “sudo”
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify that the installation is successful by running the hello-world
image:
$ sudo docker run hello-world
This command downloads a test image and runs it in a container. When the container runs, it prints a confirmation message and exits.
To run Docker without root privileges, use the following commands
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
Log out and log back in so that your group membership is re-evaluated.
5. Create docker-compose.yml file
We now need to create our docker-compose file. You may use the following code for that, please make sure to change the key parameters:
$ sudo vi docker-compose.yml
services:
mariadb:
image: mariadb:latest
environment:
MARIADB_ROOT_PASSWORD: toor
MARIADB_DATABASE: keycloak
MARIADB_USER: keycloak
MARIADB_PASSWORD: keycloak
mem_limit: 300m
container_name: mariadb
restart: always
volumes:
- mariadb_data:/var/lib/mysql
networks:
- keycloak-auth
keycloak:
image: quay.io/keycloak/keycloak:latest
environment:
KC_DB: mariadb
KC_DB_SCHEMA: keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
KC_DB_URL_HOST: mariadb
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_PROXY_HEADERS: xforwarded
KC_HTTP_ENABLED: true
KC_HOSTNAME_STRICT: false
KC_HOSTNAME_URL: https://mydomain
mem_limit: 500m
ports:
- 8443:8443
- 8081:8080
container_name: keycloak
restart: always
networks:
- keycloak-auth
depends_on:
- mariadb
command: start
volumes:
mariadb_data:
driver: local
networks:
keycloak-auth:
driver: bridge
You can use following github repository also for reference: docker-compose.yml .
6. Bring up the container and validate everything
$ docker-compose up
If you have followed all the steps correctly, the Keycloak Server should come up
That’s it our server is ready. Use the admin credentials to login.