Skip to content

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:

javascript
// 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:

bash
# 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=30000

Configuration Validation

Validate configuration on startup:

javascript
// 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

  1. Never log API keys in application logs
  2. Use environment variables for all secrets
  3. Rotate keys regularly (quarterly recommended)
  4. Restrict API key permissions if available
  5. Monitor API key usage for anomalies
javascript
// 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:

javascript
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:

javascript
// 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:

javascript
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:

javascript
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:

javascript
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:

javascript
// 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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

yaml
# 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.conf

Rolling Deployment

For Kubernetes deployments:

yaml
# 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-key

Scaling Considerations

Horizontal Scaling

For high-traffic applications:

  1. Stateless design: Ensure your application doesn't store state locally
  2. Session caching: Use Redis or similar for session storage
  3. Load balancing: Distribute requests across multiple instances
  4. Database scaling: Consider read replicas for domain data

Rate Limit Handling

Implement proper rate limit handling:

javascript
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:

javascript
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:

  1. API key compromise: Have a process to rotate keys quickly
  2. Service downtime: Implement graceful degradation
  3. Data corruption: Regular backups and restore procedures
  4. 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

  1. Test thoroughly in sandbox before production
  2. Use proper secret management for API keys
  3. Implement comprehensive monitoring and alerting
  4. Plan for scale from day one
  5. Have rollback procedures ready
  6. Monitor performance continuously
  7. Keep backups of critical configurations
  8. Document deployment procedures
  9. Train your team on troubleshooting
  10. Plan for disaster recovery

Built with ❤️ for PocketDNS Partners