# Docker Compose Production Installation

> Source: https://docs.synthesized.io/tdk/latest/user_guide/050_deployment_operations/production_setup/dc
> For the complete documentation index, see [llms.txt](https://docs.synthesized.io/llms.txt).

> **WARNING**
> This installation requires a separately available PostgreSQL database and is intended for the production deployment of Governor. If you prefer an easier option to install Governor for evaluation and demonstration purposes, use the [demo setup](https://docs.synthesized.io/tdk/latest/user_guide/010_get_started/quickstart) instead.

## Prerequisites

1. [Docker](https://docs.docker.com/get-docker) must be available on the production server.
2. PostgreSQL server (version 13 or later) must be available in order to hold the Governor database. Empty database should be created prior to installation of Governor and login credentials for this database should be known.
3. Contact Sales to get access to the [governor-compose-prod.zip](https://www.synthesized.io/contact-sales). This file contains recommended setup for backend (JVM-based) and frontend (nginx-based) Docker containers.

## Setting up Docker Compose

### Setting up the access to the Governor database

Modify the following lines in the docker-compose file:

```
- SPRING_DATASOURCE_URL=jdbc:postgresql://host.docker.internal:5432/governor (1)
- SPRING_DATASOURCE_USERNAME=apiuser (2)
- SPRING_DATASOURCE_PASSWORD=apipassword (3)
```

1. Modify JDBC URL in order to point to your PostgreSQL database for Governor. If it is being run on the same host as Docker images for Governor, then `host.docker.internal` can be used as a host name.
2. Set the correct user name for Governor database
3. Set the correct password for Governor database

For RHEL with SELinux enabled runtime only

Allow the 389 (ldap) and 80 (frontend http) ports for usage in SELinux subsystem

```shell
sudo semanage port -a -t http_port_t -p tcp 80
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
```

### Configuring environment variables

**JWT\_SECRET**

Generate a JWT secret to serve as the signing key for authentication. Follow these steps based on your operating system:

- Mac/Linux
- Windows (Powershell)

```shell
openssl rand -base64 256 | tr -d '\n'
```

```powershell
[Convert]::ToBase64String((Get-Random -Count 256 -InputObject (0..255)))
```

After generating the key, replace `[your jwt secret]` in the `docker-compose.yml` file with the newly generated secret key.

**ADMIN\_EMAIL** and **ADMIN\_DEFAULT\_PASSWORD**

Generate admin password:

- Mac/Linux
- Windows (Powershell)

```shell
openssl rand -hex 20
```

```powershell
-join ((33..126) | Get-Random -Count 20 | ForEach-Object {[char]$_})
```

Replace `[your admin email]` and `[your default admin password]` in the `docker-compose.yml` with credentials for a seed admin user.

**CREDENTIALS\_ENCRYPTION\_KEY** (recommended)

Governor encrypts database connection passwords at rest using AES. By default, a well-known key is used. For production deployments, generate a custom 256-bit key:

- Mac/Linux
- Windows (Powershell)

```shell
openssl rand -base64 32
```

```powershell
[Convert]::ToBase64String((Get-Random -Count 32 -InputObject (0..255)))
```

Set the `CREDENTIALS_ENCRYPTION_KEY` environment variable in your `docker-compose.yml` to the generated value.

**Key rotation**

To rotate the encryption key, set the value to a semicolon-separated list where the first key is the new one and subsequent keys are historical:

```
CREDENTIALS_ENCRYPTION_KEY=<new-key>;<old-key>
```

On the next restart, Governor will re-encrypt all stored credentials with the new key. After restart completes, you can remove the old key from the list.

**SYNTHESIZED\_LICENSE**

Insert your Synthesized license key into the `docker-compose.yml` file by replacing \[your synthesized key\].

### (Optional) Setting up volumes for logs and DuckDB

In most scenarios, it makes sense to keep logs and DuckDB storage on the host’s filesystem, not the Docker’s internal filesystem.

In order to do so, uncomment the following lines in the docker-compose.yml:

```
    # volumes:
      # - [your path to storage]:/app/storage
      # - [your path to logs]:/app/logs
```

1. substitute `[your path to storage]` to the path where you would like to store DuckDB data
2. substitute `[your path to logs]` to the path where you would like to store application logs.

The required free disk space for partitions containing DuckDB and logs heavily depends on your usage scenarios, we recommend that at least 100Gb must be available for production usage.

## Running

Use the detached mode of docker compose to run the Governor containers in production:

```
docker compose up --detach
```

The Governor UI will be available at [http://localhost:80](http://localhost:80). Use the username and password specified as `ADMIN_EMAIL` and `ADMIN_DEFAULT_PASSWORD` to log in.

Use `docker compose ps` command in order to make sure that `backend` and `frontend` services are both running and in `healthy` state. The most common source of potential problems is connectivity to the database. Verify that database connection URL, username and password are correct, check backend logs (`docker compose logs backend`) for details if the problem persists.

## Setting up TLS termination

Governor requires `https://` protocol in order to run successfully from any address besides `localhost`. If you want to set up a domain name for Governor, you have to set up TLS termination as well.

The simplest way to do so is to install `nginx` and provide domain certificates.

- Setup [nginx](https://nginx.org/en/docs/install.html).
- Create a file named after your domain in `/etc/nginx/sites-available` with the following

```nginx
server {
    listen 443 ssl;
    server_name [domain name];

    ssl_certificate [path-to-your-certificate]/fullchain.pem;
    ssl_certificate_key [path-to-your-certificate]/privkey.pem;

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

- In this file
  
  - `[domain name]` is the domain name for your website, e.g. `governor.example.com`.
  - `[path-to-your-certificate]` is the folder where website certificates are stored.
- Create a symlink with nginx configuration from `/etc/nginx/sites-available` to `/etc/nginx/sites-enabled`
- Execute `nginx -s reload`.

You may also be interested in automatic creation and renewal of your domain certificates with [Certbot](https://certbot.eff.org/). In this case, refer to the relevant [documentation](https://www.nginx.com/blog/using-free-ssltls-certificates-from-lets-encrypt-with-nginx/).
