# How to Configure the Encryption Key for FreeLLMAPI: Complete Setup Guide

> Learn how to configure the encryption key for FreeLLMAPI using a 64-character hex string for AES-256-GCM encryption. Secure your API keys today.

- Repository: [Tashfeen/freellmapi](https://github.com/tashfeenahmed/freellmapi)
- Tags: how-to-guide
- Published: 2026-08-28

---

**Set a 64-character hex string in the `ENCRYPTION_KEY` environment variable to enable AES-256-GCM encryption for all stored API keys.**

FreeLLMAPI uses **AES-256-GCM encryption** to protect API keys at rest. The encryption key must be a 32-byte (64-character hexadecimal) secret configured through environment variables. This guide walks through generating, validating, and deploying this key based on the actual implementation in [tashfeenahmed/freellmapi](https://github.com/tashfeenahmed/freellmapi).

## Understanding the Encryption Key System

The encryption logic resides in [[`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts)](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts). On server startup, `initEncryptionKey(db)` executes a priority-based lookup to determine which key to use.

### Key Resolution Order

1. **`ENCRYPTION_KEY` environment variable** — Validated 64-character hex string; used directly if present and valid
2. **Development fallback file** — `.encryption-key` file adjacent to the SQLite database (non-production only)
3. **Legacy database migration** — Existing key from the `settings` table, migrated to file storage
4. **Auto-generated dev key** — Fresh random key created and persisted to file (development only)

In **production mode** (`NODE_ENV=production`), the server strictly requires a valid `ENCRYPTION_KEY`. Missing or invalid keys trigger an immediate startup error:

```

ENCRYPTION_KEY is required in production for API key encryption.
Set a 64-character hex key (generate one with:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))").
Outside production a local key file is auto-generated next to the database.

```

## Generating a Valid Encryption Key

Run this command once to produce a cryptographically secure 64-character hexadecimal string:

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

```

Example output:

```

a3f1c8e9b5d6f7a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3

```

This satisfies the validation check in `initEncryptionKey`: exactly 64 characters, hexadecimal only (`/^[a-f0-9]{64}$/i`).

## Configuring the Encryption Key in FreeLLMAPI

### Step 1: Copy the Environment Template

The repository includes [`.env.example`](https://github.com/tashfeenahmed/freellmapi/blob/main/.env.example) as a starting configuration:

```bash
cp .env.example .env

```

The relevant section contains:

```dotenv
ENCRYPTION_KEY=your-64-char-hex-key-here

```

### Step 2: Replace with Your Generated Key

Edit `.env` and substitute the placeholder:

```dotenv
ENCRYPTION_KEY=a3f1c8e9b5d6f7a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3

```

### Step 3: Load and Verify

Start the server in development to confirm successful key loading:

```bash
npm run dev

```

With `ENCRYPTION_KEY` properly set, no warnings appear. The key is cached in memory via `cachedKey` and accessible through `getEncryptionKey()` for all encryption operations.

For production deployments, export the variable in your hosting environment rather than relying on `.env` files.

## Development-Only Auto-Configuration

When running FreeLLMAPI locally **without** `ENCRYPTION_KEY` set, the system automatically handles key provisioning:

- Creates `.encryption-key` file beside the SQLite database
- Writes with atomic `0600` permissions (owner read/write only)
- Reuses this file across subsequent restarts

This convenience is **disabled in production**. Never commit auto-generated key files to version control.

## Programmatic Key Usage

The encryption subsystem exposes three core functions from [[`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts)](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts):

```typescript
import { initEncryptionKey, encrypt, decrypt } from './server/src/lib/crypto.js';
import { connectDb } from './server/src/db/index.js';

const db = connectDb();
initEncryptionKey(db);  // Must run before encrypt/decrypt

const secret = 'sk-my-api-key';
const cipher = encrypt(secret);
// Returns: { encrypted: Buffer, iv: Buffer, authTag: Buffer }

const recovered = decrypt(cipher.encrypted, cipher.iv, cipher.authTag);

```

All stored API keys in FreeLLMAPI follow this encryption pattern. The initialization step ensures the cached key is available before any cryptographic operations execute.

## Key Files and Related Components

| File | Purpose |
|------|---------|
| [[`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts)](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts) | Core implementation: `initEncryptionKey`, `getEncryptionKey`, `encrypt`, `decrypt` |
| [`.env.example`](https://github.com/tashfeenahmed/freellmapi/blob/main/.env.example) | Template with `ENCRYPTION_KEY` placeholder |
| [[`server/src/lib/db-backup.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/db-backup.ts)](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/db-backup.ts) | Database backup encryption (separate `FREEAPI_DB_BACKUP_KEY` or falls back to main key) |

## Summary

- **Generate** a 64-character hex key using Node.js `crypto.randomBytes(32)`
- **Configure** via `ENCRYPTION_KEY` environment variable in production
- **Validate** that the server starts without encryption warnings
- **Protect** key files with restrictive permissions and exclude from version control
- **Reference** [`server/src/lib/crypto.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/crypto.ts) for implementation details

## Frequently Asked Questions

### What happens if I don't set ENCRYPTION_KEY in production?

FreeLLMAPI throws a fatal startup error with explicit instructions. The server refuses to start without valid encryption configuration when `NODE_ENV=production`.

### Can I rotate or change the encryption key later?

The current implementation does not provide automatic key rotation. Changing `ENCRYPTION_KEY` invalidates all previously encrypted API keys. Plan key rotation carefully with backup restoration procedures.

### How does the auto-generated dev key work?

When `ENCRYPTION_KEY` is unset and `NODE_ENV` is not `production`, `initEncryptionKey` creates `.encryption-key` in the database directory. This file persists across restarts but should never be used for production deployments.

### Is the same encryption key used for database backups?

[[`server/src/lib/db-backup.ts`](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/db-backup.ts)](https://github.com/tashfeenahmed/freellmapi/blob/main/server/src/lib/db-backup.ts) checks for `FREEAPI_DB_BACKUP_KEY` first, then falls back to the main `ENCRYPTION_KEY`. Configure a separate backup key for additional isolation if desired.