# Required configuration

This page covers the options every deployment needs: the secret keys, the SQL database, Redis, and file storage. Feature options such as LLM providers, moderation, or hooks have their own pages, linked at the end.

CKEditor AI On-Premises reads every option from one of two sources:

* **Environment variables** – the default. The service reads each option from the environment variable that has the option name in upper case, for example `LICENSE_KEY` or `DATABASE_HOST`.
* **A JSON configuration file** – read when the `CS_CONFIG_PATH` environment variable points to a file. The file holds a flat JSON object whose keys are the option names, for example `{ "license_key": "...", "database_host": "..." }`.

> **Warning**
>
> The two sources are mutually exclusive. When you set `CS_CONFIG_PATH`, the service reads options only from the file and ignores the environment variables that hold options. There is no default file path. Without `CS_CONFIG_PATH`, the service reads environment variables.

To configure the service with a file, mount the file into the container and point `CS_CONFIG_PATH` at it:

```bash
docker run --init -p 8000:8000 \
	-v [PATH_TO_LOCAL_CONFIG_FILE]:/app/config.json \
	-e CS_CONFIG_PATH=/app/config.json \
	docker.cke-cs.com/ai-service:[version]
```

This page shows every option in both forms. The **JSON** tab shows the entry for the configuration file, and the **Environment variable** tab shows the same option as a variable. Option names are case-insensitive, so `license_key` and `LICENSE_KEY` name the same option.

> **Note**
>
> Telemetry variables prefixed with `OTEL_` and `LANGFUSE_` are an exception. The service reads them from the process environment when it starts. Pass them as environment variables even when the rest of the configuration is in a file. See [Observability](observability.md) for details.

<a id="secret-keys">

## Secret keys

The service needs a `license_key` option. The key confirms that you have the rights to run the service. To get a key, [contact us](https://ckeditor.com/contact/). The service does not start with an empty or invalid key.

The `environments_management_secret_key` option grants access to the [Cloud Services Management Panel](../cs-onpremises/management.md). Set it to a string from a password generator.

**JSON**

```json
{
	"license_key": "[LICENSE_KEY]",
	"environments_management_secret_key": "[ENVIRONMENTS_MANAGEMENT_SECRET_KEY]"
}
```

**Environment variable**

```bash
LICENSE_KEY=[LICENSE_KEY]
ENVIRONMENTS_MANAGEMENT_SECRET_KEY=[ENVIRONMENTS_MANAGEMENT_SECRET_KEY]
```

<a id="sql-database">

## SQL database

<a id="postgresql-database">

### PostgreSQL database

Set the `database_driver` option to `postgres`.

Then provide:

* `database_host` and `database_port` to set the database address.
* `database_user` and `database_password` to set the database credentials.
* `database_database` and `database_schema` to set the database and schema the service uses.

To encrypt the connection, set the `database_ssl_ca`, `database_ssl_key`, and `database_ssl_cert` options.

**JSON**

```json
{
	"database_driver": "postgres",
	"database_host": "[DATABASE_HOST]",
	"database_port": 5432,
	"database_user": "[DATABASE_USER]",
	"database_password": "[DATABASE_PASSWORD]",
	"database_database": "[DATABASE_NAME]",
	"database_schema": "[DATABASE_SCHEMA]"
}
```

**Environment variable**

```bash
DATABASE_DRIVER=postgres
DATABASE_HOST=[DATABASE_HOST]
DATABASE_PORT=5432
DATABASE_USER=[DATABASE_USER]
DATABASE_PASSWORD=[DATABASE_PASSWORD]
DATABASE_DATABASE=[DATABASE_NAME]
DATABASE_SCHEMA=[DATABASE_SCHEMA]
```

<a id="mysql-database">

### MySQL database

To use MySQL instead of PostgreSQL, set the `database_driver` option to `mysql`. The service uses MySQL when the option is not set.

Then provide:

* `database_host` and `database_port` to set the database address.
* `database_user` and `database_password` to set the database credentials.
* `database_database` to set the database the service uses.

To encrypt the connection, set the `database_ssl_ca`, `database_ssl_key`, and `database_ssl_cert` options.

**JSON**

```json
{
	"database_driver": "mysql",
	"database_host": "[DATABASE_HOST]",
	"database_port": 3306,
	"database_user": "[DATABASE_USER]",
	"database_password": "[DATABASE_PASSWORD]",
	"database_database": "[DATABASE_NAME]"
}
```

**Environment variable**

```bash
DATABASE_DRIVER=mysql
DATABASE_HOST=[DATABASE_HOST]
DATABASE_PORT=3306
DATABASE_USER=[DATABASE_USER]
DATABASE_PASSWORD=[DATABASE_PASSWORD]
DATABASE_DATABASE=[DATABASE_NAME]
```

<a id="redis-database">

## Redis database

The service needs Redis in addition to the SQL database. Configure it with:

* `redis_host` and `redis_port` to set the Redis address.
* `redis_user` and `redis_password` to set the Redis credentials. Both are optional.

Set `redis_db` to use a database number other than the default `1`.

If the Redis address is an IPv6 address or an IPv6 domain name, set `redis_ip_family` to `6`. The service uses IPv4 by default.

To encrypt the connection, set the `redis_tls_ca`, `redis_tls_key`, and `redis_tls_cert` options. If you do not have a custom certificate, set `redis_tls_enable` to `true` instead.

**JSON**

```json
{
	"redis_host": "[REDIS_HOST]",
	"redis_port": 6379,
	"redis_user": "[REDIS_USER]",
	"redis_password": "[REDIS_PASSWORD]",
	"redis_db": 1
}
```

**Environment variable**

```bash
REDIS_HOST=[REDIS_HOST]
REDIS_PORT=6379
REDIS_USER=[REDIS_USER]
REDIS_PASSWORD=[REDIS_PASSWORD]
REDIS_DB=1
```

<a id="connecting-to-redis-cluster">

## Connecting to Redis Cluster

To connect to a Redis Cluster, set:

* `redis_cluster_nodes` – required for a Redis Cluster connection.
* `redis_ip_family` – optional. Set it to `6` when `redis_cluster_nodes` holds IPv6 addresses or IPv6 domain names.

The value is a comma-separated list of nodes in this format:

```bash
"IP:PORT:[optional PASSWORD],IP:PORT:[optional PASSWORD]"
```

For example:

```bash
# IPv6
[0:0:0:0:0:0:0:1]:7000,[0:0:0:0:0:0:0:1]:7001,[0:0:0:0:0:0:0:1]:7002

# IPv6 with a password
[0:0:0:0:0:0:0:1]:7000:password1,[0:0:0:0:0:0:0:1]:7001:password2,[0:0:0:0:0:0:0:1]:7002:password3

# Domain name
example.redis.server.com:7000,example.redis.server.com:7001,example.redis.server.com:7002

# Domain name with a password
example.redis.server.com:7000:password1,example.redis.server.com:7001:password2,example.redis.server.com:7002:password3
```

The example below shows a cluster of domain-name nodes with IPv6 support enabled:

**JSON**

```json
{
	"redis_cluster_nodes": "example.ipv6.redis.server.com:7000,example.ipv6.redis.server.com:7001,example.ipv6.redis.server.com:7002",
	"redis_ip_family": 6
}
```

**Environment variable**

```bash
REDIS_CLUSTER_NODES="example.ipv6.redis.server.com:7000,example.ipv6.redis.server.com:7001,example.ipv6.redis.server.com:7002"
REDIS_IP_FAMILY=6
```

<a id="storage">

## Storage

<a id="s3-storage">

### S3 storage

To store files in S3, set the `storage_driver` option to `s3`.

Then provide:

* `storage_access_key_id` and `storage_secret_access_key` to authorize the service.
* `storage_bucket` to set the bucket the service writes the files to.

For an S3-compatible server, set its address with the `storage_endpoint` option.

**JSON**

```json
{
	"storage_driver": "s3",
	"storage_region": "[AWS_REGION]",
	"storage_access_key_id": "[AWS_ACCESS_KEY_ID]",
	"storage_secret_access_key": "[AWS_SECRET_ACCESS_KEY]",
	"storage_bucket": "[AWS_S3_BUCKET]",
	"storage_endpoint": "[AWS_S3_ENDPOINT]"
}
```

**Environment variable**

```bash
STORAGE_DRIVER=s3
STORAGE_REGION=[AWS_REGION]
STORAGE_ACCESS_KEY_ID=[AWS_ACCESS_KEY_ID]
STORAGE_SECRET_ACCESS_KEY=[AWS_SECRET_ACCESS_KEY]
STORAGE_BUCKET=[AWS_S3_BUCKET]
STORAGE_ENDPOINT=[AWS_S3_ENDPOINT]
```

<a id="azure-blob-storage">

### Azure Blob Storage

To store files in Azure Blob Storage, set the `storage_driver` option to `azure`.

Then provide:

* `storage_account_name` and `storage_account_key` to authorize the service.
* `storage_container` to set the container the service writes the files to.

By default, the service builds the endpoint from the account name: `https://[AZURE_ACCOUNT_NAME].blob.core.windows.net`. To use another address, set the `storage_endpoint` option.

**JSON**

```json
{
	"storage_driver": "azure",
	"storage_account_name": "[AZURE_ACCOUNT_NAME]",
	"storage_account_key": "[AZURE_ACCOUNT_KEY]",
	"storage_container": "[AZURE_CONTAINER]",
	"storage_endpoint": "[AZURE_ENDPOINT]"
}
```

**Environment variable**

```bash
STORAGE_DRIVER=azure
STORAGE_ACCOUNT_NAME=[AZURE_ACCOUNT_NAME]
STORAGE_ACCOUNT_KEY=[AZURE_ACCOUNT_KEY]
STORAGE_CONTAINER=[AZURE_CONTAINER]
STORAGE_ENDPOINT=[AZURE_ENDPOINT]
```

<a id="filesystem">

### Filesystem

To store files on a local filesystem, set the `storage_driver` option to `filesystem`.

Then set the path to the directory for the files with the `storage_location` option.

**JSON**

```json
{
	"storage_driver": "filesystem",
	"storage_location": "/var/storage/location"
}
```

**Environment variable**

```bash
STORAGE_DRIVER=filesystem
STORAGE_LOCATION=/var/storage/location
```

<a id="sql-storage">

### SQL storage

To store files in PostgreSQL or MySQL, set the `storage_driver` option to `database`. The service then uses the connection that the `database_*` options define.

**JSON**

```json
{
	"storage_driver": "database"
}
```

**Environment variable**

```bash
STORAGE_DRIVER=database
```

<a id="llm-providers">

## LLM providers

See [LLM providers](llm-providers.md) for the `providers` and `models` options.

<a id="opentelemetry">

## OpenTelemetry

See [Observability](observability.md) for the telemetry options.

<a id="content-moderation">

## Content moderation

See [Moderation](moderation.md) for the `moderation` option.

<a id="web-resources">

## Web resources

See [Web resources](web-resources.md) for the `webresources_*` options.

<a id="web-search">

## Web search

See [Web search](web-search.md) for the `websearch_*` options.

---

Full index of the Cloud Services documentation: [llms.txt](../../../llms.txt)
