How to Fix Next.js Certificate Verify Failed on DigitalOcean Droplet
Troubleshooting: Next.js “Certificate Verify Failed” on DigitalOcean Droplet
As Senior DevOps Engineers, we often encounter subtle environmental issues that manifest as cryptic errors. One common challenge when deploying Next.js applications on a DigitalOcean Droplet involves SSL/TLS certificate verification failures. This guide will walk you through diagnosing and resolving the “Certificate Verify Failed” error, ensuring your Next.js application can securely communicate with external services.
1. The Root Cause: Why This Happens
The “Certificate Verify Failed” error (often appearing as UNABLE_TO_VERIFY_LEAF_SIGNATURE, CERT_HAS_EXPIRED, or similar messages in your Next.js application logs) indicates that the Node.js runtime, which powers your Next.js application, cannot validate the SSL/TLS certificate presented by a remote server it’s trying to communicate with.
On a DigitalOcean Droplet, this usually boils down to one of the following:
- Outdated CA Certificates: The operating system (e.g., Ubuntu, Debian) on your Droplet might have an outdated set of trusted Certificate Authority (CA) root certificates. This is common if the Droplet hasn’t been updated in a while, or if a very minimal base image was used.
- Missing Intermediate Certificates: The server your Next.js app is connecting to might be configured incorrectly, failing to send its full certificate chain, leading to a gap in trust.
- Custom or Self-Signed Certificates: If you’re connecting to an internal API or database that uses a custom or self-signed certificate, your Droplet’s default trust store won’t recognize it.
- Network Interception: Less common but possible, a network proxy or firewall might be intercepting SSL traffic and re-signing it with its own certificates, which are not trusted by the Droplet.
- Node.js Version Issues: Specific Node.js versions might have quirks with certificate handling, though this is less frequent with recent LTS releases.
Essentially, the Droplet’s trust store (or Node.js’s internal one) doesn’t contain the necessary root or intermediate CA to validate the certificate chain of the target server.
2. Quick Fix (CLI)
Before diving into deeper configuration, let’s try some standard system updates that often resolve this issue.
A. Update System CA Certificates (Recommended First Step)
This is the most common fix. It ensures your Droplet’s operating system has the latest trusted root certificates.
# For Debian/Ubuntu-based Droplets
sudo apt update
sudo apt upgrade -y
sudo apt install --reinstall ca-certificates # Reinstall to ensure integrity
sudo update-ca-certificates # Update the CA certificate store
# For CentOS/RHEL-based Droplets
sudo yum update
sudo yum install ca-certificates
sudo update-ca-trust extract # Update the CA certificate store
After running these commands, restart your Next.js application to see if the issue is resolved.
B. Temporarily Disable Certificate Verification (Use with Extreme Caution!)
While not recommended for production, this can help diagnose if the issue is indeed certificate verification. This bypasses a critical security mechanism and should only be used for debugging in a controlled environment.
# For Next.js development server
NODE_TLS_REJECT_UNAUTHORIZED=0 next dev
# For Next.js production server
NODE_TLS_REJECT_UNAUTHORIZED=0 next start
If your application starts working after setting NODE_TLS_REJECT_UNAUTHORIZED=0, it definitively confirms the problem is related to certificate verification. Immediately remove this flag for any production deployments and proceed to find a proper solution.
C. Explicitly Trust a Custom CA Certificate
If you have a custom or self-signed certificate that your Next.js application needs to trust (e.g., for an internal service), you can point Node.js to it.
-
Obtain the CA certificate: Get the
.pemfile for the CA that signed the target server’s certificate. -
Place it on the Droplet: For example,
/etc/ssl/certs/custom-ca.pem. -
Set the environment variable:
# For Next.js development server NODE_EXTRA_CA_CERTS=/etc/ssl/certs/custom-ca.pem next dev # For Next.js production server NODE_EXTRA_CA_CERTS=/etc/ssl/certs/custom-ca.pem next startFor persistent use, you would set
NODE_EXTRA_CA_CERTSin your application’s environment configuration (e.g., in yoursystemdservice file,.envfile for local development, or your CI/CD pipeline).
3. Configuration Check
Beyond quick CLI fixes, inspect your application and server configurations for persistent solutions.
A. Next.js Application Environment Variables
Check your .env files (e.g., .env.production, .env.local) and any deployment-specific environment variables for these:
NODE_TLS_REJECT_UNAUTHORIZED: Ensure this is not set to0in production unless absolutely unavoidable and fully understood.NODE_EXTRA_CA_CERTS: Verify if this is correctly pointing to your custom CA certificate if one is required.
B. Node.js fetch or axios Configuration
If you’re making HTTP requests within your Next.js application (e.g., in getStaticProps, API routes, or client-side fetches), review how these requests are configured.
-
Custom
agentforhttps: If you’re usinghttps.Agentoraxioswith a custom agent, check forrejectUnauthorizedsettings.// Example with Node.js native fetch (or a polyfill) import https from 'https'; const agent = new https.Agent({ rejectUnauthorized: true, // Should be true in production ca: [fs.readFileSync('/path/to/additional-ca.pem')] // Add specific CAs }); fetch('https://your-api.com', { agent }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error(err)); -
process.env.NODE_TLS_REJECT_UNAUTHORIZED: Ensure your code isn’t inadvertently overriding this based on an environment variable you didn’t intend to set.
C. Systemd Service File (if applicable)
If you’re running your Next.js application as a systemd service, ensure any necessary environment variables are set correctly within the service unit file (e.g., /etc/systemd/system/your-next-app.service).
[Service]
Environment="NODE_ENV=production"
Environment="NODE_EXTRA_CA_CERTS=/etc/ssl/certs/custom-ca.pem" # If needed
ExecStart=/usr/bin/node /path/to/your/nextjs/app/.next/standalone/server.js
# ... other configurations
D. Diagnosing the Target Server’s Certificate
You can use openssl directly from your Droplet to inspect the certificate chain of the problematic target server. This helps identify if the target server itself is misconfigured.
# Replace example.com:443 with your target host and port
openssl s_client -connect example.com:443 -servername example.com
Look for Verify return code: 0 (ok) in the output. If you see other codes, it indicates an issue with the target server’s certificate or its chain. You can also examine the Certificate chain section to see if all necessary certificates (root, intermediate) are being sent.
4. Verification
After applying any of the fixes, follow these steps to verify the issue is resolved:
- Restart your Next.js application: Ensure no old processes are running with outdated configurations.
# If using npm npm stop # if you have a stop script npm start # If using systemd sudo systemctl restart your-next-app.service sudo systemctl status your-next-app.service - Check application logs: Monitor your Next.js application’s output for the “Certificate Verify Failed” error.
- Test functionality: Interact with your Next.js application in a way that triggers the network requests that were previously failing.
- Confirm
opensslstatus (if applicable): If you had issues with a specific target server, re-run theopenssl s_clientcommand from your Droplet to ensure it now showsVerify return code: 0 (ok).
By systematically working through these steps, you can effectively diagnose and resolve “Certificate Verify Failed” errors for your Next.js applications on DigitalOcean Droplets, ensuring secure and reliable communication with external services.