Installation
Installation Troubleshooting
Common QuoteNode deployment problems with links, CORS, SMTP, DNS, Docker health checks, and lost secrets.
Installation Troubleshooting
Most installation problems come from URL mismatch, missing SMTP, blocked ports, or lost secrets. Start with the visible URL in your browser and work inward.
Public links open on my computer but not for customers
Check what URL was copied or sent.
http://localhost/...works only on the same machine.http://192.168.x.x/...works only on the LAN or VPN. VPN can be a valid bridge for internal teams, but it is not a public customer-link strategy.https://crm.example.com/...works publicly only when DNS, HTTPS, proxy, and firewall are correct.
For public customer links, deploy with a public domain using Ubuntu public server or Coolify.
Browser shows CORS errors
CORS_ALLOWED_ORIGINS must match the browser origin exactly. These are different origins:
https://crm.example.com
https://www.crm.example.com
http://crm.example.com
https://crm.example.com:8443
Fix the variable, redeploy, and retry in a fresh browser session.
Email is not delivered
Check these first:
SMTP_HOSTandSMTP_PORTare correct.SMTP_AUTH=truewhen your provider requires authentication.SMTP_STARTTLS=truefor port 587.SMTP_USERNAMEandSMTP_PASSWORDare valid.- The provider allows SMTP/app-password login.
NOTIFICATIONS_EMAIL_ENABLED=truewhen notification emails should be sent.
Manual public-link sharing and PDF download can still work without SMTP.
Notification preference links are wrong
Set:
NOTIFICATIONS_PUBLIC_PREFERENCES_URL=https://<frontend-domain>/notifications/preferences
Do not leave it pointing to localhost in a public deployment.
Docker containers are unhealthy
Run:
docker compose ps
docker compose logs -f backend
docker compose logs -f frontend
docker compose logs -f gotenberg
Common causes:
- PostgreSQL is still starting.
DB_PASSWORDdiffers between PostgreSQL and backend.DB_ENCRYPTION_KEYis missing or malformed.- Gotenberg is not healthy, so PDF generation cannot start.
- Host ports 80/443 are already used by another service.
After fixing configuration, restart the affected service or the stack:
docker compose restart backend
docker compose up -d
My IP is blocked — cannot log in
There are two common causes: the IP allowlist locked you out, or brute-force protection blocked your IP after too many failed logins.
IP allowlist lockout
QuoteNode has an IP allowlist configured in Settings > Security > IP Allowlist (or via the SECURITY_IP_WHITELIST environment variable). When enabled it gates the whole admin surface — including the login and 2FA screens — so an excluded address gets 403 IP_NOT_ALLOWED and cannot even sign in. (Health checks and customer-facing public offer links stay reachable.)
First, wait two minutes if you just changed it in the app. An in-app enable or narrow is lockout-protected: it must be re-confirmed by your session within a short window (default 120 s), and if your current address is not covered it rolls back automatically to the previous allowlist. So an accidental self-lockout from the Security screen heals itself — just wait and retry. (This safety net does not apply to the SECURITY_IP_WHITELIST environment variable, which is enforced at startup.)
Recovery (operator override): if you are still locked out — e.g. an operator SECURITY_IP_WHITELIST, an invalid stored list, or you cannot wait — add this variable to the backend container environment (.env or docker-compose environment: section) and restart:
SECURITY_IP_WHITELIST_FORCE_DISABLE=true
docker compose restart backend
This bypasses the allowlist entirely and lets you log in. Once inside, fix the allowlist in Settings > Security, then remove SECURITY_IP_WHITELIST_FORCE_DISABLE and restart again.
Do not leave
SECURITY_IP_WHITELIST_FORCE_DISABLE=truein production. It disables the entire IP access control.
Brute-force protection lockout
QuoteNode blocks IPs that fail too many login attempts within one hour:
| Threshold | Failures in 1 h | Effect |
|---|---|---|
| Soft | 10 | Progressive delay (1 s per extra attempt, max 30 s) |
| Temp lock | 20 | Locked for 5 minutes |
| Hard lock | 50 | Locked until manually cleared |
How to unblock:
- Admin panel — another administrator opens Settings > Security Dashboard > Blocked IPs and clicks Unblock.
- Wait — temp locks expire after
SECURITY_TEMP_LOCK_MINUTES(default 5 minutes). Hard locks do not expire on their own. - Raise thresholds temporarily if locked out and no other admin can help. Add to
.env, restart, log in, then remove:
SECURITY_MAX_FAILED_LOGINS_SOFT=9999
SECURITY_MAX_FAILED_LOGINS_TEMP_LOCK=9999
SECURITY_MAX_FAILED_LOGINS_HARD_LOCK=9999
Reset these to their defaults after regaining access.
Public link IP blocks
The public link rate limiter blocks IPs that exceed probe or failure limits. These blocks are in-memory and expire after PUBLIC_RATE_LIMIT_IP_BLOCK_MINUTES (default 60 minutes) or after a backend restart.
HTTPS certificate does not issue
For public deployments:
- DNS must point to the deployment server.
- Ports 80 and 443 must be reachable from the internet.
- Only one proxy should terminate HTTPS for the same domain.
- In Coolify, assign the domain to the
frontendservice.
I lost .env
If you lost .env, stop and assess before rotating values.
DB_PASSWORDcan usually be reset with PostgreSQL admin access.TIMING_TOKEN_SECRETandPUBLIC_LINK_PASSWORD_SESSION_SECRETcan be regenerated, but existing sessions/tokens may expire.DB_ENCRYPTION_KEYis critical. Without the original key, encrypted values cannot be decrypted.- If PII encryption is enabled, encrypted customer/contact fields depend on
DB_ENCRYPTION_KEY.
Restore .env from backup whenever possible.
Recovery if .env is lost but database backup exists
- Create a fresh
.envwith new secrets. - Restore the database from your backup (
pg_dump/pg_restore). - All business data (customers, offers, products, users) will be fully accessible.
- Only a few fields are lost: MFA codes (users re-enroll), SMTP password (re-enter in settings), FX API key (re-enter). If
ENCRYPT_PII=truewas enabled, encrypted customer data is also lost.
If your backups are age-encrypted (the default), you need the age identity file from your recovery kit to decrypt them first. See the Backup and Recovery guide.
Forgot admin password
Use a non-destructive recovery path:
- If SMTP is configured, use the login page: Forgot your password?
- If another administrator can still sign in, open Users in the admin panel and reset the password.
- If no administrator can sign in and the email reset flow is unavailable, restore access from a known-good backup or use your internal maintenance procedure.
docker compose down -vis not a password reset procedure. It deletes all data — users, offers, customers, settings, and backups. Use it only for disposable test environments.
License verification fails
For real deployments, keep:
LICENSE_SKIP_SIGNATURE_CHECK=false
If a valid license still fails, check that the deployment has the expected app version and an NTP-synced system clock. Confirm that the license matches the deployed edition/version, then contact support or replace the license file through the documented operator path. Do not set signature bypass to true as a production workaround.