Server Deployment Guide
This guide covers deploying and running the Roomz server.
Server Entry Points
Roomz provides two entry points:
Command |
Description |
|---|---|
|
Start the chat server (from installed package) |
|
Start the CLI client |
Running the Server
Development Mode
# Using the installed command
roomz
# Or directly with uvicorn (hot reload)
uvicorn app:asgi_app --reload --host 0.0.0.0 --port 8000
Production Mode
# Using gunicorn with uvicorn workers
gunicorn -k uvicorn.workers.UvicornWorker app:asgi_app --bind 0.0.0.0:8000 --workers 4
# Or directly with uvicorn
uvicorn app:asgi_app --host 0.0.0.0 --port 8000
Environment Variables
Create a .env file or set environment variables:
# Required
export JWT_SECRET_KEY="your-256-bit-secret-key-here"
export ALLOWED_EMAILS="user1@example.com,user2@example.com"
# Email configuration
export EMAIL_SENDER="resend" # or "console" for development
export RESEND_API_KEY="re_your_api_key_here"
export EMAIL_FROM="noreply@yourdomain.com"
# Optional tuning
export JWT_EXPIRY_DAYS="30"
export MAGIC_LINK_EXPIRY_MINUTES="15"
export MAGIC_LINK_RATE_LIMIT="5"
Configuration Reference
Required Variables
JWT_SECRET_KEY
Secret key for signing JWT tokens.
Required: Yes
Min Length: 32 characters (256 bits)
Generate with:
python -c "import secrets; print(secrets.token_urlsafe(32))"
export JWT_SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
ALLOWED_EMAILS
Comma-separated list of email addresses allowed to authenticate.
Required: Yes
Format:
email1@example.com,email2@example.comCase-insensitive: Emails are normalized to lowercase
export ALLOWED_EMAILS="alice@example.com,bob@example.com"
Email Configuration
EMAIL_SENDER
Email sending method.
Values:
console(development) orresend(production)Default:
console
# Development - logs magic links to console
export EMAIL_SENDER=console
# Production - sends via Resend
export EMAIL_SENDER=resend
RESEND_API_KEY
API key for Resend email service.
Required: Only if
EMAIL_SENDER=resendGet from: resend.com
export RESEND_API_KEY=re_your_api_key_here
EMAIL_FROM
Sender email address for magic link emails.
Default:
no-reply@example.comRequired: No, but recommended for production
export EMAIL_FROM=noreply@yourdomain.com
Optional Variables
JWT_EXPIRY_DAYS
JWT token lifetime in days.
Default:
30Range: 1-365 days recommended
MAGIC_LINK_EXPIRY_MINUTES
Magic link validity period in minutes.
Default:
15Security: Shorter is more secure
MAGIC_LINK_RATE_LIMIT
Maximum magic link requests per email per hour.
Default:
5Security: Prevents spam
Integration into Other Applications
Quart Application
Roomz uses the Baseweb framework which is built on Quart. You can integrate Roomz into an existing Quart application:
from quart import Quart
from roomz.app import server
# Create your Quart app
app = Quart(__name__)
# Import Roomz components
# Note: This approach requires careful integration
# Or run Roomz as a separate service and use the client library
Using as a Library
For custom integrations, use the client library:
from roomz import AsyncClient
# Connect to a Roomz server
client = AsyncClient(server_url="https://chat.yourdomain.com")
await client.connect(token="your-magic-link")
Security Considerations
JWT Security
Secret Key: Use a strong, randomly-generated key (minimum 256 bits)
Algorithm: HS256 (hardcoded, not configurable)
Storage: httpOnly cookies prevent XSS access
SameSite: Strict prevents CSRF attacks
Magic Link Security
Single Use: Tokens are invalidated after first use
Short Lifetime: 15-minute default expiration
Rate Limited: 5 requests per email per hour
Hashed Storage: Tokens stored as SHA-256 hashes
CORS Configuration
For production with a separate frontend:
# In your Quart app configuration
# Note: Roomz uses Baseweb which handles CORS
# Configure allowed origins
ALLOWED_ORIGINS = ["https://yourdomain.com"]
Production Checklist
[ ] Set secure JWT_SECRET_KEY (256+ bits)
[ ] Configure ALLOWED_EMAILS for all users
[ ] Set EMAIL_SENDER=resend for production
[ ] Configure RESEND_API_KEY
[ ] Set EMAIL_FROM to your domain
[ ] Enable HTTPS (set cookie secure=True)
[ ] Configure rate limiting at reverse proxy level
[ ] Set up logging and monitoring
Reverse Proxy Configuration
Nginx
server {
listen 443 ssl http2;
server_name chat.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket timeout
proxy_read_timeout 86400;
}
Caddy
chat.yourdomain.com {
reverse_proxy localhost:8000 {
# WebSocket support
header_up Host {host}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
}
}
Monitoring and Logging
Roomz logs using Python’s standard logging module:
import logging
# Configure logging level
logging.basicConfig(level=logging.INFO)
Key log messages:
Client connected: {email}- User authenticatedClient disconnected: {email}- User disconnectedUser authenticated: {email}- Magic link verifiedMagic link created for {email}- Link sentRejected connection {sid}- Connection rejected
Scaling Considerations
Stateless Authentication
Roomz uses JWT tokens stored in httpOnly cookies, making the server stateless. This allows:
Multiple server instances behind a load balancer
Server restarts without losing sessions
Horizontal scaling
WebSocket Connections
For WebSocket scaling across multiple servers:
Use a Socket.IO Redis adapter
Configure sticky sessions at load balancer level
Consider connection limits per instance
Magic Link Storage
Magic links are stored in memory by default. For production scaling:
Replace in-memory storage with Redis
Implement distributed rate limiting
# Current: In-memory
from roomz.app.auth import magic_link_manager, magic_link_limiter
# For scaling: Implement Redis-backed versions
Troubleshooting
Common Issues
“JWT_SECRET_KEY environment variable must be set”
Set the environment variable:
export JWT_SECRET_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
“Failed to send magic link email”
Check your email configuration:
EMAIL_SENDER=consolefor developmentEMAIL_SENDER=resendrequires validRESEND_API_KEY
WebSocket connection fails
Check CORS configuration
Verify WebSocket support in reverse proxy
Check browser console for errors