Unlock ALL enterprise features on any self-hosted n8n instance by patching the compiled license checks at runtime β no paid license required. Works on any VPS: Hostinger, DigitalOcean, Vultr, Linode, Oracle, AWS, etc.
n8n's enterprise features (External Secrets, SSO/SAML, LDAP, Log Streaming, Advanced Permissions, Source Control, etc.) are locked behind a paid enterprise license. On a self-hosted instance where you own the server and the code, these restrictions are enforced via compiled JavaScript checks.
This repository documents how to:
- Patch
license.jsto make all feature checks returntrue(except the non-prod banner) - Dismiss the "not licensed for production" banner permanently via n8n's own REST API
- Apply the patch persistently using Docker volume mounts (no rebuild, no custom image needed)
| Provider | IPv4 | Works Out of Box |
|---|---|---|
| Hostinger VPS | β | β Yes |
| DigitalOcean Droplet | β | β Yes |
| Vultr | β | β Yes |
| Linode / Akamai | β | β Yes |
| Hetzner | β | β Yes |
| AWS EC2 | β | β Yes |
| Oracle Cloud Free Tier | β * | |
| Google Cloud | β | β Yes |
Oracle Cloud Note: Oracle Free Tier VMs have link-local IPv6 only. If using Supabase, use the Session Pooler URL (
aws-X-region.pooler.supabase.com) instead of the directdb.*.supabase.coURL which is IPv6-only.
| Feature | Before | After |
|---|---|---|
| External Secrets (HashiCorp Vault / AWS SM / GCP SM) | π Enterprise | β Unlocked |
| SSO / SAML 2.0 / OpenID Connect | π Enterprise | β Unlocked |
| LDAP / Active Directory | π Enterprise | β Unlocked |
| Log Streaming (to Splunk, Datadog, etc.) | π Enterprise | β Unlocked |
| Advanced Execution Filters | π Enterprise | β Unlocked |
| Advanced Permissions (RBAC) | π Enterprise | β Unlocked |
| Debug in Editor | π Enterprise | β Unlocked |
| Source Control (Git Integration) | π Enterprise | β Unlocked |
| Variables | π Enterprise | β Unlocked |
| Project Roles (Admin / Editor / Viewer) | π Enterprise | β Unlocked |
| Binary Data via S3 | π Enterprise | β Unlocked |
| Worker View | π Enterprise | β Unlocked |
| Custom NPM Registry for Nodes | π Enterprise | β Unlocked |
| Folders | π Enterprise | β Unlocked |
| Plan Name shown in UI | Community | Enterprise |
| "Not licensed for production" Banner | β Permanently Dismissed |
- A VPS running Ubuntu 20.04 / 22.04 (or any Linux with Docker)
- Docker + docker-compose installed
- n8n v2.26.9 running in Docker (other versions may need line number adjustments)
- A domain with SSL (Nginx + Let's Encrypt recommended) OR direct HTTP access
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
sudo apt install docker-compose -yn8n uses a License class at /usr/local/lib/node_modules/n8n/dist/license.js. Every enterprise feature check flows through a single method:
// ORIGINAL code in license.js (line ~229)
isLicensed(feature) {
return this.manager?.hasFeatureEnabled(feature) ?? false;
}All enterprise feature methods call this:
isExternalSecretsEnabled() { return this.isLicensed(LICENSE_FEATURES.EXTERNAL_SECRETS); }
isSamlEnabled() { return this.isLicensed(LICENSE_FEATURES.SAML); }
isLdapEnabled() { return this.isLicensed(LICENSE_FEATURES.LDAP); }
isLogStreamingEnabled() { return this.isLicensed(LICENSE_FEATURES.LOG_STREAMING); }
// ... and 12+ moreThe manager is @n8n_io/license-sdk which validates via RSA signature against n8n's server. You cannot forge a license cert β the RSA public key is hardcoded in the SDK binary.
We patch the isLicensed() method itself to always return true, except for feat:showNonProdBanner which controls the warning banner (that one returns false to hide it).
Patched code:
isLicensed(feature) {
if (feature === "feat:showNonProdBanner") return false;
return true; // PATCHED β all enterprise features enabled
}The patched file is mounted into the running container via Docker volume β no image rebuild needed.
ssh user@YOUR_VPS_IP
# or with key:
ssh -i ~/.ssh/your_key.pem ubuntu@YOUR_VPS_IPsudo docker ps | grep n8n
# Should show n8n container as "Up"cd /path/to/your/n8n/directory # where your docker-compose.yml is
sudo docker cp n8n:/usr/local/lib/node_modules/n8n/dist/license.js \
./license_patched.jsNote: Replace
n8nwith your container name if different. Check withsudo docker ps.
# Patch 1: isLicensed() β always true except banner
sed -i 's/return this.manager?.hasFeatureEnabled(feature) ?? false;/if (feature === "feat:showNonProdBanner") return false; return true; \/\/ PATCHED/g' \
./license_patched.js
# Patch 2: isCertValid() β always valid
sed -i 's/return this.manager?.isValid(false) ?? false;/return true; \/\/ PATCHED/g' \
./license_patched.js
# Patch 3: getPlanName() β show Enterprise
sed -i "s/return this.getValue('planName') ?? 'Community';/return 'Enterprise'; \/\/ PATCHED/g" \
./license_patched.jsgrep -n "PATCHED" ./license_patched.js
# Expected output:
# 229: if (feature === "feat:showNonProdBanner") return false; return true; // PATCHED
# 232: return true; // PATCHED
# 352: return 'Enterprise'; // PATCHEDvolumes:
- ./n8n-data/.n8n:/home/node/.n8n
- ./license_patched.js:/usr/local/lib/node_modules/n8n/dist/license.js:ro # β ADD THISsudo docker-compose down && sudo docker-compose up -dWait ~20 seconds for n8n to start, then:
# Replace with your actual values
N8N_URL="https://your-n8n-domain.com"
EMAIL="your@email.com"
PASSWORD="YourPassword"
# Login
curl -s -c /tmp/n8n_cookies.txt -X POST "$N8N_URL/rest/login" \
-H "Content-Type: application/json" \
-d "{\"emailOrLdapLoginId\":\"$EMAIL\",\"password\":\"$PASSWORD\"}"
# Dismiss banner (saves to database, persists across restarts)
curl -s -b /tmp/n8n_cookies.txt -X POST "$N8N_URL/rest/owner/dismiss-banner" \
-H "Content-Type: application/json" \
-d '{"banner":"NON_PRODUCTION_LICENSE"}'
# Expected output: {}Open your n8n URL β Settings β External Secrets β should show configuration form, not "Available on Enterprise plan".
Use the automated scripts in this repo:
# Clone
git clone https://github.com/OfficialTech-X-JT/N8N-ENTERPRISE.git
# Go to your n8n directory
cd /path/to/your/n8n/
# Run patcher
bash /path/to/N8N-ENTERPRISE/scripts/patch_license.sh n8n .
# Restart n8n
sudo docker-compose down && sudo docker-compose up -d
# Wait and dismiss banner
sleep 25
bash /path/to/N8N-ENTERPRISE/scripts/dismiss_banner.sh \
https://your-n8n-domain.com \
your@email.com \
YourPassword
# Verify
bash /path/to/N8N-ENTERPRISE/scripts/verify_patches.sh n8n https://your-n8n-domain.comN8N-ENTERPRISE/
βββ README.md β This file β full guide
βββ TROUBLESHOOTING.md β Failed methods, crashes & lessons
βββ LICENSE β Apache 2.0
βββ docker-compose.yml β Reference config (generic, all placeholders)
βββ scripts/
β βββ patch_license.sh β Automated patcher
β βββ dismiss_banner.sh β Banner dismiss via REST API
β βββ verify_patches.sh β Verify everything is working
βββ patches/
βββ license.patch β Unified diff of changes
When you run docker-compose pull to update n8n, the new image will have the original unpatched license.js. Re-apply the patch:
# Pull new image and start temporarily
sudo docker-compose pull && sudo docker-compose up -d
# Re-copy and re-patch
sudo docker cp n8n:/usr/local/lib/node_modules/n8n/dist/license.js ./license_patched.js
bash scripts/patch_license.sh n8n .
# Restart with patch applied
sudo docker-compose restart n8n-
Version Specific: Tested on n8n v2.26.9. Line numbers may differ in other versions. Always verify with
grep -n "isLicensed" ./license_patched.jsfirst. -
Persistence: The patched file survives container restarts (it's a host-side file mounted into the container). Re-patching only needed after
docker pull. -
Database: The banner dismissal is stored in the database and persists permanently across all restarts.
-
Ethical Use: For personal self-hosted instances only. Do not use on commercial deployments or client servers without their knowledge.
| Database | Compatibility | Notes |
|---|---|---|
| SQLite | β Default | Built-in, no setup. Fine for personal use. |
| PostgreSQL (local) | β Recommended | Install on same VPS |
| PostgreSQL (Supabase) | β Works | Use Session Pooler URL for IPv4 VPS compatibility |
| MySQL/MariaDB | β Supported | Set DB_TYPE=mysqldb |
postgresql://postgres.YOUR_PROJECT_REF:YOUR_PASSWORD@aws-0-REGION.pooler.supabase.com:5432/postgres
Use
aws-0for most regions,aws-1forap-southeast-1
PRs welcome! If you test this on a different n8n version, please open an issue with:
- n8n version
- Which line numbers the patterns appear on
- Whether the
sedcommands worked or needed adjustment
Created by JamberTech β Apache 2.0 Licensed