Add hostname configuration for production deployment

Add environment variable configuration to support deployment on custom
domains like https://awards.dj7nt.de

## Changes
- Add .env.example with configuration template
- Update API client to use VITE_API_BASE_URL with fallback to /api
- Update SvelteKit config to use VITE_APP_URL for CSRF trusted origins
- Update backend CORS to use configurable allowed origins
- Add ALLOWED_ORIGINS environment variable for production
- Add build and preview scripts to package.json
- Update README with production deployment guide and nginx example

## Environment Variables
- VITE_APP_URL: Application hostname (e.g., https://awards.dj7nt.de)
- VITE_API_BASE_URL: API base URL (empty = relative paths)
- ALLOWED_ORIGINS: Comma-separated CORS origins
- JWT_SECRET: Strong secret for production
- NODE_ENV: development/production

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 08:22:37 +01:00
parent afe150f15c
commit a4ed1ec6d6
6 changed files with 130 additions and 10 deletions

22
.env.example Normal file
View File

@@ -0,0 +1,22 @@
# Application Configuration
# Copy this file to .env and update with your values
# Hostname for the application (e.g., https://awards.dj7nt.de)
# Leave empty for development (uses localhost)
VITE_APP_URL=
# API Base URL (in production, can be same domain or separate)
# Leave empty to use relative paths (recommended for same-domain deployment)
VITE_API_BASE_URL=
# Allowed CORS origins for backend (comma-separated)
# Only needed for production if not using same domain
# Example: https://awards.dj7nt.de,https://www.awards.dj7nt.de
ALLOWED_ORIGINS=
# JWT Secret (for production, use a strong random string)
# Generate with: openssl rand -base64 32
JWT_SECRET=change-this-in-production
# Node Environment
NODE_ENV=development

View File

@@ -87,13 +87,28 @@ cd award
bun install bun install
``` ```
3. Set up environment variables (optional): 3. Set up environment variables:
Create a `.env` file in the project root: Create a `.env` file in the project root (copy from `.env.example`):
```env ```bash
JWT_SECRET=your-secret-key-here cp .env.example .env
``` ```
If not provided, a default secret will be used. Edit `.env` with your configuration:
```env
# Application URL (for production deployment)
VITE_APP_URL=https://awards.dj7nt.de
# API Base URL (leave empty for same-domain deployment)
VITE_API_BASE_URL=
# JWT Secret (generate with: openssl rand -base64 32)
JWT_SECRET=your-generated-secret-here
# Environment
NODE_ENV=production
```
**For development**: You can leave `.env` empty or use defaults.
4. Initialize the database: 4. Initialize the database:
```bash ```bash
@@ -217,6 +232,74 @@ In production, you can either:
2. **Keep the proxy setup** with a proper reverse proxy (nginx, caddy) 2. **Keep the proxy setup** with a proper reverse proxy (nginx, caddy)
3. **Use SvelteKit adapter** for Node/Bun to serve everything from one process 3. **Use SvelteKit adapter** for Node/Bun to serve everything from one process
## Production Deployment
### Building for Production
```bash
# Build the frontend
bun run build
# Preview the production build locally
bun run preview
```
### Deployment Options
#### Option 1: Static Site + Backend Server
1. Build the frontend: `bun run build`
2. Serve `src/frontend/build/` with Elysia using `@elysiajs/static`
3. Backend runs on one port serving both frontend and API
#### Option 2: Reverse Proxy (Recommended)
Use nginx or Caddy to proxy:
- `/` → SvelteKit frontend (port 5173 or static files)
- `/api` → Elysia backend (port 3001)
**Example nginx configuration:**
```nginx
server {
server_name awards.dj7nt.de;
# Frontend
location / {
proxy_pass http://localhost:5173;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Backend API
location /api {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
#### Option 3: Single Process with SvelteKit Node Adapter
Use `@sveltejs/adapter-node` to build for Node/Bun:
- Everything runs in one process
- API routes handled by SvelteKit (need to migrate from Elysia)
### Environment Variables for Production
Make sure to set these in your production environment:
```bash
VITE_APP_URL=https://awards.dj7nt.de
VITE_API_BASE_URL= # Leave empty for same-domain
JWT_SECRET=<strong-random-string>
NODE_ENV=production
```
## Features in Detail ## Features in Detail
### Background Job Queue ### Background Job Queue

View File

@@ -7,6 +7,8 @@
"dev": "bun run src/backend/index.js & cd src/frontend && bun run dev", "dev": "bun run src/backend/index.js & cd src/frontend && bun run dev",
"dev:backend": "bun run src/backend/index.js", "dev:backend": "bun run src/backend/index.js",
"dev:frontend": "cd src/frontend && bun run dev", "dev:frontend": "cd src/frontend && bun run dev",
"build": "cd src/frontend && bun run build",
"preview": "cd src/frontend && bun run preview",
"db:generate": "drizzle-kit generate", "db:generate": "drizzle-kit generate",
"db:push": "drizzle-kit push", "db:push": "drizzle-kit push",
"db:migrate": "drizzle-kit migrate" "db:migrate": "drizzle-kit migrate"

View File

@@ -25,10 +25,18 @@ import {
* Main backend application * Main backend application
* Serves API routes * Serves API routes
*/ */
// Get allowed origins from environment or allow all in development
const ALLOWED_ORIGINS = process.env.ALLOWED_ORIGINS
? process.env.ALLOWED_ORIGINS.split(',')
: process.env.NODE_ENV === 'production'
? [process.env.VITE_APP_URL || 'https://awards.dj7nt.de']
: true; // Allow all in development
const app = new Elysia() const app = new Elysia()
// Enable CORS for frontend communication // Enable CORS for frontend communication
.use(cors({ .use(cors({
origin: true, // Allow all origins in development origin: ALLOWED_ORIGINS,
credentials: true, credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
})) }))

View File

@@ -1,10 +1,10 @@
import { browser } from '$app/environment'; import { browser } from '$app/environment';
/** /**
* API base URL - proxied through SvelteKit dev server * API base URL - configurable via environment variable
* In production, this will be relative to the same origin * Falls back to relative path for same-domain deployment
*/ */
const API_BASE = '/api'; const API_BASE = import.meta.env.VITE_API_BASE_URL || '/api';
/** /**
* Make an API request * Make an API request

View File

@@ -4,9 +4,14 @@ import adapter from '@sveltejs/adapter-auto';
const config = { const config = {
kit: { kit: {
adapter: adapter(), adapter: adapter(),
// Get app URL from environment or default to localhost
// This is used for production builds and CSRF configuration
// Set via VITE_APP_URL environment variable
// Disable origin checks in dev to prevent issues with browser extensions // Disable origin checks in dev to prevent issues with browser extensions
csrf: { csrf: {
trustedOrigins: process.env.NODE_ENV === 'production' ? undefined : ['http://localhost:5173', 'http://127.0.0.1:5173'] trustedOrigins: process.env.NODE_ENV === 'production'
? (process.env.VITE_APP_URL ? [new URL(process.env.VITE_APP_URL).origin] : undefined)
: ['http://localhost:5173', 'http://127.0.0.1:5173']
} }
} }
}; };