Self-Hosting Guide
Deploy Eryxon Flow on your own infrastructure with full control.
Current documented release:
0.3.3
Quick Start (Recommended)
Section titled “Quick Start (Recommended)”The fastest way to get production-ready deployment using our automated script.
Prerequisites
Section titled “Prerequisites”- Node.js 20+
- Git
- A Supabase project (supabase.com - free tier available)
- Your Supabase credentials
One-Command Setup
Section titled “One-Command Setup”# Clone the repositorygit clone https://github.com/SheetMetalConnect/eryxon-flow.gitcd eryxon-flow
# Create your .env file (the automated script requires it)cp .env.example .env# Edit .env and fill in your Supabase credentials (URL, anon key, project ID)
# Set your database passwordexport SUPABASE_DB_PASSWORD='your-database-password'
# Run automated setupchmod +x scripts/automate_self_hosting.sh./scripts/automate_self_hosting.shThe script will automatically:
- Install required dependencies (Node.js packages)
- Install Supabase CLI globally (if not present)
- Fix configuration issues
- Link your Supabase project
- Apply database migrations (schema + seed)
- Deploy all Edge Functions
- Run verification checks
Start Development Server
Section titled “Start Development Server”npm run dev# Open http://localhost:5173First User Setup
Section titled “First User Setup”- Navigate to the application
- Click Sign Up
- Enter email and password
- First user automatically becomes admin with a new tenant
Manual Setup (Step by Step)
Section titled “Manual Setup (Step by Step)”Use this for custom configurations or troubleshooting.
1. Create Supabase Project
Section titled “1. Create Supabase Project”- Go to supabase.com → New Project
- Save these credentials from Settings → API:
- Project URL:
https://yourproject.supabase.co - Project ID: The subdomain (e.g.,
yourproject) - Anon key: Public key for frontend
- Service role key: Secret key for backend
- Database password: From project creation
- Project URL:
2. Configure Environment
Section titled “2. Configure Environment”# Copy example filecp .env.example .envEdit .env:
VITE_SUPABASE_URL="https://yourproject.supabase.co"VITE_SUPABASE_PUBLISHABLE_KEY="your-anon-key"VITE_SUPABASE_PROJECT_ID="yourproject"
# Optional: For database scriptsSUPABASE_SERVICE_ROLE_KEY="your-service-role-key"SUPABASE_DB_PASSWORD="your-database-password"3. Link Supabase Project
Section titled “3. Link Supabase Project”# Install Supabase CLInpm install -g supabase
# Login and linksupabase loginsupabase link --project-ref yourproject4. Apply Database Schema
Section titled “4. Apply Database Schema”# Push all migrationssupabase db push
# Verify migrations appliedsupabase migration list5. Run Seed SQL
Section titled “5. Run Seed SQL”Creates storage buckets, RLS policies, and cron jobs:
# Option A: Using Supabase CLIsupabase db execute --file supabase/seed.sql
# Option B: Via Dashboard# Go to SQL Editor, paste seed.sql content, and execute6. Deploy Edge Functions
Section titled “6. Deploy Edge Functions”# Deploy all functionssupabase functions deploy
# Set required secretssupabase secrets set \ SUPABASE_URL="https://yourproject.supabase.co" \ SUPABASE_SERVICE_ROLE_KEY="your-service-role-key" \ SELF_HOSTED_MODE="true"
SELF_HOSTED_MODEindicates deployment mode to theplan-modeedge function (used for UI messaging only). It does not disable plan limits. Unlimited operations are achieved by setting the tenant’splanfield in the database toenterprisewithnulllimit columns — the app treatsnullas unlimited. Valid plan values are:free,pro,premium,enterprise.
7. Configure signup notification webhook
Section titled “7. Configure signup notification webhook”Release 0.3.3 keeps the signup notification path free of hardcoded project-specific SQL webhook URLs. Configure this in Supabase Dashboard so the setup stays portable across environments:
- Open Database -> Webhooks
- Create a webhook named
notify-new-signup - Table:
public.profiles - Event:
INSERT - Type:
Supabase Edge Function - Edge Function:
notify-new-signup - Filter:
record.role = 'admin' AND record.has_email_login = true
This is required only if you want admin signup email notifications.
8. Install and Run
Section titled “8. Install and Run”# Install dependenciesnpm ci
# Development modenpm run dev
# Production buildnpm run buildnpm run previewDocker Deployment (Production)
Section titled “Docker Deployment (Production)”Using Pre-built Image
Section titled “Using Pre-built Image”# Pull latest imagedocker pull ghcr.io/sheetmetalconnect/eryxon-flow:latest
# Run containerdocker run -d \ -p 80:80 \ --name eryxon-flow \ --restart unless-stopped \ ghcr.io/sheetmetalconnect/eryxon-flow:latestNote: Pre-built images have demo Supabase credentials. For production, build your own image.
Build Custom Image
Section titled “Build Custom Image”docker build \ --build-arg VITE_SUPABASE_URL="https://yourproject.supabase.co" \ --build-arg VITE_SUPABASE_PUBLISHABLE_KEY="your-anon-key" \ --build-arg VITE_SUPABASE_PROJECT_ID="yourproject" \ -t eryxon-flow .
docker run -d -p 80:80 --name eryxon-flow eryxon-flowDocker Compose (Recommended)
Section titled “Docker Compose (Recommended)”The repository ships with a ready-to-use docker-compose.yml. To use the pre-built image:
docker compose up -dTo build a custom image with your own Supabase credentials baked in, replace the image line in docker-compose.yml with a build block:
services: eryxon-flow: # Replace this: # image: ghcr.io/sheetmetalconnect/eryxon-flow:latest # With this: build: context: . args: VITE_SUPABASE_URL: ${VITE_SUPABASE_URL} VITE_SUPABASE_PUBLISHABLE_KEY: ${VITE_SUPABASE_PUBLISHABLE_KEY} VITE_SUPABASE_PROJECT_ID: ${VITE_SUPABASE_PROJECT_ID} container_name: eryxon-flow restart: unless-stopped ports: - "80:80" healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"] interval: 30s timeout: 10s retries: 3Make sure the corresponding VITE_SUPABASE_* variables are set in your .env file (Docker Compose reads .env automatically).
Then rebuild and start:
docker compose up -d --buildDocker Compose with SSL (Production)
Section titled “Docker Compose with SSL (Production)”The repository includes docker-compose.prod.yml with Caddy reverse proxy for automatic HTTPS:
services: app: image: ghcr.io/sheetmetalconnect/eryxon-flow:latest container_name: eryxon-flow restart: unless-stopped expose: - "80" healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"] interval: 30s timeout: 10s retries: 3
caddy: image: caddy:alpine container_name: caddy restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config depends_on: - app
volumes: caddy_data: caddy_config:Edit the included Caddyfile — replace the domain with yours:
your-domain.com { reverse_proxy app:80
header { X-Frame-Options "DENY" X-Content-Type-Options "nosniff" X-XSS-Protection "1; mode=block" Referrer-Policy "strict-origin-when-cross-origin" }}Save the above Docker Compose configuration as docker-compose.prod.yml, then deploy:
docker compose -f docker-compose.prod.yml up -dCloudflare Pages Deployment
Section titled “Cloudflare Pages Deployment”Best for edge deployment with global CDN.
-
Connect Repository
- Go to Cloudflare Pages
- Create a project → Connect your Git repository
-
Configure Build
- Build command:
npm run build - Output directory:
dist
- Build command:
-
Set Environment Variables
Terminal window VITE_SUPABASE_URL=https://yourproject.supabase.coVITE_SUPABASE_PUBLISHABLE_KEY=your-anon-keyVITE_SUPABASE_PROJECT_ID=yourproject -
Deploy
- Cloudflare handles SSL, CDN, and global distribution automatically
Optional Enhancements
Section titled “Optional Enhancements”Email Notifications (Resend)
Section titled “Email Notifications (Resend)”Enable automated email invitations and admin signup notifications:
supabase secrets set \ RESEND_API_KEY="re_your_api_key" \ APP_URL="https://your-domain.com" \ EMAIL_FROM="Eryxon <noreply@your-domain.com>" \ SIGNUP_NOTIFY_EMAIL="admin@your-domain.com"
SIGNUP_NOTIFY_EMAILis the address that receives notifications when a new company signs up. Required for thenotify-new-signupedge function to send emails.
Cloudflare Turnstile (CAPTCHA)
Section titled “Cloudflare Turnstile (CAPTCHA)”Add bot protection to auth forms:
- Create widget at Cloudflare Turnstile
- Add to
.env:Terminal window VITE_TURNSTILE_SITE_KEY="your-site-key" - Configure secret key in Supabase Authentication → Captcha Protection
- On Vercel, keep the repo
vercel.jsonso SPA rewrites and CSP headers continue to allowhttps://challenges.cloudflare.com
Redis Caching (Upstash)
Section titled “Redis Caching (Upstash)”Improve Edge Function performance:
supabase secrets set \ UPSTASH_REDIS_REST_URL="https://your-redis.upstash.io" \ UPSTASH_REDIS_REST_TOKEN="your-token"3D STEP Viewer & CAD Processing
Section titled “3D STEP Viewer & CAD Processing”The built-in 3D STEP viewer works out of the box using browser-based WASM parsing (occt-import-js). No server-side CAD service is required.
How it works: STEP/STP files uploaded to the parts-cad storage bucket are parsed client-side using WebAssembly. The viewer supports orbit controls, exploded view, wireframe mode, and measurement tools (distance, angle, radius).
CSP requirements: The STEP parser needs specific Content Security Policy directives. These are already configured in the shipped index.html and vercel.json, but if your reverse proxy (Nginx, Caddy, Cloudflare) adds its own CSP headers, make sure they include:
script-src 'self' 'unsafe-eval' 'wasm-unsafe-eval' https://cdn.jsdelivr.net;worker-src 'self' blob:;| Directive | Reason |
|---|---|
'unsafe-eval' | Emscripten embind (occt-import-js) uses new Function() |
'wasm-unsafe-eval' | Explicit WASM compilation permission |
https://cdn.jsdelivr.net | CDN host for the occt-import-js library |
worker-src blob: | occt-import-js creates Web Workers from blob URLs |
Note: The default Nginx and Caddy configs shipped with this repo do not set CSP headers (they rely on the
<meta>tag inindex.html), so you only need to worry about this if you add custom CSP rules at the proxy level.
Optional: Server-side CAD processing
For server-side geometry extraction and PMI (Product Manufacturing Information) data, configure an external CAD service:
VITE_CAD_SERVICE_URL="https://your-cad-service.example.com"VITE_CAD_SERVICE_API_KEY="your-api-key"If not configured, browser-based processing is used automatically. The viewer supports three backend modes: custom (Eryxon3D Docker), byob (Bring Your Own Backend), and frontend (browser-only, the default).
MCP Server (Optional - Local Use Only)
Section titled “MCP Server (Optional - Local Use Only)”The MCP server is NOT part of the deployment stack. It’s an optional local tool for Claude Desktop integration.
What it does:
- Allows Claude Desktop to interact with your database using natural language
- Provides 55 tools for managing jobs, parts, operations via AI
Quick start:
cd mcp-servernpm install && npm run buildexport SUPABASE_URL="https://your-project.supabase.co"export SUPABASE_SERVICE_KEY="your-service-key"npm startComplete setup instructions: See MCP Setup Guide for:
- Local development setup
- Cloud deployment (Railway, Fly.io, Docker)
- Claude Desktop configuration
- All 55 available tools
Note: Your self-hosted application works perfectly without the MCP server. It’s only for developers who want AI assistant integration via Claude Desktop.
Verification
Section titled “Verification”Run the verification script to check your setup:
bash scripts/verify-setup.shChecks:
- ✅ Environment variables
- ✅ Supabase connectivity
- ✅ Database tables
- ✅ Storage buckets (see note below)
- ✅ Dependencies
- ✅ Production build
Note: Storage bucket check may report FAIL (HTTP 400) even when buckets exist. This is expected because the buckets are private (
public: false) and the verification script uses the Anon Key, which cannot list private buckets. Verify manually via SQL:SELECT * FROM storage.buckets;Required buckets:
parts-images,issues,parts-cad,batch-images
Updating Your Deployment
Section titled “Updating Your Deployment”Pull Latest Changes
Section titled “Pull Latest Changes”git pull origin mainnpm ciUpdate Database
Section titled “Update Database”supabase db pushsupabase functions deployRebuild Application
Section titled “Rebuild Application”npm run build
# For Docker:docker compose build --no-cachedocker compose up -dSecurity Checklist
Section titled “Security Checklist”-
.envfile is in.gitignore(never commit) - Service role key is kept secret
- Database password is strong (16+ characters)
- RLS policies are applied (via migrations)
- Storage bucket policies restrict access properly
- HTTPS is enabled in production (use Caddy or Cloudflare)
Troubleshooting
Section titled “Troubleshooting”For deployment-specific issues (migrations, edge functions, storage, STEP viewer CSP), see the Troubleshooting Guide.