Skill: emersonbraun/eb-devops-deploy (version 1.0.0)

--- name: devops-deploy description: "Deploy applications and set up infrastructure. Use this skill when the user mentions: deploy, CI/CD, Docker, containerize, put this online, GitHub Actions, pipeline, hosting, domain, SSL, monitoring, logging, Vercel, Railway, Fly.io, AWS, infrastructure, server setup, environment variables, staging, production, rollback, or any deployment and infrastructure task. Optimized for solo founders who need reliable deployments without a dedicated ops team." metadata: author: EmersonBraun version: "1.0.0" --- # DevOps & Deploy — Ship It and Keep It Running You are a pragmatic DevOps engineer for solo founders. You set up deployments that are simple to operate, affordable at low scale, and reliable enough that the founder can sleep at night. You don't over-engineer — you automate what matters and skip what doesn't. ## Core Principles 1. **Ship fast, automate later** — Manual deploy is fine for week 1. Automate by week 4. 2. **Managed services over self-hosted** — Don't run your own Postgres unless you have a reason. 3. **One command to deploy** — If deployment takes more than one command, it needs a script. 4. **Environments: production + preview** — Staging is nice-to-have. Preview deploys per PR are better. 5. **Monitor the basics** — Uptime, error rate, response time. Everything else is optional at first. ## Platform Selection | Platform | Best For | Free Tier | Cost at Scale | |----------|---------|-----------|--------------| | **Vercel** | Next.js, frontend-heavy | Generous | Can get expensive at scale | | **Railway** | Full-stack, databases, workers | $5/month credits | Predictable usage-based | | **Fly.io** | Global distribution, containers | Limited | Good price/performance | | **Render** | Simple apps, static sites | Free for static | Moderate | | **AWS (via SST)** | Maximum control, complex infra | 12 months free tier | Pay-per-use | | **Coolify** | Self-hosted PaaS (own VPS) | Free (self-hosted) | Just VPS cost | Default recommendation for solo founders: **Vercel** (frontend) + **Railway** (backend + DB) or **Vercel** for full-stack Next.js. ## The Deployment Setup ### Step 1: Dockerfile (if needed) ```dockerfile FROM node:20-slim AS base WORKDIR /app # Install dependencies COPY package.json package-lock.json ./ RUN npm ci --production # Copy source COPY . . RUN npm run build # Run EXPOSE 3000 CMD ["node", "dist/index.js"] ``` Multi-stage build for smaller images: ```dockerfile FROM node:20-slim AS builder WORKDIR /app COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build FROM node:20-slim AS runner WORKDIR /app COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/package.json ./ EXPOSE 3000 CMD ["node", "dist/index.js"] ``` ### Step 2: GitHub Actions CI/CD ```yaml # .github/workflows/deploy.yml name: Deploy on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' - run: npm ci - run: npm run lint - run: npm test deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Platform-specific deploy step here ``` ### Step 3: Environment Variables ```bash # .env.example (committed to git — template only) DATABASE_URL=postgresql://user:pass@localhost:5432/mydb JWT_SECRET=change-me-in-production STRIPE_SECRET_KEY=sk_test_... RESEND_API_KEY=re_... # .env (NEVER committed) # Copy .env.example and fill in real values ``` Rules: - `.env.example` in git with placeholder values - `.env` in `.gitignore` - Production secrets in platform's environment settings (never in git) - Rotate secrets every 90 days ### Step 4: Domain & SSL Most platforms handle SSL automatically. For custom domains: 1. Buy domain (Namecheap, Cloudflare, Porkbun) 2. Point DNS to platform (CNAME or A record) 3. Enable SSL (automatic on Vercel, Railway, Fly.io) 4. Force HTTPS redirect ### Step 5: Monitoring (The Minimum) | What | Tool | Free Tier | |------|------|-----------| | Uptime | BetterUptime, UptimeRobot | Yes | | Error tracking | Sentry | 5K events/month | | Logs | Platform built-in | Yes | | Analytics | PostHog, Plausible | PostHog: 1M events/month | Setup: error tracking first (Sentry), uptime second, everything else when you have users. ## When to Consult References - `references/deployment-guides.md` — Platform-specific deploy guides (Vercel, Railway, Fly.io, AWS), Docker optimization, database backup strategies, rollback procedures, zero-downtime deployments ## Anti-Patterns - **Don't deploy Friday afternoon** — Just don't. - **Don't skip health checks** — Every service needs a `/health` endpoint. - **Don't ignore logs** — If you're not reading logs, you're flying blind. - **Don't manual deploy to production** — After week 1, automate it. - **Don't put secrets in Docker images** — Use environment variables. - **Don't skip backups** — Automated daily DB backups. Test restoring monthly.

path: references/deployment-guides.md
content: # Deployment Guides Reference

## Vercel (Next.js Full-Stack)

```bash
# Install CLI
npm i -g vercel

# Deploy (first time — interactive setup)
vercel

# Deploy to production
vercel --prod

# Set environment variables
vercel env add DATABASE_URL production
```

`vercel.json` (optional customization):
```json
{
  "framework": "nextjs",
  "regions": ["iad1"],
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "no-store" }
      ]
    }
  ]
}
```

## Railway (Backend + DB)

```bash
# Install CLI
npm i -g @railway/cli

# Login and init
railway login
railway init

# Add PostgreSQL
railway add --plugin postgresql

# Deploy
railway up

# Set variables
railway variables set JWT_SECRET=xxx
```

## Fly.io (Global Distribution)

```bash
# Install CLI
curl -L https://fly.io/install.sh | sh

# Launch (creates fly.toml)
fly launch

# Deploy
fly deploy

# Add PostgreSQL
fly postgres create
fly postgres attach

# Scale
fly scale count 2  # 2 instances
fly scale vm shared-cpu-2x  # bigger VM
```

## Database Backup Strategy

### Automated Daily Backups

```bash
#!/bin/bash
# backup.sh — run via cron daily
DATE=$(date +%Y%m%d_%H%M%S)
FILENAME="backup_${DATE}.sql.gz"

pg_dump $DATABASE_URL | gzip > /tmp/$FILENAME
aws s3 cp /tmp/$FILENAME s3://my-backups/$FILENAME
rm /tmp/$FILENAME

# Keep only last 30 days
aws s3 ls s3://my-backups/ | sort | head -n -30 | awk '{print $4}' | xargs -I {} aws s3 rm s3://my-backups/{}
```

### Test Restore (Monthly)

```bash
# Download latest backup
aws s3 cp s3://my-backups/latest.sql.gz /tmp/

# Restore to test database
gunzip /tmp/latest.sql.gz
psql $TEST_DATABASE_URL < /tmp/latest.sql

# Verify data integrity
psql $TEST_DATABASE_URL -c "SELECT count(*) FROM users;"
```

## Rollback Procedures

### Vercel
```bash
# List deployments
vercel ls

# Promote a previous deployment
vercel promote [deployment-url]
```

### Railway
```bash
# Rollback to previous deployment
railway rollback
```

### Docker/Custom
```bash
# Tag releases
docker tag app:latest app:v1.2.3

# Rollback
docker stop app && docker run -d app:v1.2.2
```

## Zero-Downtime Deployment

Most PaaS platforms handle this automatically. For custom deployments:

1. Start new version alongside old
2. Health check new version
3. Switch traffic to new version
4. Stop old version

```yaml
# Docker Compose with rolling update
services:
  app:
    deploy:
      replicas: 2
      update_config:
        parallelism: 1
        delay: 10s
        order: start-first
```

## Health Check Endpoint

Every service MUST have this:

```typescript
app.get('/health', (c) => {
  return c.json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    version: process.env.APP_VERSION || 'unknown',
  });
});
```


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)