Skip to main content

epic-deployment

Guide on deployment with Fly.io, multi-region setup, and CI/CD for Epic Stack

Datos de origen

Repositorio
epicweb-dev/epic-stack
Última actividad en el origen
24 de julio de 2026 a las 20:05
Idioma detectado de SKILL.md
inglés
Estrellas
5538
Forks
463

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
epic-deployment
description
Guide on deployment with Fly.io, multi-region setup, and CI/CD for Epic Stack
categories
["deployment","fly-io","ci-cd","docker"]
# Epic Stack: Deployment ## When to use this skill Use this skill when you need to: - Configure deployment on Fly.io - Setup multi-region deployment - Configure CI/CD with GitHub Actions - Manage secrets in production - Configure healthchecks - Work with LiteFS and volumes - Local deployment with Docker ## Patterns and conventions ### Fly.io Configuration Epic Stack uses Fly.io for hosting with configuration in `fly.toml`. **Basic configuration:** ```toml # fly.toml app = "your-app-name" primary_region = "sjc" kill_signal = "SIGINT" kill_timeout = 5 [build] dockerfile = "/other/Dockerfile" ignorefile = "/other/Dockerfile.dockerignore" [mounts] source = "data" destination = "/data" ``` ### Primary Region **Configure primary region:** ```toml primary_region = "sjc" # Change according to your location ``` **Important:** The primary region must be the same for: - `primary_region` en `fly.toml` - Region del volume `data` - `PRIMARY_REGION` en variables de entorno ### LiteFS Configuration **Configuration in `other/litefs.yml`:** ```yaml fuse: dir: '${LITEFS_DIR}' data: dir: '/data/litefs' proxy: addr: ':${INTERNAL_PORT}' target: 'localhost:${PORT}' db: '${DATABASE_FILENAME}' lease: type: 'consul' candidate: ${FLY_REGION == PRIMARY_REGION} promote: true advertise-url: 'http://${HOSTNAME}.vm.${FLY_APP_NAME}.internal:20202' consul: url: '${FLY_CONSUL_URL}' key: 'epic-stack-litefs_20250222/${FLY_APP_NAME}' exec: - cmd: npx prisma migrate deploy if-candidate: true - cmd: sqlite3 $DATABASE_PATH "PRAGMA journal_mode = WAL;" if-candidate: true - cmd: sqlite3 $CACHE_DATABASE_PATH "PRAGMA journal_mode = WAL;" if-candidate: true - cmd: npx prisma generate --sql - cmd: npm start ``` ### Healthchecks **Configuration in `fly.toml`:** ```toml [[services.http_checks]] interval = "10s" grace_period = "5s" method = "get" path = "/resources/healthcheck" protocol = "http" timeout = "2s" tls_skip_verify = false ``` **Healthcheck implementation:** ```typescript // app/routes/resources/healthcheck.tsx export async function loader({ request }: Route.LoaderArgs) { const host = request.headers.get('X-Forwarded-Host') ?? request.headers.get('host') try { await Promise.all([ prisma.$queryRaw`SELECT 1`, // Verify DB fetch(`${new URL(request.url).protocol}${host}`, { method: 'HEAD', headers: { 'X-Healthcheck': 'true' }, }), ]) return new Response('OK') } catch (error) { console.log('healthcheck ❌', { error }) return new Response('ERROR', { status: 500 }) } } ``` ### Environment Variables **Secrets in Fly.io:** ```bash # Generate secrets fly secrets set SESSION_SECRET=$(openssl rand -hex 32) --app [YOUR_APP_NAME] fly secrets set HONEYPOT_SECRET=$(openssl rand -hex 32) --app [YOUR_APP_NAME] # List secrets fly secrets list --app [YOUR_APP_NAME] # Delete secret fly secrets unset SECRET_NAME --app [YOUR_APP_NAME] ``` **Common secrets:** - `SESSION_SECRET` - Secret for signing session cookies - `HONEYPOT_SECRET` - Secret for honeypot fields - `DATABASE_URL` - Automatically configured by LiteFS - `CACHE_DATABASE_PATH` - Automatically configured - `RESEND_API_KEY` - For sending emails (optional) - `TIGRIS_*` - For image storage (automatic) - `SENTRY_DSN` - For error monitoring (optional) ### Volumes **Create volume:** ```bash fly volumes create data --region sjc --size 1 --app [YOUR_APP_NAME] ``` **List volumes:** ```bash fly volumes list --app [YOUR_APP_NAME] ``` **Expand volume:** ```bash fly volumes extend <volume-id> --size 10 --app [YOUR_APP_NAME] ``` ### Multi-Region Deployment **Deploy to multiple regions:** ```bash # Deploy in primary region (more instances) fly scale count 2 --region sjc --app [YOUR_APP_NAME] # Deploy in secondary regions (read-only) fly scale count 1 --region ams --app [YOUR_APP_NAME] fly scale count 1 --region syd --app [YOUR_APP_NAME] ``` **Verify instances:** ```bash fly status --app [YOUR_APP_NAME] # The ROLE column will show "primary" or "replica" ``` ### Consul Setup **Attach Consul:** ```bash fly consul attach --app [YOUR_APP_NAME] ``` **Consul manages:** - Which instance is primary - Automatic failover - Data replication ### GitHub Actions CI/CD **Basic workflow:** ```yaml # .github/workflows/deploy.yml name: Deploy on: push: branches: [main, dev] jobs: deploy: name: Deploy runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: superfly/flyctl-actions/setup-flyctl@master - run: flyctl deploy --remote-only env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} ``` **Complete configuration:** - Deploy to `production` from `main` branch - Deploy to `staging` from `dev` branch - Tests before deploy (optional) ### Deployable Commits Following Epic Web principles: **Deployable commits** - Every commit to the main branch should be deployable. This means: - The code should be in a working state - Tests should pass - The application should build successfully - No "WIP" or "TODO" commits that break the build **Example - Deployable commit workflow:** ```bash # ✅ Good - Each commit is deployable git commit -m "Add user profile page" # This commit is complete, tested, and deployable git commit -m "Fix login redirect bug" # This commit fixes a bug and is deployable # ❌ Avoid - Non-deployable commits git commit -m "WIP: working on feature" # This commit might not work, not deployable git commit -m "Add feature (tests failing)" # This commit breaks the build, not deployable ``` **Benefits:** - Easy rollback - any commit can be deployed - Continuous deployment - deploy any time - Clear history - each commit represents a working state - Faster recovery - can deploy any previous commit ### Small and Short Lived Merge Requests Following Epic Web principles: **Small and short lived merge requests** - Keep PRs small and merge them quickly. Large PRs are hard to review, risky to merge, and slow down the team. **Guidelines:** - **Small PRs** - Focus on one feature or fix per PR - **Short-lived** - Merge within a day or two, not weeks - **Reviewable** - PRs should be reviewable in 30 minutes or less - **Independent** - Each PR should be independently deployable **Example - Small, focused PR:** ```bash # ✅ Good - Small, focused PR # PR: "Add email validation to signup form" # - Only changes signup validation # - Includes tests # - Can be reviewed quickly # - Can be merged and deployed independently # ❌ Avoid - Large, complex PR # PR: "Refactor authentication system and add 2FA and OAuth" # - Too many changes at once # - Hard to review # - Risky to merge # - Takes days to review ``` **Benefits:** - Faster reviews - easier to understand and review - Lower risk - smaller changes are less risky - Faster feedback - get feedback sooner - Easier rollback - smaller changes are easier to revert - Better collaboration - team can work in parallel on different small PRs **When PRs get too large:** - Split into multiple smaller PRs - Use feature flags to merge incrementally - Break down into logical pieces ### Tigris Object Storage **Create storage:** ```bash fly storage create --app [YOUR_APP_NAME] ``` **This creates:** - Tigris bucket - Automatic environment variables: - `TIGRIS_ENDPOINT` - `TIGRIS_ACCESS_KEY_ID` - `TIGRIS_SECRET_ACCESS_KEY` - `TIGRIS_BUCKET_NAME` ### Database Migrations **Automatic migrations:** Migrations are automatically applied on deploy via `litefs.yml`: ```yaml exec: - cmd: npx prisma migrate deploy if-candidate: true ``` **Note:** Only the primary instance runs migrations (`if-candidate: true`). ### Database Backups **Create backup:** ```bash # SSH to instance fly ssh console --app [YOUR_APP_NAME] # Create backup mkdir /backups litefs export -name sqlite.db /backups/backup-$(date +%Y-%m-%d).db exit # Download backup fly ssh sftp get /backups/backup-2024-01-01.db --app [YOUR_APP_NAME] ``` **Restore backup:** ```bash # Upload backup fly ssh sftp shell --app [YOUR_APP_NAME] put backup-2024-01-01.db # Ctrl+C to exit # SSH and restore fly ssh console --app [YOUR_APP_NAME] litefs import -name sqlite.db /backup-2024-01-01.db exit ``` ### Deployment Local **Deploy con Fly CLI:** ```bash fly deploy ``` **Deploy con Docker:** ```bash # Build docker build -t epic-stack . -f other/Dockerfile \ --build-arg COMMIT_SHA=$(git rev-parse --short HEAD) # Run docker run -d \ -p 8081:8081 \ -e SESSION_SECRET='secret' \ -e HONEYPOT_SECRET='secret' \ -e FLY='false' \ -v ~/litefs:/litefs \ epic-stack ``` ### Zero-Downtime Deploys **Strategy:** - Deploy to multiple instances - Automatic blue-green deployment - Healthchecks verify app is ready - Auto-rollback if healthcheck fails **Configuration:** ```toml [experimental] auto_rollback = true ``` ### Monitoring **View logs:** ```bash fly logs --app [YOUR_APP_NAME] ``` **View metrics:** ```bash fly dashboard --app [YOUR_APP_NAME] # Or visit: https://fly.io/apps/[YOUR_APP_NAME]/monitoring ``` **Sentry (opcional):** ```bash fly secrets set SENTRY_DSN=your-sentry-dsn --app [YOUR_APP_NAME] ``` ## Common examples ### Example 1: Complete initial setup ```bash # 1. Create apps fly apps create my-app fly apps create my-app-staging # 2. Configure secrets fly secrets set \ SESSION_SECRET=$(openssl rand -hex 32) \ HONEYPOT_SECRET=$(openssl rand -hex 32) \ --app my-app fly secrets set \ SESSION_SECRET=$(openssl rand -hex 32) \ HONEYPOT_SECRET=$(openssl rand -hex 32) \ ALLOW_INDEXING=false \ --app my-app-staging # 3. Create volumes fly volumes create data --region sjc --size 1 --app my-app fly volumes create data --region sjc --size 1 --app my-app-staging # 4. Attach Consul fly consul attach --app my-app fly consul attach --app my-app-staging # 5. Create storage fly storage create --app my-app fly storage create --app my-app-staging # 6. Deploy fly deploy --app my-app ``` ### Example 2: Multi-region setup ```bash # First region (primary) - 2 instances fly scale count 2 --region sjc --app my-app # Secondary regions - 1 instance each fly scale count 1 --region ams --app my-app fly scale count 1 --region syd --app my-app # Verify fly status --app my-app ``` ### Example 3: GitHub Actions workflow ```yaml # .github/workflows/deploy.yml name: Deploy on: push: branches: [main, dev] jobs: deploy-production: if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: superfly/flyctl-actions/setup-flyctl@master - run: flyctl deploy --remote-only --app my-app env:
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub