Files
ReadMeABook/documentation/backend/services/environment.md
T
2026-01-28 11:41:24 -05:00

200 lines
6.6 KiB
Markdown

# Environment Variables
**Status:** ✅ Implemented | Centralized URL handling via getBaseUrl() utility
Defines all environment variables used by ReadMeABook, configuration priority, and troubleshooting guide.
## Public URL Configuration (OAuth Callbacks)
**Critical for OAuth:** Plex OAuth and OIDC authentication require correct redirect URIs.
**Priority Order:**
1. `PUBLIC_URL` - **Primary** (documented standard)
2. `NEXTAUTH_URL` - Legacy fallback (backward compatibility)
3. `BASE_URL` - Alternative fallback
4. `http://localhost:3030` - Development default
**Format Requirements:**
- Must start with `http://` or `https://`
- No trailing slash (automatically normalized)
- Must be publicly accessible for OAuth callbacks
- Example: `https://readmeabook.example.com`
**Docker Compose:**
```yaml
environment:
PUBLIC_URL: "https://readmeabook.example.com"
```
**Implementation:** `src/lib/utils/url.ts``getBaseUrl()`
**Used By:**
- OIDC OAuth redirect_uri: `{PUBLIC_URL}/api/auth/oidc/callback`
- Plex OAuth redirect_uri: `{PUBLIC_URL}/api/auth/plex/callback`
- Login error redirects: `{PUBLIC_URL}/login?error=...`
## Database Configuration
**Required:**
- `DATABASE_URL` - PostgreSQL connection string
- **Auto-generated** by entrypoint in unified container
- Format: `postgresql://{user}:{password}@{host}:{port}/{database}`
- Example: `postgresql://readmeabook:password@localhost:5432/readmeabook`
**PostgreSQL Settings (Unified Container):**
- `POSTGRES_USER` - Default: `readmeabook`
- `POSTGRES_PASSWORD` - Auto-generated on first run if not set
- `POSTGRES_DB` - Default: `readmeabook`
## Security & Secrets
**Auto-generated on first run (Unified Container):**
- `JWT_SECRET` - JWT access token signing key
- `JWT_REFRESH_SECRET` - JWT refresh token signing key
- `CONFIG_ENCRYPTION_KEY` - Config field encryption key (Plex tokens, etc.)
- `POSTGRES_PASSWORD` - PostgreSQL password
**Manual Override:** Set in docker-compose.yml before first run to use custom secrets.
## File Ownership (Unified Container)
**User/Group ID Mapping:**
- `PUID` - Default: 1000 (your host user ID)
- `PGID` - Default: 1000 (your host group ID)
**How It Works:**
- PostgreSQL: UID 103, GID={PGID}
- Node/Redis: Fully remapped to PUID:PGID
- See: documentation/deployment/unified.md
## Plex Configuration
**Optional Overrides:**
- `PLEX_CLIENT_IDENTIFIER` - Default: auto-generated UUID
- `PLEX_PRODUCT_NAME` - Default: `ReadMeABook`
- `PLEX_OAUTH_CALLBACK_URL` - Custom OAuth callback (overrides PUBLIC_URL)
## Logging
**Optional:**
- `LOG_LEVEL` - Default: `info`
- Values: `debug`, `info`, `warn`, `error`
- `debug` logs base URL resolution source
**Debug Example:**
```
[URL Utility] Using base URL from PUBLIC_URL: https://example.com
```
## Setup Middleware
**Internal Override:**
- `SETUP_CHECK_BASE_URL` - Override base URL for setup status check
- Use case: Reverse proxies with TLS termination
- Default: Tries request origin, then loopback
- See: documentation/backend/middleware.md
## Troubleshooting
### Issue: OAuth Redirects to Localhost
**Symptoms:**
- OIDC/Plex OAuth redirects to `http://localhost:3030/api/auth/...`
- Authentik/Identity Provider shows `localhost` redirect URI
- "Redirect URI Error" or "Mismatching redirection URI"
**Cause:** `PUBLIC_URL` not set (defaulting to localhost)
**Fix:**
```yaml
# docker-compose.yml
environment:
PUBLIC_URL: "https://your-actual-domain.com" # No trailing slash
```
**Restart container after change.**
### Issue: Invalid Redirect URI Format
**Symptoms:**
- Warning: `Invalid base URL format`
- OAuth fails with malformed URL
**Cause:** PUBLIC_URL missing protocol or has invalid format
**Fix:**
- ✅ Correct: `https://example.com`
- ❌ Wrong: `example.com` (missing protocol)
- ❌ Wrong: `https://example.com/` (trailing slash, auto-normalized but avoid)
### Issue: Production Using Localhost
**Symptoms:**
- Warning: `Using localhost URL in production`
- OAuth fails from external clients
**Cause:** NODE_ENV=production but PUBLIC_URL not set
**Fix:** Always set PUBLIC_URL in production deployments.
### Issue: checks.state argument is missing (OIDC)
**Symptoms:**
- Error in URL after OIDC login: `error=TypeError: checks.state argument is missing`
- Login redirects back to login page after Authentik authentication
**Cause:** Missing state parameter in openid-client callback checks (fixed in latest version)
**Fix:** Update to latest version with state parameter fix
### Issue: OIDC login succeeds but redirects back to login page
**Symptoms:**
- OIDC authentication completes in Authentik
- Redirect back to ReadMeABook succeeds
- URL shows `/login?redirect=%2F`
- Not actually logged in, no auth cookies visible
**Cause:** httpOnly cookies prevent JavaScript from reading tokens (fixed in latest version)
**Fix:**
- Update to latest version
- Callback now uses URL hash + accessible cookies (matches Plex OAuth pattern)
- Tokens properly stored in localStorage
**Authentik Configuration Requirements:**
1. Go to Application/Provider → Scopes
2. Add: `openid`, `profile`, `email`, `groups`
3. Redirect URI: `https://your-domain.com/api/auth/oidc/callback`
4. Save and retry login
## Environment Variable Reference
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PUBLIC_URL` | Prod | localhost:3030 | Public URL for OAuth callbacks |
| `NEXTAUTH_URL` | No | - | Legacy fallback for PUBLIC_URL |
| `BASE_URL` | No | - | Alternative fallback for PUBLIC_URL |
| `DATABASE_URL` | Yes | Auto-generated | PostgreSQL connection string |
| `POSTGRES_USER` | No | readmeabook | PostgreSQL username |
| `POSTGRES_PASSWORD` | No | Auto-generated | PostgreSQL password |
| `POSTGRES_DB` | No | readmeabook | PostgreSQL database name |
| `JWT_SECRET` | No | Auto-generated | JWT signing secret |
| `JWT_REFRESH_SECRET` | No | Auto-generated | Refresh token secret |
| `CONFIG_ENCRYPTION_KEY` | No | Auto-generated | Config encryption key |
| `PUID` | No | 1000 | Host user ID for file ownership |
| `PGID` | No | 1000 | Host group ID for file ownership |
| `PLEX_CLIENT_IDENTIFIER` | No | Auto-generated | Plex API client ID |
| `PLEX_PRODUCT_NAME` | No | ReadMeABook | Plex product name |
| `PLEX_OAUTH_CALLBACK_URL` | No | - | Custom Plex OAuth callback |
| `LOG_LEVEL` | No | info | Logging verbosity |
| `SETUP_CHECK_BASE_URL` | No | - | Setup middleware override |
| `NODE_ENV` | No | production | Environment mode |
## Related
- OAuth Implementation: documentation/backend/services/auth.md
- OIDC Configuration: documentation/features/audiobookshelf-integration.md
- Deployment: documentation/deployment/unified.md
- Setup Middleware: documentation/backend/middleware.md