Deploying Keycloak to a VPS Using Docker-compose, Nginx, Certbot, and SSL
Tags: keycloak, vps, ssl, certbot
Published: 2024-07-06 12:21:23

In this article, I would like to share how to deploy Keycloak to a VPS using Docker-compose, Nginx, Certbot, and SSL.

## Key points:
- Keycloak v.25.0.1
- SSL protection for Keycloak
- Certbot v.2.11.0 for obtaining and renewing SSL certificates
- Nginx v.1.27.0 as a reverse proxy
- Postgres v.14 to replace the default internal H2 DB of Keycloak
- Automatic realm import during deployment
- Docker-compose for deployment automation
- .env file for managing environment variables

For those who might not be familiar, Keycloak is a powerful access management system with SSO support that can significantly simplify user management and authentication.

The desire to deploy your own Keycloak can arise both for experimenting with your projects and for handling your usual backend tasks. This happened to me as well. I decided to kill two birds with one stone. However, I couldn't find a comprehensive guide. I don't need Keycloak locally, but setting it up on a separate, always-available server with backup and the ability to export/import realms, etc., is excellent. Plus, the deployment process is automated, making it easier to switch to another VPS provider.

Everyone has their own motivation, but let's get to the point.

## Introduction

#### What is Keycloak?
Keycloak is an open-source identity and access management solution. It provides features such as SSO (Single Sign-On), user management, authentication, and authorization.

#### Why Docker-compose?
Docker-compose makes it easy to manage multi-component applications like Keycloak and simplifies the deployment and scaling process. This guide uses containers for Keycloak, Certbot, Nginx, and the Postgres database.

#### Why Nginx and Certbot?
Nginx will act as a reverse proxy, ensuring security and performance, while Certbot will help obtain and automatically renew SSL certificates from Let's Encrypt, saving us a couple of thousand rubles on certificates for our domain, which is nice.

Let's get started!

## Step 1: Preparing the Environment

#### Cloning the Repository

First, clone the repository with ready-made configurations to our VPS, which I have carefully prepared for you. It contains docker-compose.yml for managing deployment, nginx configs, and an environment variables file needed for docker-compose.

```
git clone git@github.com:s-rb/keycloak-dockerized-ssl-nginx.git
cd keycloak-dockerized-ssl-nginx
```

#### Editing the .env File
Open the .env file and edit the following variables:

- `KEYCLOAK_ADMIN_PASSWORD` - Admin password for accessing Keycloak
- `KC_DB_PASSWORD` - Password for Keycloak service access to the Postgres DB (should match `POSTGRES_PASSWORD` if a separate user is not created)
- `POSTGRES_PASSWORD` - Admin password for Postgres

Replace `password` with your values unless you want anyone to connect to your services ;)

Example of a complete environment variables file:
```
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=password
PROXY_ADDRESS_FORWARDING=true
KC_PROXY=edge
KC_DB=postgres
KC_DB_URL=jdbc:postgresql://keycloak-postgres:5432/keycloak
KC_DB_USERNAME=keycloak
KC_DB_PASSWORD=password
POSTGRES_DB=keycloak
POSTGRES_USER=keycloak
POSTGRES_PASSWORD=password
```

## Step 2: Domain Registration and DNS Setup
This step can be done before the first step - it does not depend on it. In the following instructions, we assume you have registered your domain (e.g., surkoff.com) and we want Keycloak to be accessible at my-keycloak.surkoff.com.

#### Domain Registration
Register a domain with any registrar, for example, REG.RU.

#### Creating an `A` Record for the Subdomain
Create an `A` record pointing to your server's IP. For example, for the subdomain my-keycloak.surkoff.com, specify your server's IP.

![Creating subdomain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1lyc4qyari5zoxfdqac.png)

#### Checking the DNS Record
Ensure the DNS record is correctly configured:

```
ping my-keycloak.surkoff.com
```

The response should show your server's IP address.

## Step 3: Configuring Nginx
#### Nginx Configuration
In the nginx configs - `default.conf_with_ssl`, `default.conf_without_ssl` edit and specify your domain:

- `server_name` section
- path to the certificate `ssl_certificate`
- path to the key `ssl_certificate_key`

Example configuration with SSL:
```
server {
    listen 443 ssl;
    server_name my-keycloak.surkoff.com;

    ssl_certificate /etc/letsencrypt/live/my-keycloak.surkoff.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my-keycloak.surkoff.com/privkey.pem;

    location / {
        proxy_pass http://keycloak:8080;
        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;
    }
}
```

## Step 4: Obtaining an SSL Certificate
#### Obtaining a Test Certificate
Use the configuration without SSL:
```
cp nginx/conf.d/default.conf_without_ssl nginx/conf.d/default.conf
docker-compose up -d
```

Obtain a test certificate (replace the domain and email with your own):
```
docker exec certbot certbot certonly --webroot --webroot-path=/data/letsencrypt -d my-keycloak.surkoff.com --email your_email@gmail.com --agree-tos --no-eff-email --staging
```

![Obtain test SSL certificate](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/si62vmnbk48zdryoy3d8.png)

#### Checking the Certificate
```
docker exec certbot certbot certificates
```

![Check if certificate exists](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nv3692ihg02bqz9c9ihi.png)

#### Deleting the Test Certificate (replace the domain with your own)
```
docker exec certbot certbot delete --cert-name my-keycloak.surkoff.com
```

#### Obtaining a Real Certificate (replace email and domain with your own)
```
docker exec certbot certbot certonly --webroot --webroot-path=/data/letsencrypt -d my-keycloak.surkoff.com --email your_email@gmail.com --agree-tos --no-eff-email
```

## Step 5: Final Configuration and Launch
#### Updating Nginx Configuration to Use SSL
```
docker-compose down
cp nginx/conf.d/default.conf_with_ssl nginx/conf.d/default.conf
docker-compose up -d
```

#### Checking Access to Keycloak
Open a browser and go to my-keycloak.surkoff.com (your domain).

You should see the admin login page where you can log in using the username and password you specified in the .env file.


![Keycloak admin page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cg2twvbvn7kr3z1hxcot.png)

For configuring Keycloak, there are interesting articles on other resources, which we won't cover in this publication.

## Automatic Certificate Renewal
To automatically renew certificates and restart Nginx, create the `renew_and_reload.sh` script (already available in the repository):
```
#!/bin/bash
# Renew certificates
docker exec certbot certbot renew --webroot --webroot-path=/data/letsencrypt

# Restart Nginx
docker restart nginx
```

Make the script executable:
```
chmod +x renew_and_reload.sh
```

Add it to crontab for regular execution:
```
crontab -e
```

Add a line to crontab, remembering to specify the path to the script:
```
0 0 1 * * /path/to/renew_and_reload.sh
```

## Importing Realms
If you want to import a realm at startup, you can place it in the `keycloak/config/` folder, and it will be imported when the application starts.

### Conclusion
That's it! Now you have a deployed latest Keycloak with SSL on your VPS. I hope this article was helpful! If you have any questions or suggestions, feel free to write to me.

The source code is available at [the link here](https://github.com/s-rb/keycloak-dockerized-ssl-nginx)