---
title: "Environment Variables"
description: "Configure Koios behavior using environment variables — network, performance, logging, authentication, and reverse proxy settings"
source_url: https://ai-ops.com/docs/installation/environment-variables
---

# Environment Variables

Koios is configured through environment variables passed to the Docker container. Most deployments work with the defaults, but you can customize network ports, performance tuning, logging, authentication, and reverse proxy settings.

## Setting Environment Variables

Add `-e` flags to the `docker run` command in your systemd service file:

```ini
ExecStart=/usr/bin/docker run --rm --name=%n --network host \
  -e ENABLE_TLS=true \
  -e HTTPS_PORT=8443 \
  -e LOG_STDOUT_ENABLED=true \
  --mount source=koios_data_postgres,target=/var/lib/postgresql/16/main \
  --mount source=koios_data_influxdb,target=/root/.influxdbv2 \
  --mount source=koios_media,target=/var/www/koios/media \
  --mount source=koios_logs,target=/var/www/koios/logs \
  --mount source=koios_certs,target=/var/www/koios/certs \
  --mount source=koios_license,target=/var/www/koios/license \
  --mount source=koios_secrets,target=/var/www/koios/secrets \
  aiopinc/koios:latest
```

After editing the service file, reload and restart:

```bash
sudo systemctl daemon-reload
sudo systemctl restart docker.koios.service
```

---

## Network & TLS

Control how Koios handles HTTPS, HTTP, and port assignments.

| Variable | Default | Description |
|----------|---------|-------------|
| `ENABLE_TLS` | `true` | When `true`, Koios serves HTTPS with a self-signed certificate and redirects HTTP to HTTPS. Set to `false` when running behind a load balancer or reverse proxy that handles TLS termination. |
| `HTTPS_PORT` | `443` | The port for HTTPS traffic. Only used when `ENABLE_TLS=true`. |
| `HTTP_PORT` | `80` | The port for HTTP traffic. In TLS mode, this port redirects to HTTPS. In no-TLS mode, this is the primary listening port. |

### Common Scenarios

**Standard deployment (default):**
No variables needed — Koios listens on ports 443 (HTTPS) and 80 (HTTP redirect).

**Custom ports:**

```ini
-e HTTPS_PORT=8443 \
-e HTTP_PORT=8080 \
```

**Behind a TLS-terminating proxy (e.g., NGINX, HAProxy, AWS ALB):**

```ini
-e ENABLE_TLS=false \
-e HTTP_PORT=8080 \
```

Koios serves plain HTTP on port 8080. The proxy handles HTTPS and forwards traffic to this port.

> [!WARNING] Port mapping with host networking
> When using `--network host`, the container binds directly to the host's ports. Make sure your chosen ports are not already in use. If using explicit port mapping instead (e.g., `-p 8443:443`), the port variables control the ports *inside* the container.

---

## Performance Tuning

Adjust worker threads and timeouts for your deployment size.

| Variable | Default | Description |
|----------|---------|-------------|
| `UVICORN_WORKERS` | CPU count (max 4) | Number of web server worker processes. Increase for deployments with many concurrent API clients. |
| `GRAPHQL_REQUEST_TIMEOUT` | `30` | Maximum time (in seconds) for a single API request to complete. Increase if large queries (e.g., bulk exports) are timing out. |
| `DC_THREAD_POOL_SIZE` | `8` | Number of worker threads for device polling. Increase for deployments with many devices to improve polling concurrency. |
| `PE_THREAD_POOL_SIZE` | `8` | Number of worker threads for AI model inference. Increase for deployments running many models concurrently. |
| `PE_GROUP_THREAD_POOL_SIZE` | `32` | Maximum threads for parallel model inference within a scan group. When a scan group fires, all its models can run concurrently up to this limit. |
| `EE_THREAD_POOL_SIZE` | `8` | Number of worker threads for expression evaluation. Increase for deployments with many calculated tags (expressions). |
| `EE_IN_MEMORY_HEARTBEAT_INTERVAL` | `60` | Safety-net poll interval (in seconds) for in-memory tag sources feeding expression tags and AI models. The Expression Evaluator now reacts to live in-memory updates via push events; this heartbeat is purely a fallback to detect a stale producer. Lower it only if you suspect a producer is silently failing to publish. The legacy `EE_IN_MEMORY_SCAN_RATE` variable is still honored for backward compatibility. |

> [!TIP] When to increase thread pools
> The default thread pool sizes work well for most deployments (up to ~50 devices, ~50 models, or ~50 expressions). If you have significantly more, increase the corresponding pool size. Monitor CPU usage on the System Health page — if the server has spare capacity but polling, inference, or expression evaluation feels slow, increasing the pool may help.

---

## Authentication

Control JWT token lifetimes for user sessions.

| Variable | Default | Description |
|----------|---------|-------------|
| `KOIOS_ACCESS_TOKEN_LIFETIME_SECONDS` | `3600` | How long an access token remains valid (in seconds). Default is 1 hour. Shorter values improve security; longer values reduce re-authentication frequency. |
| `KOIOS_REFRESH_TOKEN_LIFETIME_DAYS` | `7` | How long a refresh token remains valid (in days). This determines the maximum session duration before a user must log in again. |

---

## Logging

Control log output destination, format, and verbosity.

| Variable | Default | Description |
|----------|---------|-------------|
| `LOG_STDOUT_ENABLED` | `false` | When `true`, streams all service logs to container stdout, making them visible via `docker logs`. When `false`, logs are written to files inside the container's log volume and viewable from the in-app log viewer. |
| `KOIOS_DEFAULT_LOG_LEVEL` | `INFO` | Log verbosity for all Koios services. Options: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`. |

> [!NOTE] In-app log viewer
> Regardless of these settings, service logs are always available in the in-app log viewer at **System > Logs**. The `LOG_STDOUT_ENABLED` variable controls whether logs are *also* sent to container stdout.

---

## Log Forwarding (OpenTelemetry)

Forward logs from Koios to an external observability platform using the built-in OpenTelemetry Collector.

| Variable | Default | Description |
|----------|---------|-------------|
| `OTEL_COLLECTOR_ENABLED` | `false` | When `true`, starts the OpenTelemetry Collector inside the container. |
| `OTEL_REMOTE_ENDPOINT` | *(none)* | The remote OTLP HTTP endpoint URL (e.g., `https://your-collector:4318`). Required when the collector is enabled. |
| `OTEL_REMOTE_AUTH_TOKEN` | *(none)* | Bearer token for authenticating to the remote endpoint. |

### Example: Forwarding to Grafana Cloud

```ini
-e OTEL_COLLECTOR_ENABLED=true \
-e OTEL_REMOTE_ENDPOINT=https://otlp-gateway-prod-us-east-0.grafana.net/otlp \
-e OTEL_REMOTE_AUTH_TOKEN=your-grafana-cloud-token \
```

---

## OPC-UA Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `OPCUA_CERT_HOSTNAME` | System hostname | The hostname embedded in the OPC-UA client's application URI and used when generating client certificates. Override this if the system hostname doesn't match what your OPC-UA servers expect for certificate validation. |

---

## Reverse Proxy Settings

> [!NOTE] Advanced configuration
> These settings are only needed when Koios is deployed behind a reverse proxy (NGINX, Apache, HAProxy, AWS ALB, etc.) that handles TLS termination. For standalone deployments with `ENABLE_TLS=true`, the defaults work correctly.

When running behind a reverse proxy, you may need to configure CSRF protection and cookie settings so that the proxy's domain and protocol are trusted.

### CSRF Protection

| Variable | Default | Description |
|----------|---------|-------------|
| `DJANGO_CSRF_TRUSTED_ORIGINS` | *(empty)* | Comma-separated list of trusted origins. **Must be set** when behind a proxy to match the browser's Origin header. Example: `https://koios.example.com,https://other.example.com` |
| `DJANGO_CSRF_COOKIE_SECURE` | `True` | Set to `False` if serving over plain HTTP (e.g., behind a proxy on a private network). |
| `DJANGO_CSRF_COOKIE_HTTPONLY` | `False` | Set to `True` to prevent JavaScript from reading the CSRF cookie. |
| `DJANGO_CSRF_COOKIE_DOMAIN` | *(current domain)* | Set to `.example.com` for cross-subdomain CSRF cookie sharing. |
| `DJANGO_CSRF_COOKIE_PATH` | `/` | URL path for the CSRF cookie. |
| `DJANGO_CSRF_COOKIE_SAMESITE` | *(browser default)* | SameSite attribute: `Lax`, `Strict`, or `None`. |

### Session Cookies

| Variable | Default | Description |
|----------|---------|-------------|
| `DJANGO_SESSION_COOKIE_SECURE` | `True` | Set to `False` if serving over plain HTTP. |
| `DJANGO_SESSION_COOKIE_DOMAIN` | *(current domain)* | Domain for the session cookie. |
| `DJANGO_SESSION_COOKIE_PATH` | `/` | URL path for the session cookie. |
| `DJANGO_SESSION_COOKIE_SAMESITE` | `Lax` | SameSite attribute for the session cookie. |

### Proxy Headers

| Variable | Default | Description |
|----------|---------|-------------|
| `DJANGO_USE_X_FORWARDED_HOST` | `True` | Use the `X-Forwarded-Host` header from the proxy to determine the request host. |
| `DJANGO_USE_X_FORWARDED_PORT` | `True` | Use the `X-Forwarded-Port` header from the proxy. |
| `DJANGO_SECURE_PROXY_SSL_HEADER` | `HTTP_X_FORWARDED_PROTO,https` | Header and expected value (comma-separated) used to detect HTTPS behind a proxy. |
| `DJANGO_SECURE_SSL_REDIRECT` | `False` | When `True`, the application redirects all HTTP requests to HTTPS. Usually `False` when the proxy handles redirection. |

### Example: Behind NGINX with Custom Domain

```ini
-e ENABLE_TLS=false \
-e HTTP_PORT=8080 \
-e DJANGO_CSRF_TRUSTED_ORIGINS=https://koios.example.com \
-e DJANGO_CSRF_COOKIE_SECURE=True \
-e DJANGO_SESSION_COOKIE_SECURE=True \
```

---

## Debugging

These variables are intended for troubleshooting and should not be enabled in normal operation.

| Variable | Default | Description |
|----------|---------|-------------|
| `DJANGO_DEBUG` | `False` | Enables verbose error pages with stack traces. **Never enable in production** — it exposes sensitive information. |
| `KOIOS_DB_QUERY_LOG` | *(disabled)* | Database query logging for the data collection and inference services. Set to `summary` for a periodic 60-second summary, or `verbose` for every individual query with timing. Useful for diagnosing slow queries. |
