TL;DR
Render hands you automatic SSL, managed databases, and isolated services with no configuration. What's left to you: keep secrets in environment variables (secret files for multi-line ones), make internal APIs private services, and point your database allowlist at Render's static outbound IPs. One thing catches people out. Preview environments inherit your main service's variables by default, production secrets included.
What Render Handles for You
A fair amount is already handled before you configure anything:
- Automatic SSL: Free TLS certificates for all services
- Isolated services: Each service runs in its own container
- Private networking: Services can communicate internally
- Managed databases: PostgreSQL and Redis with backups
- DDoS protection: Built-in protection at the edge
Environment Variables on Render
Setting Environment Variables
Set them per service, or put them in an environment group that several services share:
// Node.js
const databaseUrl = process.env.DATABASE_URL;
const apiKey = process.env.API_KEY;
// Python
import os
database_url = os.environ.get('DATABASE_URL')
api_key = os.environ.get('API_KEY')
Secret Files
Environment variables are a poor fit for anything multi-line, a PEM private key being the usual example. Render has secret files for exactly that:
# In Render dashboard, create a secret file
# Path: /etc/secrets/private-key.pem
# Contents: Your private key
# Access in code
const fs = require('fs');
const privateKey = fs.readFileSync('/etc/secrets/private-key.pem', 'utf8');
Never commit secrets: Render storing them safely doesn't help much if a copy is also sitting in your repo. Keep them in the dashboard or an environment group.
Database Security
Render Managed Databases
Render's Postgres is locked down before you touch it:
- Encrypted at rest and in transit
- Not publicly accessible by default (internal URL only)
- Automatic daily backups
- Can enable external access with specific IPs
Internal vs External Database URLs
# Internal URL (services in same Render region)
DATABASE_URL=postgres://user:pass@dpg-xxx.oregon-postgres.render.com/db
# External URL (for local development, external services)
DATABASE_EXTERNAL_URL=postgres://user:pass@dpg-xxx.oregon-postgres.render.com:5432/db
Best practice: Use internal URLs between Render services. They're faster, and the traffic stays on Render's private network. Turn on external access only when something outside Render genuinely needs it, then restrict it to specific IP addresses.
Private Services
A private service gets no public URL at all. Nothing outside your Render account can reach it:
# Private service URL (internal only)
INTERNAL_API=http://internal-api:10000
# From another Render service
const response = await fetch('http://internal-api:10000/process', {
method: 'POST',
headers: {
'X-Internal-Token': process.env.INTERNAL_TOKEN, // Optional auth
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
When to Use Private Services
- Background workers that process jobs
- Internal APIs not meant for public access
- Microservices that only other services call
Static Outbound IPs
If an external database wants an allowlist, you first have to know which addresses your service calls out from. Render can pin them for you:
# In Render dashboard, enable "Static Outbound IP Address"
# You'll get dedicated IPs for your service
# Use these IPs in your external database allowlist:
# - MongoDB Atlas Network Access
# - AWS RDS Security Groups
# - Other firewall configurations
Preview Environments
Every pull request gets its own deployed environment. That's the convenient part.
Preview environments use the same environment variables as your main service by default. Consider using different databases or API keys for previews.
Preview URLs are the part people forget. They're public, linked from the pull request, and talking to your production database unless you changed something.
Securing Preview Environments
- Point previews at a separate database instance
- Swap production API keys for test ones
- Check that preview URLs aren't getting indexed by search engines
Render Security Checklist
Before Going to Production
All secrets in environment variables (not code)
Database uses internal URL where possible
External database access restricted to specific IPs
Internal services are set to private
API endpoints have authentication
Preview environments don't use production data
Health check endpoints configured
Logs don't contain sensitive data
Are my environment variables secure on Render?
Yes. Render encrypts them at rest, they're only exposed to your service at runtime, and they don't show up in logs. Worth knowing: anyone on your team with dashboard access can read them.
Can I restrict who deploys to my service?
Yes. Render has team permissions covering who can view, deploy, and modify each service. Use them to keep production deploys to a short list of people.
How do I connect to external databases securely?
Enable static outbound IPs on your Render service, then add those IPs to your external database's allowlist. This ensures only your Render services can connect.
Are Render databases backed up?
Yes. Render PostgreSQL databases get automatic daily backups with point-in-time recovery. You can also take a manual backup before a major change, which is worth the thirty seconds.
Deploying to Render?
Scan your project for security issues before going live.