Skip to content

Commit 5137a25

Browse files
committed
Add remainging rate limits. Add docker compose production example. Update beta-checklist.
1 parent fed7c3c commit 5137a25

File tree

4 files changed

+117
-65
lines changed

4 files changed

+117
-65
lines changed

README.md

Lines changed: 99 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -306,21 +306,100 @@ bin/dev
306306

307307
## Production Deployment
308308

309-
### Docker
309+
### Docker Compose (Recommended)
310+
311+
Create a `docker-compose.yml` file:
312+
313+
```yaml
314+
services:
315+
clinch:
316+
image: ghcr.io/dkam/clinch:latest
317+
ports:
318+
- "127.0.0.1:3000:3000" # Bind to localhost only (reverse proxy on same host)
319+
# Use "3000:3000" if reverse proxy is in Docker network or different host
320+
environment:
321+
# Rails Configuration
322+
RAILS_ENV: production
323+
SECRET_KEY_BASE: ${SECRET_KEY_BASE}
324+
325+
# Application Configuration
326+
CLINCH_HOST: ${CLINCH_HOST}
327+
CLINCH_FROM_EMAIL: ${CLINCH_FROM_EMAIL:-noreply@example.com}
328+
329+
# SMTP Configuration
330+
SMTP_ADDRESS: ${SMTP_ADDRESS}
331+
SMTP_PORT: ${SMTP_PORT}
332+
SMTP_DOMAIN: ${SMTP_DOMAIN}
333+
SMTP_USERNAME: ${SMTP_USERNAME}
334+
SMTP_PASSWORD: ${SMTP_PASSWORD}
335+
SMTP_AUTHENTICATION: ${SMTP_AUTHENTICATION:-plain}
336+
SMTP_ENABLE_STARTTLS: ${SMTP_ENABLE_STARTTLS:-true}
337+
338+
# OIDC Configuration (optional - generates temporary key if not provided)
339+
OIDC_PRIVATE_KEY: ${OIDC_PRIVATE_KEY}
340+
341+
# Optional Configuration
342+
FORCE_SSL: ${FORCE_SSL:-false}
343+
volumes:
344+
- ./storage:/rails/storage
345+
restart: unless-stopped
346+
```
347+
348+
Create a `.env` file in the same directory:
310349

311350
```bash
312-
# Build image
313-
docker build -t clinch .
314-
315-
# Run container
316-
docker run -p 3000:3000 \
317-
-v clinch-storage:/rails/storage \
318-
-e SECRET_KEY_BASE=your-secret-key \
319-
-e SMTP_ADDRESS=smtp.example.com \
320-
-e SMTP_PORT=587 \
321-
-e SMTP_USERNAME=your-username \
322-
-e SMTP_PASSWORD=your-password \
323-
clinch
351+
# Generate with: openssl rand -hex 64
352+
SECRET_KEY_BASE=your-secret-key-here
353+
354+
# Application URLs
355+
CLINCH_HOST=https://auth.yourdomain.com
356+
CLINCH_FROM_EMAIL=noreply@yourdomain.com
357+
358+
# SMTP Settings
359+
SMTP_ADDRESS=smtp.example.com
360+
SMTP_PORT=587
361+
SMTP_DOMAIN=yourdomain.com
362+
SMTP_USERNAME=your-smtp-username
363+
SMTP_PASSWORD=your-smtp-password
364+
365+
# OIDC (optional - generates temporary key if not set)
366+
# Generate with: openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
367+
# Then: OIDC_PRIVATE_KEY=$(cat private_key.pem)
368+
OIDC_PRIVATE_KEY=
369+
370+
# Optional: Force SSL redirects (if not behind a reverse proxy handling SSL)
371+
FORCE_SSL=false
372+
```
373+
374+
Start Clinch:
375+
376+
```bash
377+
docker compose up -d
378+
```
379+
380+
**First Run:**
381+
1. Visit `http://localhost:3000` (or your configured domain)
382+
2. Complete the first-run wizard to create your admin account
383+
3. Configure applications and invite users
384+
385+
**Upgrading:**
386+
387+
```bash
388+
# Pull latest image
389+
docker compose pull
390+
391+
# Restart with new image (migrations run automatically)
392+
docker compose up -d
393+
```
394+
395+
**Logs:**
396+
397+
```bash
398+
# View logs
399+
docker compose logs -f clinch
400+
401+
# View last 100 lines
402+
docker compose logs --tail=100 clinch
324403
```
325404

326405
### Backup & Restore
@@ -351,9 +430,9 @@ sqlite3 storage/production.sqlite3 "VACUUM INTO 'backup-$(date +%Y%m%d).sqlite3'
351430
# 2. Backup uploaded files (ActiveStorage files are immutable)
352431
tar -czf uploads-backup-$(date +%Y%m%d).tar.gz storage/uploads/
353432
354-
# Docker equivalent
355-
docker exec clinch sqlite3 /rails/storage/production.sqlite3 "VACUUM INTO '/rails/storage/backup-$(date +%Y%m%d).sqlite3';"
356-
docker exec clinch tar -czf /rails/storage/uploads-backup-$(date +%Y%m%d).tar.gz /rails/storage/uploads/
433+
# Docker Compose equivalent
434+
docker compose exec clinch sqlite3 /rails/storage/production.sqlite3 "VACUUM INTO '/rails/storage/backup-$(date +%Y%m%d).sqlite3';"
435+
docker compose exec clinch tar -czf /rails/storage/uploads-backup-$(date +%Y%m%d).tar.gz /rails/storage/uploads/
357436
```
358437

359438
**Restore:**
@@ -380,13 +459,13 @@ sqlite3 /host/path/production.sqlite3 "VACUUM INTO '/host/path/backup-$(date +%Y
380459
rsync -av /host/path/backup-*.sqlite3 /host/path/uploads/ remote:/backups/clinch/
381460
```
382461

383-
b) **Docker volumes** (e.g., `-v clinch_storage:/rails/storage`):
462+
b) **Docker volumes** (e.g., using named volumes in compose):
384463
```bash
385464
# Database backup (safe while running)
386-
docker exec clinch sqlite3 /rails/storage/production.sqlite3 "VACUUM INTO '/rails/storage/backup.sqlite3';"
465+
docker compose exec clinch sqlite3 /rails/storage/production.sqlite3 "VACUUM INTO '/rails/storage/backup.sqlite3';"
387466
388467
# Copy out of container
389-
docker cp clinch:/rails/storage/backup.sqlite3 ./backup-$(date +%Y%m%d).sqlite3
468+
docker compose cp clinch:/rails/storage/backup.sqlite3 ./backup-$(date +%Y%m%d).sqlite3
390469
```
391470

392471
**Option 2: While Stopped (Offline Backup)**
@@ -411,35 +490,7 @@ docker compose up -d
411490

412491
## Configuration
413492

414-
### Environment Variables
415-
416-
Create a `.env` file (see `.env.example`):
417-
418-
```bash
419-
# Rails
420-
SECRET_KEY_BASE=generate-with-bin-rails-secret
421-
RAILS_ENV=production
422-
423-
# Database
424-
# SQLite database stored in storage/ directory (Docker volume mount point)
425-
426-
# SMTP (for sending emails)
427-
SMTP_ADDRESS=smtp.example.com
428-
SMTP_PORT=587
429-
SMTP_DOMAIN=example.com
430-
SMTP_USERNAME=your-username
431-
SMTP_PASSWORD=your-password
432-
SMTP_AUTHENTICATION=plain
433-
SMTP_ENABLE_STARTTLS=true
434-
435-
# Application
436-
CLINCH_HOST=https://auth.example.com
437-
CLINCH_FROM_EMAIL=noreply@example.com
438-
439-
# OIDC (optional - generates temporary key in development)
440-
# Generate with: openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
441-
OIDC_PRIVATE_KEY=<contents-of-private-key.pem>
442-
```
493+
All configuration is handled via environment variables (see the `.env` file in the Docker Compose section above).
443494

444495
### First Run
445496
1. Visit Clinch at `http://localhost:3000` (or your configured domain)

app/controllers/invitations_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class InvitationsController < ApplicationController
33

44
allow_unauthenticated_access
55
before_action :set_user_by_invitation_token, only: %i[show update]
6+
rate_limit to: 10, within: 10.minutes, only: :update, with: -> { redirect_to signin_path, alert: "Too many attempts. Try again later." }
67

78
def show
89
# Show the password setup form

app/controllers/passwords_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ class PasswordsController < ApplicationController
22
allow_unauthenticated_access
33
before_action :set_user_by_token, only: %i[edit update]
44
rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_password_path, alert: "Try again later." }
5+
rate_limit to: 10, within: 10.minutes, only: :update, with: -> { redirect_to new_password_path, alert: "Too many attempts. Try again later." }
56

67
def new
78
end

docs/beta-checklist.md

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ This checklist ensures Clinch meets security, quality, and documentation standar
153153
### Deployment
154154
- [x] Docker support
155155
- [x] Docker Compose example
156-
- [ ] Production deployment guide
156+
- [x] Production deployment guide (Docker Compose with .env configuration, upgrading, logs)
157157
- [x] Backup and restore documentation
158158

159159
## Security Hardening
@@ -165,10 +165,13 @@ This checklist ensures Clinch meets security, quality, and documentation standar
165165
- [x] Referrer-Policy (strict-origin-when-cross-origin in production config)
166166

167167
### Rate Limiting
168-
- [ ] Login attempt rate limiting
169-
- [ ] API endpoint rate limiting
170-
- [ ] Token endpoint rate limiting
171-
- [ ] Password reset rate limiting
168+
- [x] Login attempt rate limiting (20/3min on sessions#create)
169+
- [x] TOTP verification rate limiting (10/3min on sessions#verify_totp)
170+
- [x] WebAuthn rate limiting (10/1min on webauthn endpoints, 10/3min on session endpoints)
171+
- [x] Password reset rate limiting (10/3min on request, 10/10min on completion)
172+
- [x] Invitation acceptance rate limiting (10/10min)
173+
- [x] OAuth token endpoint rate limiting (60/1min on token, 30/1min on authorize)
174+
- [x] Backup code rate limiting (5 failed attempts per hour, model-level)
172175

173176
### Secrets Management
174177
- [x] No secrets in code
@@ -222,15 +225,15 @@ To move from "experimental" to "Beta", the following must be completed:
222225
- [x] All tests passing
223226
- [x] Core features implemented and tested
224227
- [x] Basic documentation complete
228+
- [x] Backup/restore documentation
229+
- [x] Production deployment guide
225230
- [ ] At least one external security review or penetration test
226-
- [ ] Production deployment guide
227-
- [ ] Backup/restore documentation
228231

229232
**Important (Should have for Beta):**
230-
- [ ] Rate limiting on auth endpoints
231-
- [ ] Security headers configuration documented
233+
- [x] Rate limiting on auth endpoints
234+
- [x] Security headers configuration documented (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy)
235+
- [x] Known limitations documented (ForwardAuth same-domain requirement in README)
232236
- [ ] Admin audit logging
233-
- [ ] Known limitations documented
234237

235238
**Nice to have (Can defer to post-Beta):**
236239
- [ ] Bug bounty program
@@ -250,16 +253,12 @@ To move from "experimental" to "Beta", the following must be completed:
250253

251254
**Before Beta Release:**
252255
- 🔶 External security review recommended
253-
- 🔶 Rate limiting implementation needed
254-
- 🔶 Production deployment documentation
255-
- 🔶 Security hardening checklist completion
256+
- 🔶 Admin audit logging (optional)
256257

257258
**Recommendation:** Consider Beta status after:
258259
1. External security review or penetration testing
259-
2. Rate limiting implementation
260-
3. Production hardening documentation
261-
4. 1-2 months of real-world testing
260+
2. Real-world testing period
262261

263262
---
264263

265-
Last updated: 2026-01-01
264+
Last updated: 2026-01-02

0 commit comments

Comments
 (0)