Skip to main content

Configuration

Codex uses YAML configuration files with environment variable overrides. This guide covers all configuration options and best practices.

Configuration File

Codex looks for configuration in the following order:

  1. Path specified via --config flag
  2. codex.yaml in the current directory
  3. Default values
codex serve --config /path/to/codex.yaml

Configuration Priority

Settings can come from multiple sources, with this priority (highest to lowest):

  1. Environment variables (override everything)
  2. Configuration file (YAML)
  3. Database settings (runtime-configurable options)
  4. Hardcoded defaults (fallback)

Database Configuration

Codex supports both SQLite and PostgreSQL databases.

tip

For detailed database setup instructions including installation, user creation, and troubleshooting, see the Database Setup guide.

Best for single-user or small deployments with fewer than 10,000 books.

database:
db_type: sqlite
sqlite:
path: ./data/codex.db
pragmas:
journal_mode: WAL
synchronous: NORMAL

SQLite Pragmas

PragmaOptionsDescription
journal_modeWAL (recommended), DELETE, TRUNCATEWAL provides better concurrency
synchronousNORMAL (recommended), FULL, OFFTrade-off between safety and speed
foreign_keysAlways ONCannot be disabled (data integrity)
WAL Mode

Write-Ahead Logging (WAL) is strongly recommended for SQLite. It provides:

  • Better read/write concurrency
  • Faster writes for most workloads
  • Crash recovery improvements

SQLite Connection Pool

SQLite connection pool settings can be tuned for your workload:

database:
db_type: sqlite
sqlite:
path: ./data/codex.db
# Connection pool settings
max_connections: 16 # Maximum pool size (default: 16)
min_connections: 2 # Minimum warm connections (default: 2)
acquire_timeout_seconds: 30 # Wait time for connection (default: 30)
idle_timeout_seconds: 300 # Idle connection timeout (default: 300 = 5 min)
max_lifetime_seconds: 1800 # Max connection lifetime (default: 1800 = 30 min)
SettingDefaultDescription
max_connections16Maximum connections in pool
min_connections2Minimum warm connections
acquire_timeout_seconds30How long to wait for a connection
idle_timeout_seconds300Idle connection timeout (5 min)
max_lifetime_seconds1800Maximum connection lifetime (30 min)
SQLite Pool Sizing

SQLite with WAL mode handles concurrent reads well, but writes are serialized. The default of 16 connections works well for most workloads. Increase if you see "connection pool timeout" errors during heavy load.

Best for multi-user environments, large libraries, or horizontal scaling.

database:
db_type: postgres
postgres:
host: localhost
port: 5432
username: codex
password: codex
database_name: codex
ssl_mode: prefer
# Connection pool settings
max_connections: 100 # Maximum pool size (default: 100)
min_connections: 5 # Minimum warm connections (default: 5)
acquire_timeout_seconds: 30 # Wait time for connection (default: 30)
idle_timeout_seconds: 600 # Idle connection timeout (default: 600 = 10 min)
max_lifetime_seconds: 3600 # Max connection lifetime (default: 3600 = 1 hour)

PostgreSQL SSL Modes

ModeDescription
disableNo SSL (not recommended for production)
allowTry without SSL, use SSL if available
preferTry SSL first, fallback to no SSL (default)
requireSSL required, but don't verify certificate
verify-caSSL required, verify server certificate
verify-fullSSL required, verify certificate and hostname
Production Security

For production deployments, use verify-ca or verify-full SSL mode with proper certificates.

Application Configuration

application:
name: Codex # Server name (displayed in UI)
host: 0.0.0.0 # Bind address (0.0.0.0 for all interfaces)
port: 8080 # Server port
SettingDefaultDescription
nameCodexServer display name
host127.0.0.1Bind address
port8080HTTP port

Authentication Configuration

auth:
jwt_secret: "CHANGE_ME_IN_PRODUCTION"
jwt_expiry_hours: 24
refresh_token_enabled: false
email_confirmation_required: false
argon2_memory_cost: 19456
argon2_time_cost: 2
argon2_parallelism: 1
SettingDefaultDescription
jwt_secretRequiredSecret key for JWT signing
jwt_expiry_hours24Token validity period
refresh_token_enabledfalseEnable refresh tokens
email_confirmation_requiredfalseRequire email verification
argon2_memory_cost19456Argon2 memory cost (KiB)
argon2_time_cost2Argon2 iterations
argon2_parallelism1Argon2 parallelism
JWT Secret

Always change the JWT secret in production! Generate a secure random string:

openssl rand -base64 32

OIDC (Single Sign-On)

Enable OpenID Connect authentication to allow users to sign in via external identity providers:

auth:
oidc:
enabled: true
auto_create_users: true
default_role: reader
providers:
authentik:
display_name: "Authentik"
issuer_url: "https://authentik.example.com/application/o/codex/"
client_id: "codex-client-id"
client_secret: "codex-client-secret"
scopes:
- email
- profile
- groups
role_mapping:
admin:
- codex-admins
maintainer:
- codex-editors
reader:
- codex-users
groups_claim: "groups"
SettingDefaultDescription
oidc.enabledfalseEnable OIDC authentication
oidc.auto_create_userstrueCreate users on first OIDC login
oidc.default_rolereaderDefault role when no groups match
oidc.redirect_uri_baseauto-detectedOverride base URL for OAuth callbacks

See OIDC / Single Sign-On for full setup instructions and provider guides.

API Configuration

api:
enable_api_docs: false
api_docs_path: "/docs"
cors_enabled: true
max_page_size: 100
SettingDefaultDescription
enable_api_docsfalseEnable API documentation (Scalar)
api_docs_path/docsAPI documentation URL path
cors_enabledtrueEnable CORS
max_page_size100Maximum items per page

Logging Configuration

logging:
level: info
# file: ./logs/codex.log # Uncomment to enable file logging
SettingDefaultDescription
levelinfoLog level: error, warn, info, debug, trace
fileNoneOptional log file path

Task Worker Configuration

These settings require a restart to take effect.

task:
worker_count: 4
SettingDefaultDescription
worker_count4Number of parallel background workers

Scanner Configuration

These settings require a restart to take effect.

scanner:
max_concurrent_scans: 2
SettingDefaultDescription
max_concurrent_scans2Maximum concurrent library scans

Files Configuration

Configuration for file storage directories (thumbnails and uploads).

files:
thumbnail_dir: data/thumbnails
uploads_dir: data/uploads
SettingDefaultDescription
thumbnail_dirdata/thumbnailsDirectory for thumbnail cache
uploads_dirdata/uploadsDirectory for user-uploaded files (covers, etc.)

Additional thumbnail settings are stored in the database and can be changed via the Settings API without restart:

  • thumbnail_max_dimension - Maximum width/height (default: 400px)
  • thumbnail_jpeg_quality - JPEG quality (default: 85%)

Email Configuration (Optional)

For email verification and notifications:

email:
smtp_host: localhost
smtp_port: 587
smtp_username: ""
smtp_password: ""
smtp_from_email: noreply@example.com
smtp_from_name: Codex
verification_token_expiry_hours: 24
verification_url_base: http://localhost:8080

PDF Rendering Configuration

Codex can render PDF pages server-side using the PDFium library. This enables:

  • Thumbnails and covers for all PDF types (text-only, vector graphics, scanned)
  • Server-side page rendering for the streaming reader mode
pdf:
# pdfium_library_path: /path/to/libpdfium.so # Optional, auto-detected if not set
render_dpi: 150 # Render DPI (72-300, higher = better quality, larger files)
jpeg_quality: 85 # JPEG compression quality (1-100)
cache_rendered_pages: true # Cache rendered pages to disk
cache_dir: data/cache # Cache directory for rendered PDF pages
SettingDefaultDescription
pdfium_library_pathAuto-detectPath to PDFium shared library. Usually not needed - Codex automatically searches the executable directory and system library paths
render_dpi150Render resolution in DPI. Higher values produce sharper images but larger files
jpeg_quality85JPEG compression quality (1-100). Higher values = better quality, larger files
cache_rendered_pagestrueEnable disk caching of rendered PDF pages
cache_dirdata/cacheDirectory for PDF page cache (stored in {cache_dir}/pdf_pages/)

PDFium Library Installation

PDFium is bundled in the official Docker image. No additional setup required.

Binary Installation (Linux)

For standalone binary deployments, install PDFium separately:

# Download pre-built PDFium library (Debian/Ubuntu with glibc)
wget -O- https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-x64.tgz \
| sudo tar -xz -C /usr/local
sudo ldconfig

# Or for Alpine/musl-based systems
wget -O- https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-linux-musl-x64.tgz \
| sudo tar -xz -C /usr/local

macOS

# Download PDFium for macOS
wget -O- https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-x64.tgz \
| sudo tar -xz -C /usr/local

# Or for Apple Silicon (arm64)
wget -O- https://github.com/bblanchon/pdfium-binaries/releases/latest/download/pdfium-mac-arm64.tgz \
| sudo tar -xz -C /usr/local

Windows

  1. Download pdfium-win-x64.zip from bblanchon/pdfium-binaries releases
  2. Extract pdfium.dll to a directory in your PATH
  3. Or set CODEX_PDF_PDFIUM_LIBRARY_PATH to the full path of pdfium.dll

Without PDFium

If PDFium is not installed:

  • Scanned PDFs (with embedded images): Work normally via embedded image extraction
  • Text-only PDFs: Page extraction will fail, but the PDF can still be viewed in native mode
Native PDF Mode

Users can switch to native PDF mode in the reader settings, which downloads the full PDF and renders it client-side using pdf.js. This works without PDFium but uses more bandwidth.

Cache Management

Rendered PDF pages are cached to disk to improve performance. The cache structure is:

{cache_dir}/pdf_pages/{book_id_prefix}/{book_id}/page_{number}_{dpi}.jpg

Cache is automatically invalidated when:

  • A book file is updated (detected by file hash change during scan)
  • The book is deleted from the library

To manually clear the cache:

  • Delete a specific book's cache: Remove {cache_dir}/pdf_pages/{book_id}/
  • Clear all cached pages: Remove {cache_dir}/pdf_pages/

Komga-Compatible API (Optional)

Codex can expose a Komga-compatible API, allowing you to use third-party apps designed for Komga (such as Komic for iOS) with your Codex server.

info

This feature is disabled by default and must be explicitly enabled in your configuration.

komga_api:
enabled: true
prefix: "komga" # URL prefix (default: komga)
SettingDefaultDescription
enabledfalseEnable Komga-compatible API endpoints
prefixkomgaURL prefix for Komga API (results in /{prefix}/api/v1/...)

When enabled, the Komga API will be available at:

http://your-server:8080/komga/api/v1/libraries
http://your-server:8080/komga/api/v1/series
http://your-server:8080/komga/api/v1/books
...

Configuring Third-Party Apps

To connect apps like Komic to Codex:

  1. Server URL: http://your-server:8080/komga
  2. Authentication: Use your Codex username and password (Basic Auth)
Custom Prefix

You can change the URL prefix to avoid conflicts or for preference. For example, setting prefix: "compat" would make the API available at /compat/api/v1/....

Supported Features

  • Library browsing
  • Series and book navigation
  • Thumbnail display
  • Page streaming for reading
  • Reading progress sync
  • Book file downloads
  • Next/previous book navigation

Limitations

  • Read-only: Metadata editing through the Komga API is not supported
  • No collections/read lists: These Komga features are not implemented
  • Basic search only: Full Komga search syntax is not supported
  • No oneshot detection: The oneshot field is always omitted from responses

For more details, see the Third-Party Apps documentation.

Rate Limiting

Codex includes built-in API rate limiting to protect against abuse. Rate limiting is enabled by default and uses a token bucket algorithm with per-client tracking.

rate_limit:
enabled: true
anonymous_rps: 10 # Requests per second for anonymous users
anonymous_burst: 50 # Maximum burst size for anonymous users
authenticated_rps: 50 # Requests per second for authenticated users
authenticated_burst: 200 # Maximum burst size for authenticated users
exempt_paths: # Glob patterns for paths exempt from rate limiting
- /health
- /api/v1/events
- /api/v1/events/**
- /api/v1/books/*/thumbnail # Exempt book thumbnails
cleanup_interval_secs: 60 # How often to clean stale buckets
bucket_ttl_secs: 300 # Time before a bucket is considered stale
SettingDefaultDescription
enabledtrueEnable/disable rate limiting
anonymous_rps10Requests per second for anonymous users
anonymous_burst50Maximum burst size for anonymous users
authenticated_rps50Requests per second for authenticated users
authenticated_burst200Maximum burst size for authenticated users
exempt_paths["/health", "/api/v1/events", "/api/v1/events/**"]Glob patterns for paths exempt from rate limiting
cleanup_interval_secs60How often to clean up stale client buckets
bucket_ttl_secs300Time in seconds before a bucket is considered stale

Exempt paths support glob patterns:

  • * matches a single path segment (e.g., /api/v1/books/*/thumbnail matches /api/v1/books/123/thumbnail)
  • ** matches zero or more path segments (e.g., /api/v1/events/** matches /api/v1/events/stream)
  • Exact paths match only themselves (e.g., /health matches only /health, not /health/check)

How It Works

Rate limiting uses a token bucket algorithm:

  1. Each client (identified by IP address or user ID) has a bucket of tokens
  2. Tokens are added at the configured rate (e.g., 10/second for anonymous)
  3. Each request consumes one token
  4. If no tokens are available, the request is rejected with HTTP 429
  5. The bucket can hold up to the burst limit, allowing temporary spikes

Response Headers

All API responses include rate limit information:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when limit resets

429 Too Many Requests

When rate limited, the API returns:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1706140800
Content-Type: application/json

{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 30 seconds.",
"retry_after": 30
}

Disabling Rate Limiting

To disable rate limiting (not recommended for production):

rate_limit:
enabled: false

Or via environment variable:

CODEX_RATE_LIMIT_ENABLED=false
caution

Disabling rate limiting may expose your server to abuse. Only disable for trusted networks or development environments.

Plugin Credential Encryption

Codex encrypts sensitive plugin data at rest — including OAuth tokens, refresh tokens, and plugin credentials — using AES-256-GCM authenticated encryption. This section covers setting up and managing the encryption key.

Setting Up the Encryption Key

The encryption key is provided via the CODEX_ENCRYPTION_KEY environment variable. It must be a base64-encoded 32-byte (256-bit) key.

Generate a key using OpenSSL:

openssl rand -base64 32

Then set it as an environment variable:

export CODEX_ENCRYPTION_KEY="your-generated-base64-key-here"

Or in a Docker Compose file:

environment:
CODEX_ENCRYPTION_KEY: "your-generated-base64-key-here"
Required for Plugins

The encryption key is required when using sync or recommendation plugins that store OAuth tokens. Without it, plugin connection attempts will fail with a "Service Unavailable" error. Metadata-only plugins (like Open Library) do not require an encryption key.

What the Key Protects

DataWhen Encrypted
OAuth access tokensWhen a user connects a sync/recommendation plugin
OAuth refresh tokensWhen the external service issues a refresh token
Plugin credentialsWhen a plugin stores API keys or secrets

All encrypted values use a random 96-bit nonce, so encrypting the same token twice produces different ciphertext. Decryption requires the exact same key that was used for encryption.

Key Requirements

  • Length: Exactly 32 bytes (256 bits) before base64 encoding
  • Encoding: Standard base64 (RFC 4648)
  • Persistence: Must remain the same across Codex restarts — changing the key without re-encrypting data will make existing tokens undecryptable

Key Rotation

Codex does not currently support automatic key rotation. If you need to rotate the encryption key, follow this manual procedure:

  1. Stop Codex — ensure no requests are in flight
  2. Have all users disconnect their plugins — go to Settings > Integrations and click Disconnect on each plugin connection. This deletes the encrypted tokens from the database
  3. Update the encryption key — set CODEX_ENCRYPTION_KEY to the new key
  4. Start Codex
  5. Have users reconnect their plugins — each user re-authorizes via OAuth, and new tokens are encrypted with the new key
Simpler Alternative

Since disconnecting and reconnecting plugins re-issues fresh OAuth tokens encrypted with the current key, this is the simplest and safest rotation method. No data migration or scripting is required.

Lost Key

If you lose the encryption key, all stored OAuth tokens become undecryptable. Users will need to disconnect and reconnect their plugins to issue new tokens. No plugin configuration or storage data is lost — only the encrypted credentials.

Future Enhancement

Automatic key rotation with key versioning (storing the key version alongside encrypted data for seamless re-encryption) is planned for a future release.

Environment Variables

All configuration options can be overridden with environment variables using the CODEX_ prefix.

Naming Convention

Configuration paths are converted to environment variables:

  • Use uppercase
  • Replace dots with underscores
  • Prefix with CODEX_
Config PathEnvironment Variable
database.db_typeCODEX_DATABASE_DB_TYPE
database.postgres.hostCODEX_DATABASE_POSTGRES_HOST
auth.jwt_secretCODEX_AUTH_JWT_SECRET
logging.levelCODEX_LOGGING_LEVEL

Common Environment Variables

# Database
CODEX_DATABASE_DB_TYPE=postgres
CODEX_DATABASE_POSTGRES_HOST=localhost
CODEX_DATABASE_POSTGRES_PORT=5432
CODEX_DATABASE_POSTGRES_USERNAME=codex
CODEX_DATABASE_POSTGRES_PASSWORD=secret
CODEX_DATABASE_POSTGRES_DATABASE_NAME=codex
CODEX_DATABASE_POSTGRES_SSL_MODE=require

# Application
CODEX_APPLICATION_HOST=0.0.0.0
CODEX_APPLICATION_PORT=8080

# Authentication
CODEX_AUTH_JWT_SECRET=your-secure-secret-key

# Logging
CODEX_LOGGING_LEVEL=debug
CODEX_LOGGING_FILE=/var/log/codex/codex.log

# API
CODEX_API_ENABLE_API_DOCS=true

# Task Workers
CODEX_TASK_WORKER_COUNT=4

# Scanner
CODEX_SCANNER_MAX_CONCURRENT_SCANS=2

# Files (thumbnails and uploads)
CODEX_FILES_THUMBNAIL_DIR=data/thumbnails
CODEX_FILES_UPLOADS_DIR=data/uploads

# PDF Rendering
# CODEX_PDF_PDFIUM_LIBRARY_PATH=/usr/local/lib/libpdfium.so # Optional, auto-detected
CODEX_PDF_RENDER_DPI=150
CODEX_PDF_JPEG_QUALITY=85
CODEX_PDF_CACHE_RENDERED_PAGES=true
CODEX_PDF_CACHE_DIR=data/cache

# Komga-Compatible API
CODEX_KOMGA_API_ENABLED=true
CODEX_KOMGA_API_PREFIX=komga

# Plugin Credential Encryption
CODEX_ENCRYPTION_KEY=your-base64-encoded-32-byte-key

# Rate Limiting
CODEX_RATE_LIMIT_ENABLED=true
CODEX_RATE_LIMIT_ANONYMOUS_RPS=10
CODEX_RATE_LIMIT_ANONYMOUS_BURST=50
CODEX_RATE_LIMIT_AUTHENTICATED_RPS=50
CODEX_RATE_LIMIT_AUTHENTICATED_BURST=200
CODEX_RATE_LIMIT_EXEMPT_PATHS=/health,/api/v1/events
CODEX_RATE_LIMIT_CLEANUP_INTERVAL_SECS=60
CODEX_RATE_LIMIT_BUCKET_TTL_SECS=300

Runtime vs Startup Settings

Some settings can be changed at runtime via the Settings API, while others require a restart.

Runtime-Configurable (No Restart Required)

These settings are stored in the database and can be changed via /api/v1/admin/settings:

  • Thumbnail max dimension
  • Thumbnail JPEG quality
  • Application name
  • Logging level

Startup-Time (Restart Required)

These settings are read from the config file at startup:

  • Database connection settings
  • Task worker count
  • Scanner concurrent scan limit
  • Thumbnail cache directory
  • JWT secret
  • Server host/port
  • PDF rendering settings (DPI, cache directory, PDFium library path)
  • Rate limiting settings
  • Plugin encryption key (CODEX_ENCRYPTION_KEY)

Example Configurations

Minimal SQLite Configuration

database:
db_type: sqlite
sqlite:
path: ./data/codex.db

application:
host: 127.0.0.1
port: 8080

auth:
jwt_secret: "your-secure-random-secret"

Production PostgreSQL Configuration

database:
db_type: postgres
postgres:
host: db.example.com
port: 5432
username: codex
password: ${DB_PASSWORD}
database_name: codex
ssl_mode: verify-full

application:
name: My Library
host: 0.0.0.0
port: 8080

logging:
level: info
file: /var/log/codex/codex.log

auth:
jwt_secret: ${JWT_SECRET}
jwt_expiry_hours: 12

api:
enable_api_docs: false
cors_enabled: true

task:
worker_count: 8

scanner:
max_concurrent_scans: 4

files:
thumbnail_dir: /var/lib/codex/thumbnails
uploads_dir: /var/lib/codex/uploads

Kubernetes Configuration

For Kubernetes deployments, use environment variables for all sensitive data:

# Minimal config file - most settings come from environment
task:
worker_count: 4

scanner:
max_concurrent_scans: 2

files:
thumbnail_dir: data/thumbnails
uploads_dir: data/uploads

Set these via Kubernetes ConfigMaps and Secrets:

CODEX_DATABASE_DB_TYPE=postgres
CODEX_DATABASE_POSTGRES_HOST=postgres-service
CODEX_DATABASE_POSTGRES_PORT=5432
CODEX_DATABASE_POSTGRES_USERNAME=<from secret>
CODEX_DATABASE_POSTGRES_PASSWORD=<from secret>
CODEX_DATABASE_POSTGRES_DATABASE_NAME=codex
CODEX_AUTH_JWT_SECRET=<from secret>
CODEX_ENCRYPTION_KEY=<from secret>

Configuration Validation

Codex validates configuration at startup. Common errors:

ErrorCauseSolution
Invalid database typedb_type not sqlite or postgresFix the db_type value
Missing database pathSQLite requires a pathAdd sqlite.path
Database connection failedWrong credentials or hostCheck connection settings
Invalid portPort outside 1-65535 rangeUse a valid port number
File permissionsCan't write to pathsCheck directory permissions

Library & Plugin Advanced Settings

Libraries and plugins have advanced settings for metadata preprocessing and auto-match conditions. These are configured via the web UI or API, not the config file.

Library Settings

Libraries support these optional settings for metadata processing:

SettingTypeDescription
title_preprocessing_rulesJSONRegex rules to clean series titles during scan
auto_match_conditionsJSONConditions that must pass for auto-matching

Title Preprocessing Rules

Clean up series directory names before they become display titles:

[
{
"pattern": "\\s*\\(Digital\\)$",
"replacement": "",
"description": "Remove (Digital) suffix"
}
]

Common patterns:

  • Remove "(Digital)" suffix: \\s*\\(Digital\\)$ → ``
  • Remove "[Author]" prefix: ^\\[[^\\]]+\\]\\s* → ``
  • Remove year suffix: \\s*\\(\\d{4}\\)$ → ``

Auto-Match Conditions

Control when auto-matching occurs for series in this library:

{
"mode": "all",
"rules": [
{
"field": "book_count",
"operator": "gte",
"value": 1
}
]
}

Plugin Settings

Plugins support these optional settings for search customization:

SettingTypeDescription
search_query_templatestringHandlebars template for search query
search_preprocessing_rulesJSONRegex rules to clean search queries
auto_match_conditionsJSONConditions that must pass for this plugin
use_existing_external_idbooleanReuse existing external ID instead of searching

Search Query Template

Customize the search query sent to the metadata provider:

{{metadata.title}}{{#if metadata.year}} ({{metadata.year}}){{/if}}

Use Existing External ID

When enabled, if a series already has an external ID for this plugin, Codex will call plugin.get(external_id) directly instead of searching.

For detailed configuration, see the Preprocessing Rules Guide.

Security Best Practices

  1. Use strong JWT secrets - Generate with openssl rand -base64 32
  2. Set a plugin encryption key - Required for sync/recommendation plugins; generate with openssl rand -base64 32
  3. Never commit secrets - Use environment variables or secret managers
  4. Use SSL for PostgreSQL - Set ssl_mode: verify-full in production
  5. Restrict bind address - Use 127.0.0.1 unless needed externally
  6. Disable API docs in production - Set enable_api_docs: false

Next Steps