All security features are free, default, and automatic. No paywall, no opt-in.
Every security feature in ɳSelf ships in the free tier. RLS, rate limiting, MFA throttle, SSRF guard, JWT rotation, WAF, audit logs, encryption at rest, and automatic TLS are all on by default. No license required. No upsell.
# Apply all hardening (run once on new production server)
nself prod harden
# Full security audit
nself prod check --full
# Deep security scan (runs OWASP Top 10 checks)
nself doctor --deepnself prod harden runs a hardening suite whenever you deploy to production. It also fires automatically on nself install, nself update, and daily via cron.
nself prod harden
# Output:
# [✓] Hasura console disabled
# [✓] Postgres: public schema revoked from public role
# [✓] Postgres: pg_hba.conf — local auth only
# [✓] Nginx: security headers applied
# [✓] Rate limiting: 100 req/min per IP (auth: 10 req/min)
# [✓] SSRF guard: RFC1918 ranges blocked
# [✓] File upload: 10 MB limit, 6-layer validation
# [✓] JWT: HS256 upgraded to RS256 (if not already)
# [✓] Audit log: enabled
# [✓] TLS: minimum TLS 1.2, HSTS header set
# [✓] Fail2ban: auth brute-force rules active
# Hardening complete. Score: 100/100RLS is enforced at the Postgres layer for all user-data tables. Hasura's permission system sits on top, providing a second layer. Users can never read other users' data even with a valid JWT.
-- RLS is set up automatically by nself on every np_* table:
ALTER TABLE np_items ENABLE ROW LEVEL SECURITY;
CREATE POLICY user_isolation ON np_items
USING (user_id = current_setting('hasura.user')::uuid);
-- Verify RLS is active
nself prod check --item rls
# Output:
# Table RLS Policies
# np_items ON user_isolation
# np_files ON user_isolation
# np_notifications ON user_isolationNginx-level rate limiting is configured automatically. Defaults protect all services; auth endpoints get a tighter limit.
# In .environments/prod/.env — tune if needed:
RATE_LIMIT_GENERAL=100r/m # 100 req/min per IP (all endpoints)
RATE_LIMIT_AUTH=10r/m # 10 req/min per IP (auth endpoints)
RATE_LIMIT_BURST=20 # Allow short bursts above limit
# Reload after changing limits
nself service reload nginx# MFA throttle — blocks after 5 failed TOTP attempts for 5 minutes
MFA_THROTTLE_ATTEMPTS=5
MFA_THROTTLE_WINDOW=300
# Password policy
MIN_PASSWORD_LENGTH=12
REQUIRE_UPPERCASE=true
REQUIRE_NUMBER=true
REQUIRE_SPECIAL=true
# Session expiry
JWT_EXPIRY=3600 # 1 hour access token
REFRESH_TOKEN_EXPIRY=604800 # 7 days refresh tokenServer-Side Request Forgery protection blocks internal network requests from user-supplied URLs. Enabled by default.
# Blocked by default:
# 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC 1918)
# 127.0.0.0/8 (loopback)
# 169.254.0.0/16 (link-local / AWS metadata)
# ::1, fc00::/7 (IPv6 private)
# If your integration needs an internal URL (e.g., webhook to internal service):
SSRF_ALLOWLIST=10.0.1.50/32,10.0.1.51/32
# Verify SSRF guard is active
nself prod check --item ssrf# Rotate the JWT signing key (zero-downtime — both keys valid during transition)
nself secrets rotate jwt
# What happens:
# 1. Generates new RS256 key pair
# 2. Adds new public key to Hasura's JWKS endpoint
# 3. Issues new tokens with new key
# 4. Old key stays valid for existing sessions (up to JWT_EXPIRY)
# 5. Old key removed after transition window
# Schedule automatic rotation (every 90 days)
nself secrets rotate jwt --schedule 90dNginx ModSecurity WAF runs in detection mode by default. Enable blocking when you've tuned the rule set.
# Check WAF status
nself prod check --item waf
# Enable blocking mode
WAF_MODE=blocking # detection | blocking
# View recent WAF events
nself logs nginx --filter waf --tail 50
# OWASP Core Rule Set version in use
nself prod check --item waf-crs-versionEvery auth event, admin action, and data mutation is logged. Logs are signed and append-only.
# Query audit log
nself audit list --since 24h
nself audit list --user user@example.com
nself audit list --action auth.login --limit 100
# Export audit log (for compliance)
nself audit export --since 2026-01-01 --format json > audit-2026.json
# Audit log is stored in PostgreSQL (np_audit_log table) + forwarded to Loki# Postgres data directory encryption (OS-level — set up at server provisioning):
# Use LUKS on Linux or FileVault on macOS for disk encryption.
# Application-level field encryption for sensitive columns (e.g., API keys, tokens):
# Enabled automatically for columns tagged with @encrypted in Hasura metadata.
# Backup encryption (enabled by default):
BACKUP_ENCRYPT=true
BACKUP_ENCRYPT_KEY=<generate: openssl rand -hex 32>
# Verify backup encryption
nself backup verify --check-encryption# In .env:
CSP_MODE=strict # strict | moderate | permissive | disabled
# strict (default for new installs):
# default-src 'none'; script-src 'self'; connect-src 'self' api.yourdomain.com;
# img-src 'self' data:; style-src 'self' 'unsafe-inline';
# moderate (if your app needs inline scripts):
# Adds 'unsafe-inline' to script-src with nonce support.
# Check current CSP headers
nself prod check --item cspɳSelf integrates ShellCheck, Gitleaks, Trivy, and Semgrep into the CI pipeline:
# Run full security scan locally
nself security scan
# Scan for secrets in git history
nself security scan --secrets
# Scan container images for CVEs
nself security scan --images
# OWASP Top 10 compliance check
nself doctor --deep --owaspSubscribe to security advisories at nself.org/security. Critical vulnerabilities trigger an automatic nself doctor --critical run on next startup.
nself prod check --full after every deployment.nself security scan in CI on every push to main.nself update pulls security patches automatically.auth.mfa_failed events above threshold.