-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path.env.example
More file actions
264 lines (219 loc) · 14.1 KB
/
.env.example
File metadata and controls
264 lines (219 loc) · 14.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# ─────────────────────────────────────────────────────────────────────────────
# Federated Hosting — Environment Variables
# Copy this file to .env and fill in your values.
# Never commit .env to version control.
# ─────────────────────────────────────────────────────────────────────────────
# ── Database (required) ───────────────────────────────────────────────────────
# PostgreSQL connection string
DATABASE_URL=postgresql://user:password@localhost:5432/fedhosting
# ── Object Storage (required) ─────────────────────────────────────────────────
# Bucket name / ID for storing uploaded site files
DEFAULT_OBJECT_STORAGE_BUCKET_ID=your-bucket-id
# Path prefix for private uploads within the bucket
PRIVATE_OBJECT_DIR=private
# Comma-separated path prefixes for publicly readable objects
PUBLIC_OBJECT_SEARCH_PATHS=public
# ── Application (optional) ────────────────────────────────────────────────────
# Set to "production" for JSON-structured logs and no stack traces in errors
NODE_ENV=development
# API server port (default: 8080)
PORT=8080
# Log level: trace | debug | info | warn | error (default: info)
LOG_LEVEL=info
# ── Authentication (required) ─────────────────────────────────────────────────
# OIDC issuer URL — your identity provider's discovery endpoint
# Examples:
# Authentik: https://auth.yourdomain.com/application/o/fedhost/
# Keycloak: https://auth.yourdomain.com/realms/fedhost
# Auth0: https://your-tenant.us.auth0.com/
# Dex: https://dex.yourdomain.com
ISSUER_URL=https://auth.yourdomain.com/application/o/fedhost/
# OIDC client ID — registered with your identity provider
OIDC_CLIENT_ID=your-client-id
# ── Node Identity (optional) ──────────────────────────────────────────────────
# Display name for this node in the federation network
NODE_NAME=My FedHost Node
# Geographic region (follows AWS naming: ap-southeast-3, eu-west-1, us-east-1 …)
# Indonesia: ap-southeast-3 | Singapore: ap-southeast-1 | US East: us-east-1
NODE_REGION=ap-southeast-3
# Operator contact information (shown in /.well-known/federation)
OPERATOR_NAME=Node Operator
OPERATOR_EMAIL=admin@example.com
# Advertised storage capacity in GB
STORAGE_CAPACITY_GB=100
# Advertised bandwidth capacity in GB
BANDWIDTH_CAPACITY_GB=1000
# ── Public Domain (required for federation) ───────────────────────────────────
# The public hostname where this node is reachable by other nodes.
# Other nodes will attempt to handshake with you at https://<PUBLIC_DOMAIN>/
PUBLIC_DOMAIN=node.yourdomain.com
# Comma-separated list of allowed CORS origins (defaults to * in development)
ALLOWED_ORIGINS=https://node.yourdomain.com
# ── Webhooks (optional) ───────────────────────────────────────────────────────
# Comma-separated webhook URLs to receive event notifications.
# Deliveries are Ed25519-signed with X-FedHost-Signature.
# Events: node_offline, node_online, deploy, deploy_failed, new_peer
# Example: https://hooks.slack.com/services/xxx,https://api.example.com/webhook
WEBHOOK_URLS=
# ── Geographic Routing (optional) ─────────────────────────────────────────────
# Set to "true" to enable automatic 302 redirects to the closest federation node.
# Requires multiple active peers in different regions to have any effect.
# Reads region from: Fly-Region, CF-IPCountry, CloudFront-Viewer-Country headers.
ENABLE_GEO_ROUTING=false
# ── TLS / ACME (optional) ─────────────────────────────────────────────────────
# Set to "true" to enable automatic Let's Encrypt certificate provisioning.
# Requires this node to be publicly reachable on port 80 for HTTP-01 challenges.
# If false (default), TLS must be handled by Caddy, nginx + certbot, or similar.
ACME_ENABLED=false
# Email address for Let's Encrypt account registration (required if ACME_ENABLED=true)
ACME_EMAIL=admin@example.com
# Directory where Let's Encrypt stores certificates (default: /etc/letsencrypt/live)
ACME_CERT_DIR=/etc/letsencrypt/live
# ── Database Pool (optional) ──────────────────────────────────────────────────
# Tune for your deployment. Defaults shown.
# For connection pooling (PgBouncer / managed DB pooler), set max lower.
DB_POOL_MAX=20
DB_POOL_MIN=2
DB_IDLE_TIMEOUT_MS=30000
DB_CONNECT_TIMEOUT_MS=5000
# ── Security ──────────────────────────────────────────────────────────────────
# Secret for HMAC-signing unlock cookies for password-protected sites.
# Use a long random string: openssl rand -base64 32
# Required in production. Generate: openssl rand -base64 32
COOKIE_SECRET=your-secret-here
# ── Admin / RBAC ──────────────────────────────────────────────────────────────
# Comma-separated user IDs that have admin access (no DB change needed).
# Get your user ID from GET /api/auth/user after signing in.
# You can also set users.is_admin = 1 in the database directly.
ADMIN_USER_IDS=
# ── Object Storage (S3-compatible) ───────────────────────────────────────────
# Set these to use AWS S3, Cloudflare R2, MinIO, Backblaze B2, etc.
#
# For MinIO (Docker Compose): OBJECT_STORAGE_ENDPOINT=http://minio:9000
# For Cloudflare R2: OBJECT_STORAGE_ENDPOINT=https://<account>.r2.cloudflarestorage.com
# For AWS S3: leave OBJECT_STORAGE_ENDPOINT unset (uses default AWS endpoint)
OBJECT_STORAGE_ENDPOINT=
OBJECT_STORAGE_ACCESS_KEY=
OBJECT_STORAGE_SECRET_KEY=
OBJECT_STORAGE_REGION=us-east-1
OBJECT_STORAGE_BUCKET=fedhost-sites
# ── Host Router Cache ─────────────────────────────────────────────────────────
# TTL in milliseconds for domain → site ID cache (default: 5 minutes)
# Lower = faster invalidation, more DB queries. Higher = fewer queries, slower invalidation.
DOMAIN_CACHE_TTL_MS=300000
DOMAIN_CACHE_MAX=10000
FILE_CACHE_MAX=50000
# ── Object Storage — S3/MinIO ────────────────────────────────────────────────────
# Set these to use any S3-compatible provider (AWS, Cloudflare R2, MinIO, etc.)
# Required when using S3/MinIO storage.
OBJECT_STORAGE_ENDPOINT=http://localhost:9000
OBJECT_STORAGE_ACCESS_KEY=your-access-key
OBJECT_STORAGE_SECRET_KEY=your-secret-key
OBJECT_STORAGE_REGION=us-east-1
# ── Admin / RBAC ───────────────────────────────────────────────────────────────
# Comma-separated list of user IDs that have admin access.
# Used to bootstrap the first admin without touching the database.
# After initial setup, prefer setting users.is_admin = 1 directly.
ADMIN_USER_IDS=
# ── Caching (optional) ─────────────────────────────────────────────────────────
# Domain lookup cache TTL in milliseconds (default: 300000 = 5 minutes)
DOMAIN_CACHE_TTL_MS=300000
# Max domain cache entries (default: 10000)
DOMAIN_CACHE_MAX=10000
# Max file cache entries (default: 50000)
FILE_CACHE_MAX=50000
# ── Redis (strongly recommended for production) ───────────────────────────────
# Without Redis, rate limiting is per-process only (broken in multi-instance).
# Redis also enables future session sharing and cache invalidation pub/sub.
# Format: redis://[:password@]host[:port][/db-number]
# Example: redis://redis:6379 (Docker Compose default)
# Example: redis://user:pass@managed-redis.example.com:6380
REDIS_URL=redis://redis:6379
# ── ACME Challenge Type (optional) ───────────────────────────────────────────
# http (default) — HTTP-01, requires port 80 reachable from Let's Encrypt
# dns — DNS-01, works behind NAT/firewalls, supports wildcards
# See docs/TLS.md for DNS-01 provider hook setup.
ACME_CHALLENGE_TYPE=http
# DNS propagation wait in milliseconds (DNS-01 only, default: 30000)
ACME_DNS_PROPAGATION_WAIT=30000
# ── Site Health Monitoring (optional) ─────────────────────────────────────────
# Set to "true" to enable periodic health checks of all public hosted sites.
# Checks run every 10 minutes by default. Results available at GET /api/admin/site-health.
ENABLE_SITE_HEALTH_CHECKS=false
# How often to check site health in milliseconds (default: 600000 = 10 minutes)
SITE_HEALTH_CHECK_INTERVAL_MS=600000
# ── Email Notifications (optional) ────────────────────────────────────────────
# Configure SMTP to send transactional emails:
# deploy success/failed, certificate expiry, node offline, invitations
# Leave blank to disable email (invitations still work, just no email sent).
#
# Works with any SMTP provider:
# Resend: SMTP_HOST=smtp.resend.com SMTP_USER=resend SMTP_PASS=re_xxx
# Postmark: SMTP_HOST=smtp.postmarkapp.com
# SendGrid: SMTP_HOST=smtp.sendgrid.net
# AWS SES: SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_HOST=
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=
SMTP_PASS=
# From address for outgoing emails
EMAIL_FROM=noreply@your-domain.com
EMAIL_FROM_NAME=FedHost
# ── Data Retention ────────────────────────────────────────────────────────────
# Cleanup job runs every 6 hours and prunes old data. Adjust retention windows:
ANALYTICS_RETENTION_DAYS=90
FORM_RETENTION_DAYS=365
AUDIT_LOG_RETENTION_DAYS=365
# ── Dynamic Site Hosting (NLPL / Node.js process management) ──────────────────
# Path to the NLPL interpreter (src/main.py in the NLPL repo).
# Install: git clone https://github.com/Zajfan/NLPL /opt/nlpl
NLPL_INTERPRETER_PATH=/opt/nlpl/src/main.py
# Python executable used to run the NLPL interpreter
PYTHON_BIN=python3
# Port range allocated to dynamic site processes.
# Each running site gets one port from this range.
# Ensure these ports are NOT exposed externally — only the Node proxy accesses them.
DYNAMIC_PORT_START=9000
DYNAMIC_PORT_END=9999
# Maximum restarts before a crashed process is abandoned (default: 5)
DYNAMIC_MAX_RESTARTS=5
# ── Low-Resource Mode (Raspberry Pi / volunteer nodes) ────────────────────────
# Set to "true" on constrained hardware to reduce memory and CPU usage.
# All features remain available — throughput is reduced but federation works.
# Typical hardware: Raspberry Pi 3/4, old laptops, 512MB-1GB RAM VMs.
#
# What changes with LOW_RESOURCE=true:
# DB pool connections: 20 → 5
# Domain LRU cache: 10 000 → 500 entries
# File LRU cache: 50 000 → 2 000 entries
# Analytics flush: 1 min → 5 min
# Health check: 2 min → 10 min
# Log level: info → warn
# Global rate limit: 300 → 60 req/min
# Compression: level 6 → level 1 (fastest)
LOW_RESOURCE=false
# ── Static-only mode (federation safety) ─────────────────────────────────────
# Set to "true" to disable dynamic site hosting (NLPL, Node.js, Python).
# Recommended for:
# - Volunteer nodes that only want to serve static sites
# - Nodes in high-trust federation networks where dynamic execution is risky
# - Nodes with very limited resources (no spare CPU for process management)
#
# When enabled:
# - POST /api/sites with siteType nlpl/dynamic/node/python → 400 error
# - POST /api/sites/:id/nlpl/start → 400 error with clear message
# - Federation meta endpoint advertises capabilities: ["static"] (no "dynamic")
# - Dashboard shows a banner on dynamic site pages
#
# Does NOT affect:
# - Already-registered dynamic sites (they just can't be started)
# - The build pipeline (git clone + npm build → static output is fine)
# - Federation replication of static sites from other nodes
FEDERATED_STATIC_ONLY=false
# ── Frontend node region hint (i18n) ─────────────────────────────────────────
# Injected into index.html as <meta name="fh-node-region">.
# Used by the frontend to default to Bahasa Indonesia for Southeast Asian nodes.
# Set to your node's AWS-style region (same value as NODE_REGION).
# Example: ap-southeast-3 (Jakarta) will default the UI to Bahasa Indonesia.
VITE_NODE_REGION=${NODE_REGION:-}