feat: add bootstrap admin auth docs and fix config loading
- Document bootstrap admin login via KMTN_ADMIN_USERNAME/PASSWORD env vars, including setup guide, curl examples, and config table entries across docker-compose and bare-metal deployment sections - Add KMTN_JWT_SECRET_KEY to all deployment config examples and production checklist - Fix docker-entrypoint.sh: remove unused API_UPSTREAM variable from config.json envsubst (only API_PUBLIC_URL is needed) - Fix app-config.service: default apiBaseUrl now reads from Angular environment instead of empty string, and config.json path drops leading ./ for cleaner resolution
This commit is contained in:
@@ -136,6 +136,33 @@ The database auto-seeds on first startup. To reset and re-seed at any time:
|
||||
curl -X POST http://localhost:8000/api/admin/reset
|
||||
```
|
||||
|
||||
### Setting up the bootstrap admin user
|
||||
|
||||
The backend supports a hardcoded "bootstrap admin" login via two environment variables. When both are set, anyone with those credentials can authenticate at `POST /api/auth/login` and receives a JWT token with admin privileges.
|
||||
|
||||
```bash
|
||||
# Enable bootstrap admin login
|
||||
export KMTN_ADMIN_USERNAME="admin"
|
||||
export KMTN_ADMIN_PASSWORD="my-secret-password"
|
||||
```
|
||||
|
||||
To log in, send a POST request to `/api/auth/login`:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/auth/login \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"username": "admin", "password": "my-secret-password"}'
|
||||
```
|
||||
|
||||
This returns a JWT access token you can use to access protected endpoints:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/api/auth/me \
|
||||
-H "Authorization: Bearer <access_token>"
|
||||
```
|
||||
|
||||
If either variable is left empty (the default), login is disabled and returns a 503 error. For production, also set `KMTN_JWT_SECRET_KEY` to a strong random value.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Variable | Default | Where | Description |
|
||||
@@ -145,6 +172,9 @@ curl -X POST http://localhost:8000/api/admin/reset
|
||||
| `KMTN_DATABASE_URL` | `postgresql+asyncpg://...` (prod) / `sqlite+aiosqlite:///./kmountain.db` (dev) | [backend/app/config.py](backend/app/config.py) | Database connection string |
|
||||
| `KMTN_CORS_ORIGINS` | `["http://localhost:4200"]` | [backend/app/config.py](backend/app/config.py) | CORS allowlist (JSON array) |
|
||||
| `KMTN_ENV` | `development` | [backend/app/config.py](backend/app/config.py) | Set to `production` to disable admin endpoints |
|
||||
| `KMTN_ADMIN_USERNAME` | _(empty)_ | [backend/app/config.py](backend/app/config.py) | Bootstrap admin username. Leave empty to disable login. |
|
||||
| `KMTN_ADMIN_PASSWORD` | _(empty)_ | [backend/app/config.py](backend/app/config.py) | Bootstrap admin password. Both username and password must be set to enable login. |
|
||||
| `KMTN_JWT_SECRET_KEY` | `change-me-in-production` | [backend/app/config.py](backend/app/config.py) | Secret key used to sign and verify JWT tokens. If leaked, anyone can forge admin tokens. **Change in production.** |
|
||||
| `API_UPSTREAM` | `http://api:8000` | [Dockerfile](Dockerfile) | Internal API target for Nginx proxy (Docker DNS) |
|
||||
| `API_PUBLIC_URL` | `""` (empty) | [Dockerfile](Dockerfile) | Browser-facing API URL. Empty = proxy mode; set to direct URL when ingress breaks proxy chain |
|
||||
|
||||
@@ -235,6 +265,9 @@ services:
|
||||
KMTN_DATABASE_URL: postgresql+asyncpg://postgres:postgres@db:5432/kmountain
|
||||
KMTN_CORS_ORIGINS: '["http://yourdomain.com"]'
|
||||
KMTN_ENV: production
|
||||
KMTN_ADMIN_USERNAME: admin
|
||||
KMTN_ADMIN_PASSWORD: change-me
|
||||
KMTN_JWT_SECRET_KEY: change-me-to-a-random-string
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
@@ -294,6 +327,9 @@ services:
|
||||
KMTN_DATABASE_URL: postgresql+asyncpg://postgres:postgres@db:5432/kmountain
|
||||
KMTN_CORS_ORIGINS: '["http://truenas.local:34200", "http://truenas.local"]'
|
||||
KMTN_ENV: production
|
||||
KMTN_ADMIN_USERNAME: admin
|
||||
KMTN_ADMIN_PASSWORD: change-me
|
||||
KMTN_JWT_SECRET_KEY: change-me-to-a-random-string
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
@@ -331,6 +367,9 @@ ng build --configuration production
|
||||
export KMTN_DATABASE_URL="postgresql+asyncpg://user:pass@host:5432/kmountain"
|
||||
export KMTN_CORS_ORIGINS='["https://yourdomain.com"]'
|
||||
export KMTN_ENV="production"
|
||||
export KMTN_ADMIN_USERNAME="admin"
|
||||
export KMTN_ADMIN_PASSWORD="change-me"
|
||||
export KMTN_JWT_SECRET_KEY="change-me-to-a-random-string"
|
||||
|
||||
# 3. Start the backend
|
||||
cd backend
|
||||
@@ -348,6 +387,8 @@ The database auto-seeds on first startup.
|
||||
- [ ] Use a managed PostgreSQL database (RDS, Cloud SQL, etc.)
|
||||
- [ ] Update `KMTN_CORS_ORIGINS` to your actual domain (not `localhost`)
|
||||
- [ ] Set `KMTN_ENV="production"` to disable admin endpoints
|
||||
- [ ] Set `KMTN_ADMIN_USERNAME` and `KMTN_ADMIN_PASSWORD` to strong values
|
||||
- [ ] Set `KMTN_JWT_SECRET_KEY` to a strong random value
|
||||
- [ ] Add a reverse proxy (Caddy, Traefik) in front of Nginx for HTTPS
|
||||
- [ ] Set up log rotation
|
||||
- [ ] Configure a process manager (systemd, PM2) for the backend
|
||||
|
||||
Reference in New Issue
Block a user