-
-
Notifications
You must be signed in to change notification settings - Fork 2
Nginx Generation
Nginx is the single entry point for all external traffic in a ɳSelf stack. Rather than asking you to write or maintain nginx configuration by hand, nself build generates the full nginx configuration automatically based on which services are enabled, what SSL mode you have selected, and which plugins are installed. The generated files are written to an nginx/ directory in your project root and are consumed by the nginx container at startup.
nginx/
├── nginx.conf ← Main config (auto-generated, do not edit)
├── conf.d/
│ └── default.conf ← HTTP→HTTPS redirect, /health endpoint
├── conf.d-dev/ ← Dev-specific overrides (auto-generated)
├── conf.d-prod/ ← Prod-specific overrides (auto-generated)
├── sites/ ← Auto-generated service routes (one .conf per service)
│ ├── hasura.conf
│ ├── auth.conf
│ ├── storage.conf
│ └── ...
├── includes/
│ └── rate-limits.conf ← Rate limiting zones
└── routes/ ← Plugin-generated routes
nginx.conf is the top-level entry point. It includes everything under conf.d/, conf.d-dev/ or conf.d-prod/ (depending on environment), sites/, includes/, and routes/. Never edit nginx.conf or anything under sites/ directly, those files are overwritten on every nself build.
Files in nginx/conf.d/ are hand-managed and safe to customize. The build system checks for conflicts and skips auto-generating a sites/ config if the same domain already exists in conf.d/. This lets you override a service route with a fully custom configuration without the build clobbering your changes.
For example, if you want to serve api.yourdomain.com with a custom caching policy or non-standard proxy settings, create a file in nginx/conf.d/ targeting that server name. On the next nself build, the generator will detect the conflict, skip writing nginx/sites/hasura.conf for that domain, and print a notice so you know the override is in effect.
Each enabled service gets its own subdomain. The base domain is controlled by the BASE_DOMAIN environment variable.
| Service | Subdomain | Notes |
|---|---|---|
| Hasura GraphQL | api.{BASE_DOMAIN} |
WebSocket support, 86400s read timeout |
| Auth | auth.{BASE_DOMAIN} |
Strict rate limiting (10 req/min) |
| MinIO API | storage.{BASE_DOMAIN} |
1000M max body size |
| MinIO Console | storage-console.{BASE_DOMAIN} |
|
| Admin dashboard | admin.{BASE_DOMAIN} |
Dev mode: proxies to host machine |
| Search | search.{BASE_DOMAIN} |
|
| Email UI | mail.{BASE_DOMAIN} |
|
| Grafana | grafana.{BASE_DOMAIN} |
|
| Prometheus | prometheus.{BASE_DOMAIN} |
|
| Alertmanager | alertmanager.{BASE_DOMAIN} |
Custom services get routes based on CS_N_ROUTE. Frontend apps get routes based on FRONTEND_APP_N_ROUTE. Both support full subdomain paths or path-based routing depending on your configuration.
SSL mode is controlled by the SSL_MODE environment variable. All TLS termination happens at the nginx layer, upstream services always receive plain HTTP.
| Mode | Description |
|---|---|
local (default) |
Self-signed certificates generated by mkcert (preferred) or OpenSSL fallback |
custom |
Provide your own cert and key via SSL_CERT_PATH and SSL_KEY_PATH
|
letsencrypt |
Automated Let's Encrypt certificates (production) |
none |
HTTP only , not recommended, disables all redirect logic |
For local development, mkcert is strongly preferred because browsers trust the resulting certificate without warnings or bypass prompts. When mkcert is available, nself build automatically collects all service subdomains as Subject Alternative Names (SANs) and issues a single cert covering the entire stack. If mkcert is not installed, the build falls back to OpenSSL for a self-signed cert, functional but not browser-trusted.
For production, letsencrypt mode handles certificate issuance and renewal automatically using the ACME HTTP-01 challenge. All subdomains must be publicly reachable before running nself start in this mode.
The following headers are included by default on all generated routes:
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options DENY;
add_header X-XSS-Protection "1; mode=block";A Content-Security-Policy header is intentionally not set at the global nginx level. Plugins and custom services often need to customize CSP per route (for example, a chat plugin embedding media from external sources). Set CSP in the relevant conf.d/ override or within the plugin's injected route configuration.
Rate limiting zones are defined in nginx/includes/rate-limits.conf and referenced by each generated service config. The defaults are:
| Service | Rate | Burst |
|---|---|---|
| GraphQL API | 100 req/min | 20 |
| Auth | 10 req/min | 5 |
| Storage uploads | 5 req/min | 2 |
| Functions | 50 req/min | 15 |
| Plugin webhooks | 30 req/min | 10 |
| Admin dashboard | 10 req/sec | 10 |
| Custom services | 10 req/sec | 10 |
To adjust limits for a specific service, override its route in nginx/conf.d/ with your own limit_req_zone and limit_req directives.
There is no NGINX_RATE_LIMIT variable — it does not exist anywhere in
this codebase, is not declared in any env template, and no generator reads
it. Each zone above is configured via its own dedicated var instead:
RATE_LIMIT_API_RPS, RATE_LIMIT_AUTH_RPS, RATE_LIMIT_AI_RPS
(internal/nginx/ratelimit.go) and AUTH_RATE_LIMIT for the whole-server
Auth zone.
On top of the one server-wide zone above, every generated service conf
(nginx/sites/*.conf) and every proxying nself ssl add <domain> --upstream ... custom-domain conf (nginx/conf.d/custom-*.conf) also
carries two path-scoped location blocks, applied unconditionally
regardless of which zone the server-wide one uses:
| Path | Match | Zone | Rate | Burst |
|---|---|---|---|---|
/auth/login |
exact (location =) |
auth_strict |
RATE_LIMIT_AUTH_RPS (default 5r/s) |
5 |
/api/ |
prefix | api |
RATE_LIMIT_API_RPS (default 30r/s) |
20 |
nginx resolves the longest-matching prefix location regardless of
declaration order in the file, so a request to either path always hits the
stricter zone even on a server otherwise routed through a looser one (for
example a CS_N custom service on the Custom services zone above) — a
request that never touches those paths is unaffected. Applied
unconditionally because the generator has no reliable way to know whether
a given CS_N or internal-route service's upstream actually serves either
path; the blocks are harmless when it doesn't. The custom-domain
placeholder conf (nself ssl add <domain> with no --upstream) never
proxies anywhere, so it carries neither block.
Source: internal/nginx/generator.go's defaultSecurityPathZones()
(default set) and ServiceRouteData.PathZones (template field), rendered
by internal/nginx/templates/service.conf.tmpl; custom-domain equivalent
in cmd/commands/ssl_install.go's writeCustomDomainConf(). Verified by
nself doctor --deep's SEC-HARDENING-06 check
(internal/doctor/hardening_check_nginx_zones.go), which accepts either of
two signals per generated conf file — it does not require both:
-
Service identity (cli#379): the file is split into its
server {}blocks, and a block whoseserver_namefirst label is a known auth/API hostname (authfor the auth service;api,hasura,graphql,ping, orping-apifor the API/Hasura/ping-api surface — seenginx.Routedefaults ininternal/nginx/routes_core.goand the shippedCS_1_ROUTE=pingexample ininternal/setup/setup_env_files.go) contains alimit_reqdirective anywhere in its body, including the server-widelocation /zone from the table above — not only the path-scoped blocks. -
Literal path fallback (original behavior): the file contains
limit_reqco-occurring with the literal string/auth/loginor/api/, for hand-written gateway configs that route by path instead of byserver_name.
A conf with no limit_req anywhere fails both signals, and a limit_req
confined to an unrelated service's block (e.g. only a frontend app's
location /) satisfies neither.
When plugins are installed, they can declare nginx routes in their plugin manifest. During nself build, the build system reads each installed plugin's manifest and writes the declared routes to nginx/routes/, which is included by nginx.conf automatically.
Plugins can add:
-
Service subdomains, for example, the chat plugin adds
chat.{BASE_DOMAIN}pointing to the plugin's container. -
Webhook endpoints, registered under
webhooks.{BASE_DOMAIN}/plugin-nameby default. -
Custom domains, controlled by
PLUGIN_{NAME}_WEBHOOK_DOMAINwhen a plugin needs a fully independent domain rather than a subdomain ofBASE_DOMAIN.
Plugin routes follow the same conflict-detection logic as core service routes. If a plugin's declared server name already exists in conf.d/, the plugin route is skipped and a notice is printed.
Optional services, those that may not be running at nginx startup, use a DNS-based lazy resolution pattern to prevent nginx from failing to start with an upstream lookup error:
resolver 127.0.0.11 valid=10s;
set $upstream http://admin:3021;
proxy_pass $upstream;Setting the upstream via a variable defers DNS resolution to request time rather than startup time. Docker's embedded DNS (127.0.0.11) resolves container names dynamically, so if an optional container comes up after nginx is already running, traffic routes to it without requiring a reload.
Core required services, Hasura and Auth, use direct proxy_pass without the variable pattern because they are always running when nginx starts.
See also: Architecture | Compose-Generation | Service-Graph | Home
ɳSelf CLI v1.0.9. MIT licensed. Docs CC BY 4.0.
GitHub · Issues · Discussions · nself.org · nself.org/docs
Getting Started
Commands
- Commands, Overview
- Lifecycle: cmd-init · cmd-build · cmd-start · cmd-stop · cmd-restart · cmd-dev
- Monitoring: cmd-status · cmd-logs · cmd-health · cmd-urls · cmd-doctor · cmd-monitor · cmd-alerts · cmd-sentry · cmd-watchdog
- Data: cmd-db · cmd-backup · cmd-dr · cmd-queue · cmd-webhooks
- Config: cmd-config · cmd-service · cmd-env · cmd-promote
- Networking: cmd-ssl · cmd-trust · cmd-dns-setup
- Security: cmd-access · cmd-security · cmd-secrets
- Tenancy: cmd-tenant · cmd-billing
- Plugins: cmd-plugin · cmd-license · cmd-dogfood (extracted, CLI-R11) · cmd-k8s (extracted, CLI-R11) · cmd-encryption (extracted, CLI-R11) · cmd-waf (extracted, CLI-R11) · cmd-federation (extracted, CLI-R11) · cmd-mail (extracted, CLI-R11) · cmd-dlq (extracted, CLI-R11)
- AI: cmd-ai · cmd-claw · cmd-model
- Templates: cmd-template
- Utilities: cmd-exec · cmd-clean · cmd-reset · cmd-update · cmd-upgrade · cmd-version · cmd-admin · cmd-migrate · cmd-migrate-firebase · cmd-migrate-supabase · cmd-completion
Features
- Features, Overview
- Feature-Auth
- Feature-Storage
- Feature-Search
- Feature-Functions
- Feature-Email
- Feature-Monitoring
- Feature-Plugins
- Feature-nClaw, AI Assistant
- Feature-nChat, Messaging
- Feature-nTV, Media Player
- Feature-nFamily, Family Social
- Feature-nCloud, Managed Hosting
- Feature-Memory-Rooms, Knowledge Organization
- Feature-Agent-Dashboard, Agent Metrics
- Feature-Image-Generation, AI Image Generation
Configuration
- Configuration, Overview
- Config-Env-Vars
- Config-Postgres
- Config-Hasura
- Config-Auth
- Config-Nginx
- Config-Optional-Services
- Config-Custom-Services
- Config-System
Plugins (87 + 10 monitoring)
Free (25)
- plugin-backup
- plugin-content-acquisition
- plugin-content-progress
- plugin-cron
- plugin-donorbox
- plugin-feature-flags
- plugin-github
- plugin-github-runner
- plugin-invitations
- plugin-jobs
- plugin-link-preview
- plugin-mdns
- plugin-mlflow
- plugin-monitoring
- plugin-notifications
- plugin-notify
- plugin-paypal
- plugin-search
- plugin-shopify
- plugin-stripe
- plugin-subtitle-manager
- plugin-tokens
- plugin-torrent-manager
- plugin-vpn
- plugin-webhooks
Pro (62)
- plugin-access-controls
- plugin-activity-feed
- plugin-admin-api
- plugin-nself-ai-gateway
- plugin-nself-ai-mcp
- plugin-nself-ai-mcp
- plugin-analytics
- plugin-auth
- plugin-backup-pro
- plugin-bots
- plugin-browser
- plugin-calendar
- plugin-cdn
- plugin-chat
- plugin-claw
- plugin-claw-budget
- plugin-claw-news
- plugin-claw-web
- plugin-cloudflare
- plugin-cms
- plugin-compliance
- plugin-cron-pro
- plugin-ddns
- plugin-devices
- plugin-documents
- plugin-donorbox-pro
- plugin-entitlements
- plugin-epg
- plugin-file-processing
- plugin-game-metadata
- plugin-geocoding
- plugin-geolocation
- plugin-google
- plugin-home
- plugin-idme
- plugin-knowledge-base
- plugin-linkedin
- plugin-livekit
- plugin-media-processing
- plugin-meetings
- plugin-moderation
- plugin-mux
- plugin-notify-pro
- plugin-object-storage
- plugin-observability
- plugin-paypal-pro
- plugin-photos
- plugin-podcast
- plugin-post
- plugin-realtime
- plugin-recording
- plugin-retro-gaming
- plugin-rom-discovery
- plugin-shopify-pro
- plugin-social
- plugin-sports
- plugin-stream-gateway
- plugin-streaming
- plugin-stripe-pro
- plugin-support
- plugin-tmdb
- plugin-voice
- plugin-web3
- plugin-workflows
Planned (26)
plugin-auditplugin-blogplugin-checkoutplugin-commerceplugin-drmplugin-exportplugin-flowplugin-importplugin-ldapplugin-mailgunplugin-mediaplugin-oauth-providersplugin-pagesplugin-postmarkplugin-rate-limitplugin-reportsplugin-samlplugin-schedulerplugin-sendgridplugin-ssoplugin-subscriptionplugin-thumbplugin-transcoderplugin-twilioplugin-wafplugin-watermark
Guides
- Guide-Production-Deployment
- Guide-SSL-Setup
- Guide-Multi-Tenancy
- Guide-Security-Hardening
- Guide-Monitoring-Setup
- Guide-Backup-Restore
- Guide-Custom-Services
- Guide-Migration-from-v1
Architecture
Reference
- API-Reference
- error-codes, Error Codes
Licensing
Security
Brand
Operations
- operations/release-cascade, Release Cascade
- operations/self-healing, Self-Healing Schema
- operations/redis-tuning, Redis Pool Tuning
- operations/meilisearch-warmup, MeiliSearch Warm-Up
- operations/jwt-rotation, JWT Key Rotation
- operations/windows-wsl2-setup, Windows / WSL2 Setup
- operations/gemini-oauth-reauth, Gemini OAuth Reauth
Contributing
Admin
- USER-ACTION-QUEUE, Pending Admin Actions
All commands (52)
- A: cmd-access · cmd-account · cmd-admin
- B: cmd-backup · cmd-build · cmd-bundle
- C: cmd-ci · cmd-clean · cmd-completion · cmd-config
- D: cmd-db · cmd-deploy · cmd-dev · cmd-doctor
- E: cmd-env · cmd-exec
- F: cmd-functions
- G: cmd-generate
- H: cmd-health · cmd-help-topics
- I: cmd-init · cmd-install
- L: cmd-license · cmd-login · cmd-logout · cmd-logs
- M: cmd-man · cmd-mcp · cmd-migrate
- O: cmd-oauth · cmd-ops
- P: cmd-plugin · cmd-promote
- R: cmd-remove · cmd-reset · cmd-restart · cmd-runner
- S: cmd-secrets · cmd-security · cmd-self-heal · cmd-server · cmd-service · cmd-start · cmd-status · cmd-stop
- T: cmd-telemetry · cmd-template · cmd-trust
- U: cmd-update · cmd-urls
- V: cmd-verify-sbom · cmd-version