From a4ed1ec6d6960a1bec4248835e44c5605645e077 Mon Sep 17 00:00:00 2001 From: Joerg Date: Fri, 16 Jan 2026 08:22:37 +0100 Subject: [PATCH] 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 --- .env.example | 22 +++++++++ README.md | 93 +++++++++++++++++++++++++++++++++-- package.json | 2 + src/backend/index.js | 10 +++- src/frontend/src/lib/api.js | 6 +-- src/frontend/svelte.config.js | 7 ++- 6 files changed, 130 insertions(+), 10 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..4abc3e3 --- /dev/null +++ b/.env.example @@ -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 diff --git a/README.md b/README.md index d3aab0d..79f27fb 100644 --- a/README.md +++ b/README.md @@ -87,13 +87,28 @@ cd award bun install ``` -3. Set up environment variables (optional): -Create a `.env` file in the project root: -```env -JWT_SECRET=your-secret-key-here +3. Set up environment variables: +Create a `.env` file in the project root (copy from `.env.example`): +```bash +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: ```bash @@ -217,6 +232,74 @@ In production, you can either: 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 +## 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= +NODE_ENV=production +``` + ## Features in Detail ### Background Job Queue diff --git a/package.json b/package.json index b316242..d63de8c 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "dev": "bun run src/backend/index.js & cd src/frontend && bun run dev", "dev:backend": "bun run src/backend/index.js", "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:push": "drizzle-kit push", "db:migrate": "drizzle-kit migrate" diff --git a/src/backend/index.js b/src/backend/index.js index d30454e..b2e6f71 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -25,10 +25,18 @@ import { * Main backend application * 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() // Enable CORS for frontend communication .use(cors({ - origin: true, // Allow all origins in development + origin: ALLOWED_ORIGINS, credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], })) diff --git a/src/frontend/src/lib/api.js b/src/frontend/src/lib/api.js index 7208c3a..31ff0ed 100644 --- a/src/frontend/src/lib/api.js +++ b/src/frontend/src/lib/api.js @@ -1,10 +1,10 @@ import { browser } from '$app/environment'; /** - * API base URL - proxied through SvelteKit dev server - * In production, this will be relative to the same origin + * API base URL - configurable via environment variable + * 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 diff --git a/src/frontend/svelte.config.js b/src/frontend/svelte.config.js index 326a0ad..a49aeb5 100644 --- a/src/frontend/svelte.config.js +++ b/src/frontend/svelte.config.js @@ -4,9 +4,14 @@ import adapter from '@sveltejs/adapter-auto'; const config = { kit: { 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 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'] } } };