Production Deployment
This guide covers best practices for deploying your PocketDNS integration to production.
Pre-launch Checklist
API Configuration
- [ ] Production API keys obtained and securely stored
- [ ] Environment variables configured correctly
- [ ] API endpoints pointing to production URLs
- [ ] Rate limits understood and implemented
- [ ] Error handling tested for all scenarios
Security Review
- [ ] API keys never exposed client-side
- [ ] HTTPS enforced for all communications
- [ ] Input validation implemented for all user data
- [ ] CORS headers configured appropriately
- [ ] Authentication implemented for your API endpoints
Testing
- [ ] End-to-end testing completed in sandbox
- [ ] Error scenarios tested and handled
- [ ] Performance testing completed
- [ ] Mobile responsiveness verified
- [ ] Browser compatibility tested
Monitoring
- [ ] Error tracking configured (Sentry, Bugsnag, etc.)
- [ ] Performance monitoring set up
- [ ] API usage tracking implemented
- [ ] Alerts configured for critical failures
- [ ] Log aggregation set up
Environment Configuration
Production vs Sandbox
Ensure your application correctly switches between environments:
// config/pocketdns.js
const config = {
development: {
apiUrl: 'https://api.sandbox.pocketdns.com',
embedUrl: 'https://embed.sandbox.pocketdns.com',
apiKey: process.env.POCKETDNS_SANDBOX_API_KEY,
webhookSecret: process.env.POCKETDNS_SANDBOX_WEBHOOK_SECRET
},
production: {
apiUrl: 'https://api.pocketdns.com',
embedUrl: 'https://embed.pocketdns.com',
apiKey: process.env.POCKETDNS_API_KEY,
webhookSecret: process.env.POCKETDNS_WEBHOOK_SECRET
}
};
const env = process.env.NODE_ENV || 'development';
export default config[env];Environment Variables
Set these environment variables in production:
# Required
POCKETDNS_API_KEY=sk_live_your_production_key
POCKETDNS_WEBHOOK_SECRET=whsec_your_webhook_secret
# Optional
POCKETDNS_API_URL=https://api.pocketdns.com
POCKETDNS_EMBED_URL=https://embed.pocketdns.com
POCKETDNS_TIMEOUT=30000Configuration Validation
Validate configuration on startup:
// utils/validateConfig.js
const validateProductionConfig = () => {
const required = [
'POCKETDNS_API_KEY',
'POCKETDNS_WEBHOOK_SECRET'
];
const missing = required.filter(key => !process.env[key]);
if (missing.length > 0) {
console.error(`Missing required environment variables: ${missing.join(', ')}`);
process.exit(1);
}
// Validate API key format
if (!process.env.POCKETDNS_API_KEY.startsWith('sk_live_')) {
console.error('Production API key must start with sk_live_');
process.exit(1);
}
console.log('✅ Production configuration validated');
};
if (process.env.NODE_ENV === 'production') {
validateProductionConfig();
}Security Considerations
API Key Security
- Never log API keys in application logs
- Use environment variables for all secrets
- Rotate keys regularly (quarterly recommended)
- Restrict API key permissions if available
- Monitor API key usage for anomalies
// Redact API keys from logs
const redactAPIKey = (str) => {
return str.replace(/sk_[a-zA-Z0-9_]+/g, 'sk_***REDACTED***');
};
const logAPICall = (method, url, data) => {
console.log('API Call:', {
method,
url: redactAPIKey(url),
timestamp: new Date().toISOString()
});
};Webhook Security
Verify webhook signatures to ensure requests are from PocketDNS:
const crypto = require('crypto');
const verifyWebhookSignature = (payload, signature, secret) => {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
const expectedBuffer = Buffer.from(`sha256=${expectedSignature}`, 'utf8');
const receivedBuffer = Buffer.from(signature, 'utf8');
return crypto.timingSafeEqual(expectedBuffer, receivedBuffer);
};
// Express middleware
app.use('/webhook/pocketdns', (req, res, next) => {
const signature = req.headers['pocketdns-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.POCKETDNS_WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
next();
});HTTPS Enforcement
Ensure all communications use HTTPS:
// Express middleware
app.use((req, res, next) => {
if (req.header('x-forwarded-proto') !== 'https') {
res.redirect(`https://${req.header('host')}${req.url}`);
} else {
next();
}
});CORS Configuration
Configure CORS appropriately for your domain:
const cors = require('cors');
const corsOptions = {
origin: process.env.NODE_ENV === 'production'
? ['https://yourdomain.com', 'https://www.yourdomain.com']
: true,
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));Performance Optimization
Caching Strategy
Implement caching for API responses:
const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 600 }); // 10 minutes
const getCachedDomains = async (userIdentifier) => {
const cacheKey = `domains_${userIdentifier}`;
let domains = cache.get(cacheKey);
if (!domains) {
domains = await getUserDomains(userIdentifier);
cache.set(cacheKey, domains);
}
return domains;
};Connection Pooling
Use connection pooling for better performance:
const https = require('https');
const agent = new https.Agent({
keepAlive: true,
keepAliveMsecs: 30000,
maxSockets: 50,
maxFreeSockets: 10,
timeout: 30000
});
const fetch = require('node-fetch');
const apiCall = (url, options = {}) => {
return fetch(url, { ...options, agent });
};CDN Configuration
If serving the embed iframe, use a CDN:
// CloudFront configuration example
const embedUrl = process.env.NODE_ENV === 'production'
? 'https://cdn.yourdomain.com/pocketdns-embed'
: 'http://localhost:3000/pocketdns-embed';Monitoring and Alerting
Error Tracking
Set up error tracking with Sentry:
const Sentry = require('@sentry/node');
if (process.env.NODE_ENV === 'production') {
Sentry.init({
dsn: process.env.SENTRY_DSN,
environment: 'production'
});
}
// Track PocketDNS API errors
const trackAPIError = (error, context) => {
console.error('PocketDNS API Error:', error);
if (process.env.NODE_ENV === 'production') {
Sentry.captureException(error, {
tags: {
service: 'pocketdns',
context
}
});
}
};Performance Monitoring
Monitor API response times:
const responseTimeHistogram = new Map();
const trackAPIPerformance = (endpoint, duration) => {
if (!responseTimeHistogram.has(endpoint)) {
responseTimeHistogram.set(endpoint, []);
}
responseTimeHistogram.get(endpoint).push(duration);
// Log slow requests
if (duration > 5000) {
console.warn(`Slow API request: ${endpoint} took ${duration}ms`);
}
};Health Checks
Implement health checks for monitoring:
app.get('/health', async (req, res) => {
const health = {
status: 'healthy',
timestamp: new Date().toISOString(),
services: {}
};
// Check PocketDNS API connectivity
try {
const start = Date.now();
const response = await fetch('https://api.pocketdns.com/health', {
headers: {
'Authorization': `Bearer ${process.env.POCKETDNS_API_KEY}`
},
timeout: 5000
});
health.services.pocketdns = {
status: response.ok ? 'healthy' : 'unhealthy',
responseTime: Date.now() - start
};
} catch (error) {
health.services.pocketdns = {
status: 'error',
error: error.message
};
health.status = 'degraded';
}
const statusCode = health.status === 'healthy' ? 200 : 503;
res.status(statusCode).json(health);
});Alerts Configuration
Set up alerts for critical issues:
const sendAlert = async (message, severity = 'error') => {
if (process.env.NODE_ENV !== 'production') return;
// Slack webhook example
try {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
text: `🚨 PocketDNS Integration Alert: ${message}`,
username: 'PocketDNS Bot',
icon_emoji: severity === 'critical' ? ':fire:' : ':warning:'
})
});
} catch (error) {
console.error('Failed to send alert:', error);
}
};
// Usage
if (errorRate > 0.1) {
await sendAlert('Error rate above 10%', 'critical');
}Deployment Strategies
Blue-Green Deployment
Deploy new versions without downtime:
# docker-compose.yml
version: '3.8'
services:
app-blue:
image: myapp:${BLUE_VERSION}
ports:
- "3001:3000"
environment:
- POCKETDNS_API_KEY=${POCKETDNS_API_KEY}
app-green:
image: myapp:${GREEN_VERSION}
ports:
- "3002:3000"
environment:
- POCKETDNS_API_KEY=${POCKETDNS_API_KEY}
nginx:
image: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.confRolling Deployment
For Kubernetes deployments:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pocketdns-integration
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
selector:
matchLabels:
app: pocketdns-integration
template:
metadata:
labels:
app: pocketdns-integration
spec:
containers:
- name: app
image: myapp:latest
env:
- name: POCKETDNS_API_KEY
valueFrom:
secretKeyRef:
name: pocketdns-secrets
key: api-keyScaling Considerations
Horizontal Scaling
For high-traffic applications:
- Stateless design: Ensure your application doesn't store state locally
- Session caching: Use Redis or similar for session storage
- Load balancing: Distribute requests across multiple instances
- Database scaling: Consider read replicas for domain data
Rate Limit Handling
Implement proper rate limit handling:
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const Redis = require('ioredis');
const redis = new Redis(process.env.REDIS_URL);
const limiter = rateLimit({
store: new RedisStore({
client: redis,
prefix: 'rl:pocketdns:'
}),
windowMs: 60 * 1000, // 1 minute
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP'
});
app.use('/api/pocketdns', limiter);Backup and Recovery
Data Backup
Implement backups for critical data:
const backupUserDomains = async () => {
const users = await getAllUsers();
const backup = {
timestamp: new Date().toISOString(),
users: []
};
for (const user of users) {
const domains = await getUserDomains(user.identifier);
backup.users.push({
identifier: user.identifier,
domains: domains.map(d => ({
id: d.id,
name: d.name,
status: d.status,
expires_at: d.expires_at
}))
});
}
// Store backup (S3, Google Cloud Storage, etc.)
await storeBackup(`domains-backup-${Date.now()}.json`, backup);
};
// Run daily backups
setInterval(backupUserDomains, 24 * 60 * 60 * 1000);Disaster Recovery
Plan for disaster recovery scenarios:
- API key compromise: Have a process to rotate keys quickly
- Service downtime: Implement graceful degradation
- Data corruption: Regular backups and restore procedures
- DNS failures: Backup DNS configurations
Launch Timeline
Week Before Launch
- [ ] Complete security audit
- [ ] Perform load testing
- [ ] Set up monitoring and alerts
- [ ] Prepare rollback procedures
- [ ] Brief support team
Launch Day
- [ ] Deploy to production
- [ ] Verify all services are healthy
- [ ] Monitor error rates and performance
- [ ] Test critical user flows
- [ ] Communicate launch to team
Post-Launch
- [ ] Monitor for 24-48 hours
- [ ] Address any issues promptly
- [ ] Collect user feedback
- [ ] Plan performance optimizations
- [ ] Schedule post-launch review
Best Practices Summary
- Test thoroughly in sandbox before production
- Use proper secret management for API keys
- Implement comprehensive monitoring and alerting
- Plan for scale from day one
- Have rollback procedures ready
- Monitor performance continuously
- Keep backups of critical configurations
- Document deployment procedures
- Train your team on troubleshooting
- Plan for disaster recovery
