iqjvqhelkebjnwjplyhj desde Supabase Cloud + Netlify + Cloudflare a AWS. Marca cada tarea con un click — tu progreso se guarda automáticamente en este navegador. Tiempo estimado: 4–6 h (divisible en 2 sesiones).
📋 Cómo usar esta guía
Cada tarea tiene una casilla a la izquierda. Click para marcarla como hecha — verás un check verde y la tarea queda tachada. El progreso se guarda en tu navegador (localStorage), así que si cierras la pestaña y vuelves más tarde, sigues donde lo dejaste.
La barra de progreso de arriba se mueve automáticamente. Cuando completas todas las tareas de una sección, esa sección entera se pone en verde 🟢.
El índice "Progreso global" (sección siguiente) te muestra de un golpe en qué sección vas — útil tras un descanso.
Si prefieres empezar de cero, abajo a la derecha tienes un botón ↺ Reset.
🟢 Progreso global
- Sección 0 — Rotar credenciales (5 min, urgente)0/3
- Sección 1 — Resumen del plan0/1
- Sección 2 — Preparar tu Windows0/7
- Sección 3 — Backup de Supabase con la CLI0/8
- Sección 4 — Cuenta AWS y configuración inicial0/10
- Sección 5 — Lanzar la instancia Lightsail0/4
- Sección 6 — Instalar Docker en la instancia0/6
- Sección 7 — Desplegar Supabase con Docker0/7
- Sección 8 — HTTPS con Caddy0/4
- Sección 9 — Migrar datos al servidor nuevo0/10
- Sección 10 — Configurar Google OAuth + SMTP0/7
- Sección 11 — Subir el frontend a S3 + CloudFront0/5
- Sección 12 — Mover el Worker a Lambda0/7
- Sección 13 — Dominio Nominalia → Route 530/9
- Sección 14 — Actualizar el index.html0/5
- Sección 15 — Probar todo0/12
- Sección 16 — Backups automáticos0/7
- Sección 17 — Costes mensuales—
- Sección 18 — Limpiar Netlify, Supabase Cloud, Cloudflare (1 sem después)0/5
- Sección 19 — Problemas frecuentes—
- Sección 20 — Rollback de emergencia0/3
⚠️ Sección 0 — ANTES DE NADA: rotar credenciales
-
0.1Rotar API key de Anthropic
- Entra a console.anthropic.com → Settings → API Keys
- Junto a la key actual → Revoke
- Create Key → nombre
micampo-aws→ copia la nueva - Guárdala en un gestor de contraseñas (1Password, Bitwarden, KeePass)
-
0.2Rotar contraseña del Postgres de Supabase
- supabase.com → tu proyecto
iqjvqhelkebjnwjplyhj→ Settings → Database - Junto a "Database password" → Reset database password
- Genera una sin caracteres especiales (
@/?#:) — solo letras, números,_,- - Cópiala antes de cerrar el modal — Supabase no la vuelve a mostrar
- La llamaremos <SUPABASE_DB_PASS> en el resto de la guía
- supabase.com → tu proyecto
-
0.3Crear
secretos-migracion.txten localUna hoja de ruta donde apuntar todo según lo vayas generando. Te ahorra mil idas y venidas.
PROJECT_REF = iqjvqhelkebjnwjplyhj SUPABASE_DB_PASS = (la nueva del paso 0.2) ANTHROPIC_KEY = (la nueva del paso 0.1) POSTGRES_PASS_NEW = (lo generas en el paso 7.2) JWT_SECRET = (lo generas en el paso 7.2) ANON_KEY = (lo generas en el paso 7.3) SERVICE_ROLE_KEY = (lo generas en el paso 7.3) DASHBOARD_PASS = (lo generas en el paso 7.2) LIGHTSAIL_IP = (paso 5.2) LAMBDA_URL = (paso 12.6) CLOUDFRONT_DOMAIN = (paso 11.3) CLOUDFRONT_DIST_ID = (paso 11.3) ACM_CERT_ARN = (paso 13.6) ROUTE53_NAMESERVERS= (paso 13.1)
Sección 1 — Resumen del plan
-
1.1Entender qué se mueve a dónde
Pieza Hoy Mañana index.htmlNetlify S3 + CloudFront Postgres + Auth + Realtime + Storage Supabase Cloud Supabase self-hosted en Lightsail Proxy IA Cloudflare Worker Lambda + Function URL DNS / dominio Nominalia Route 53 (delegando) Subdominios objetivo:
micampoconia.comyapp.micampoconia.com→ frontendapi.micampoconia.com→ API Supabasestudio.micampoconia.com→ panel admin Supabase
Sección 2 — Preparar tu Windows
Abre PowerShell como administrador (botón derecho en menú inicio → Windows PowerShell (Admin)).
-
2.1Instalar AWS CLI
Cierra y abre PowerShell. Verifica:winget install -e --id Amazon.AWSCLIaws --version -
2.2Instalar Git
winget install -e --id Git.Git -
2.3Instalar Node.js LTS
Cierra y abre PowerShell. Verifica:winget install -e --id OpenJS.NodeJS.LTSnode --version(v20.x) -
2.4Instalar Supabase CLI
Verifica:npm install -g supabasesupabase --version. Si falla por permisos, usanpx supabase. -
2.5Instalar PostgreSQL client tools
Durante la instalación marca solo "Command Line Tools", desmarca el resto.winget install -e --id PostgreSQL.PostgreSQL.16 -
2.6Añadir Postgres al PATH (si no lo hizo el instalador)
- Inicio → "Editar las variables de entorno del sistema"
- Variables de entorno → en "Variables del sistema" busca
Path→ Editar → Nuevo → pegaC:\Program Files\PostgreSQL\16\bin - Aceptar, cerrar todas las PowerShell, abrir una nueva
- Verifica:
psql --version
-
2.7Verificar SSH cliente
Si no responde: Settings → Apps → Optional features → Add → OpenSSH Clientssh -V
Sección 3 — Backup de Supabase con la CLI
-
3.1Login en la CLI
Abre el navegador → autorizas → vuelves a la terminal.supabase login -
3.2Crear carpeta del proyecto
cd $HOME\Desktop mkdir micampo-migracion cd micampo-migracion supabase init -
3.3Linkar al proyecto cloud
Te pide la password de DB (la del paso 0.2).supabase link --project-ref iqjvqhelkebjnwjplyhj -
3.4Pull del esquema completo
Generasupabase db pullsupabase/migrations/00000000000000_remote_schema.sql. -
3.5Dump de los datos
supabase db dump --data-only -f data.sql --use-copy -
3.6Dump de los roles (por si acaso)
supabase db dump --role-only -f roles.sql -
3.7Backup del archivo de Storage
- Supabase → tu proyecto → Storage
- Localiza el bucket y el archivo
- Click → Download → guarda en
micampo-migracion/storage-backup/ - Apunta el path completo dentro del bucket
-
3.8Copiar carpeta a OneDrive / disco externo (es tu seguro)
Sección 4 — Cuenta AWS y configuración inicial
-
4.1Crear cuenta AWS
- aws.amazon.com/es → Crear una cuenta de AWS
- Email:
aliaauicha@gmail.com, contraseña LARGA y única - Nombre cuenta:
Mi Campo - Tarjeta: pueden cargar 1 € que devuelven
- Soporte: Basic (gratis)
-
4.2Activar MFA en la cuenta root (NO negociable)
- Arriba derecha (tu nombre) → Security credentials
- Multi-factor authentication (MFA) → Assign MFA device
- Authenticator app → escanea QR con Google Authenticator/Authy
- Mete dos códigos consecutivos
-
4.3Crear usuario IAM
aliaa-admin- Buscar IAM → Users → Create user
- Username:
aliaa-admin - ✅ "Provide user access to the AWS Management Console" → Custom password
- ❌ Desmarca "Users must create a new password at next sign-in"
- Next → Attach policies directly → marca
AdministratorAccess - Next → Create user
- Apunta URL del console y Account ID
-
4.4Activar MFA para
aliaa-adminMismo proceso del 4.2 pero seleccionando este usuario. -
4.5Cerrar sesión del root y entrar con
aliaa-admin -
4.6Cambiar región a MadridArriba a la derecha → Europa (España) – eu-south-2
-
4.7Crear access key para AWS CLI
- IAM → Users →
aliaa-admin→ Security credentials - Access keys → Create access key → CLI → marca aviso → Next
- Description:
cli-windows - GUARDA el Access Key ID y el Secret (el secret solo se ve UNA vez)
- IAM → Users →
-
4.8Configurar AWS CLI en local
Pega Access Key ID, Secret, regionaws configureeu-south-2, formatjson. -
4.9Verificar
Debe devolver tu Account ID + ARN.aws sts get-caller-identity -
4.10Crear alerta de presupuesto
- Tu nombre → Billing and Cost Management
- Budgets → Create budget → Use a template → Monthly cost
- Name:
aviso-50-USD. Amount:50USD. Email:aliaauicha@gmail.com - Create budget
Sección 5 — Lanzar la instancia Lightsail
-
5.1Crear instancia
- Buscar Lightsail → entrar
- Si Lightsail no aparece en Madrid, cambia región dentro de Lightsail a París (eu-west-3)
- Create instance
- Platform: Linux/Unix
- Blueprint: OS Only → Ubuntu 22.04 LTS
- Plan: 40 USD/mes (8 GB RAM, 2 vCPU, 160 GB SSD)
- Nombre:
micampo-backend - Create instance
-
5.2IP estática (gratis)
- Lightsail → Networking → Create static IP
- Selecciona región e instancia
micampo-backend - Nombre:
micampo-ip - Apunta la IP como <LIGHTSAIL_IP>
-
5.3Verificar firewall
- Instancia → Networking → IPv4 Firewall
- Confirma abiertos: SSH 22, HTTP 80, HTTPS 443
-
5.4Conectar por SSH (terminal en navegador)Botón naranja Connect using SSH en la instancia → abre terminal en navegador. Sirve perfecto.
Sección 6 — Instalar Docker en la instancia
Dentro del SSH (eres usuario ubuntu):
-
6.1Actualizar sistema
sudo apt update && sudo apt upgrade -y -
6.2Instalar dependencias
sudo apt install -y ca-certificates curl gnupg lsb-release git -
6.3Añadir repositorio oficial Docker
sudo mkdir -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null -
6.4Instalar Docker + Compose
sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -
6.5Permitir docker sin sudo
sudo usermod -aG docker $USER exit -
6.6Reconectar y verificar
docker --version docker compose version
Sección 7 — Desplegar Supabase con Docker
-
7.1Clonar el stack
cd ~ git clone --depth 1 https://github.com/supabase/supabase.git cp -r supabase/docker ~/supabase-stack cd ~/supabase-stack cp .env.example .env -
7.2Generar las claves seguras
Copia las 3 a tuecho "POSTGRES_PASS_NEW: $(openssl rand -hex 24)" echo "JWT_SECRET: $(openssl rand -base64 48)" echo "DASHBOARD_PASS: $(openssl rand -base64 16)"secretos-migracion.txtahora mismo. -
7.3Generar ANON_KEY y SERVICE_ROLE_KEY
- Abre supabase.com/docs/guides/self-hosting/docker#generate-api-keys
- Pega tu
JWT_SECRET - Te genera dos JWTs (
eyJhbGc...) - Guarda el anon como
ANON_KEYy el service_role comoSERVICE_ROLE_KEY
-
7.4Editar
.env
Sustituye estas variables (lo demás puede quedarse):nano .env
Guardar:POSTGRES_PASSWORD=<POSTGRES_PASS_NEW> JWT_SECRET=<JWT_SECRET> ANON_KEY=<ANON_KEY> SERVICE_ROLE_KEY=<SERVICE_ROLE_KEY> DASHBOARD_USERNAME=admin DASHBOARD_PASSWORD=<DASHBOARD_PASS> SITE_URL=https://app.micampoconia.com API_EXTERNAL_URL=https://api.micampoconia.com SUPABASE_PUBLIC_URL=https://api.micampoconia.com ADDITIONAL_REDIRECT_URLS=https://micampoconia.com,https://app.micampoconia.com ENABLE_EMAIL_SIGNUP=true ENABLE_EMAIL_AUTOCONFIRM=false SMTP_ADMIN_EMAIL=aliaauicha@gmail.comCtrl+O,Enter,Ctrl+X -
7.5Levantar Supabase
Primera vez tarda 5-10 min descargando imágenes.docker compose pull docker compose up -d -
7.6Verificar que todo está running
~10 serviciosdocker compose psUpohealthy. Si alguno falla:docker compose logs <nombre-servicio> --tail 50 -
7.7Probar la API localmente
Debe devolver JSON. ✓ Si responde, el backend está vivo. 🎉curl http://localhost:8000/rest/v1/ -H "apikey: <ANON_KEY>"
Sección 8 — HTTPS con Caddy
-
8.1Instalar Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install -y caddy -
8.2Generar hash de password del Studio
Pega lacaddy hash-password<DASHBOARD_PASS>cuando pida. Copia el hash que empieza por$2a$... -
8.3Configurar Caddyfile
Reemplaza el contenido entero por:sudo nano /etc/caddy/Caddyfileapi.micampoconia.com { reverse_proxy localhost:8000 { transport http { keepalive 600s } } } studio.micampoconia.com { basicauth { admin <PEGA_AQUI_EL_HASH> } reverse_proxy localhost:3000 } -
8.4Recargar Caddy
Debe decirsudo systemctl reload caddy sudo systemctl status caddyactive (running). Los certificados fallarán hasta que apuntes los DNS (paso 13). Es esperado.
Sección 9 — Migrar datos al servidor nuevo
-
9.1Exponer Postgres temporalmente (en SSH del Lightsail)
Busca el serviciocd ~/supabase-stack docker compose stop db sudo nano docker-compose.ymldb:y añade dentro:
Guardar y reiniciar:ports: - "5432:5432"docker compose up -d db -
9.2Abrir puerto 5432 en firewall SOLO a tu IP
- Lightsail → instancia → Networking → Add rule
- Application: Custom. Protocol: TCP. Port: 5432
- Restrict to IP: tu IP pública (busca "cuál es mi IP" en Google)
- Save
-
9.3Aplicar el esquema desde Windows
Veráscd $HOME\Desktop\micampo-migracion $env:PGPASSWORD = "<POSTGRES_PASS_NEW>" psql "host=<LIGHTSAIL_IP> port=5432 user=postgres dbname=postgres sslmode=require" -f supabase\migrations\00000000000000_remote_schema.sqlNOTICEy algúnERROR("extension already exists") — son normales. -
9.4Verificar tablas
Debes verpsql "host=<LIGHTSAIL_IP> port=5432 user=postgres dbname=postgres sslmode=require" -c "\dt public.*"gastos,ventas,jornadas,fincas, etc. -
9.5Aplicar los datos
psql "host=<LIGHTSAIL_IP> port=5432 user=postgres dbname=postgres sslmode=require" -f data.sql -
9.6Verificar contadores coinciden
psql "host=<LIGHTSAIL_IP> port=5432 user=postgres dbname=postgres sslmode=require" -c "select count(*) from public.gastos;" psql "host=<LIGHTSAIL_IP> port=5432 user=postgres dbname=postgres sslmode=require" -c "select count(*) from public.fincas;" -
9.7Cerrar puerto 5432 en firewallLightsail → Networking → borra la regla del 5432.
-
9.8Quitar
portsdel docker-compose (recomendado)sudo nano docker-compose.yml # borra las dos líneas "ports: 5432:5432" dentro de db: docker compose up -d db -
9.9Crear tu cuenta admin en el Supabase nuevo
Esto puede esperar al paso 13 cuando tengas el Studio HTTPS accesible.
- Studio → Authentication → Users → Add user → Create new user
- Email:
aliaauicha@gmail.com. Password: la que quieras - ✅ "Auto Confirm User" → Create
-
9.10Migrar el archivo de Storage
- Studio → Storage → New bucket
- Nombre igual al del original. Marca "Public bucket" si lo era
- Upload → arrastra el archivo del
storage-backup/ - Comprueba que el path coincide con lo esperado por la app
Sección 10 — Configurar Google OAuth + SMTP
-
10.1Añadir redirect URI en Google Cloud
- console.cloud.google.com → tu proyecto
- APIs & Services → Credentials
- Click en tu OAuth 2.0 Client ID
- Authorized redirect URIs → Add URI →
https://api.micampoconia.com/auth/v1/callback - Save
-
10.2Configurar Google en Supabase nuevo
- Studio (
https://studio.micampoconia.com) → Authentication → Providers → Google - Activa toggle
- Pega Client ID y Client Secret de Google
- Save
- Studio (
-
10.3Verificar dominio en SES
- Consola AWS → SES (asegúrate región Madrid)
- Verified identities → Create identity
- Domain →
micampoconia.com - ✅ Use a custom MAIL FROM domain →
mail.micampoconia.com - ✅ DKIM signing (RSA 2048)
- Create identity
- APUNTA los 3-4 registros DNS que te da (CNAMEs DKIM + MX + TXT). Los crearás en Route 53 en el paso 13.
-
10.4Solicitar salida del sandbox SES
- SES → Account dashboard → "Request production access"
- Use case: "Transactional emails for Mi Campo, a farm management app"
- Website:
https://app.micampoconia.com - Expected emails/day:
100 - Submit (aprueban en horas o 1-2 días)
-
10.5Verificar tu propio email mientras sale del sandboxSES → Verified identities → Create identity → Email address →
aliaauicha@gmail.com. Te llega correo, clickas el enlace. -
10.6Crear credenciales SMTP
- SES → SMTP settings → Create SMTP credentials
- IAM user name:
ses-smtp-supabase→ Create - Download credentials o copia username/password (solo se ve una vez)
-
10.7Configurar SMTP en SupabaseStudio → Project Settings → Auth → SMTP Settings:
Save.Sender email: noreply@micampoconia.com Sender name: Mi Campo Host: email-smtp.eu-south-2.amazonaws.com Port: 587 Username: (de SES) Password: (de SES)
Sección 11 — Frontend en S3 + CloudFront
-
11.1Crear bucket S3
- Consola AWS → S3 → Create bucket
- Bucket name:
micampoconia-frontend(si está cogido pruebamicampoconia-frontend-aliaa) - Region: eu-south-2 Madrid
- ✅ Block all public access
- Create bucket
-
11.2Subir
index.html(versión actual, todavía apunta a Supabase Cloud)aws s3 cp index.html s3://micampoconia-frontend/index.html --content-type "text/html; charset=utf-8" --region eu-south-2 -
11.3Crear distribución CloudFront
- Consola → CloudFront → Create distribution
- Origin domain:
micampoconia-frontend.s3.eu-south-2.amazonaws.com - Origin access: Origin access control settings (recommended) → Create new OAC → defaults
- Viewer protocol policy: Redirect HTTP to HTTPS
- Allowed HTTP methods: GET, HEAD
- ✅ Compress objects automatically
- Default root object:
index.html - Create distribution
- Apunta el dominio
dXXXXX.cloudfront.netcomo <CLOUDFRONT_DOMAIN> y el ID como <CLOUDFRONT_DIST_ID>
-
11.4Pegar bucket policy en S3
- CloudFront → tu distribución → Origins → tu origin → Edit
- Desplázate al fondo → Copy policy
- S3 → tu bucket → Permissions → Bucket policy → Edit → pega → Save
-
11.5ProbarAbre
https://<CLOUDFRONT_DOMAIN>→ carga tu app (todavía conectada a Supabase Cloud viejo).
Sección 12 — Mover el Worker a Lambda
-
12.1Guardar API key en Secrets Manager (la NUEVA del paso 0.1)
- Consola AWS → Secrets Manager (Madrid)
- Store a new secret → Other type of secret → key/value:
- Key:
ANTHROPIC_API_KEY - Value:
sk-ant-api03-...(la nueva) - Next → Secret name:
micampo/anthropic-key→ Next → Next → Store - Apunta el ARN
-
12.2Crear función Lambda
- Consola → Lambda → Create function
- Author from scratch
- Function name:
micampo-ai-proxy - Runtime: Node.js 20.x
- Architecture: arm64
- Execution role: "Create a new role with basic Lambda permissions"
- Create function
-
12.3Pegar el código en
index.mjs
Pulsa Deploy.const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages'; let cachedKey = null; async function getApiKey() { if (cachedKey) return cachedKey; if (process.env.ANTHROPIC_API_KEY) { cachedKey = process.env.ANTHROPIC_API_KEY; return cachedKey; } const { SecretsManagerClient, GetSecretValueCommand } = await import('@aws-sdk/client-secrets-manager'); const sm = new SecretsManagerClient({}); const r = await sm.send(new GetSecretValueCommand({ SecretId: 'micampo/anthropic-key' })); const j = JSON.parse(r.SecretString); cachedKey = j.ANTHROPIC_API_KEY; return cachedKey; } const CORS = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'POST, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, anthropic-version, x-api-key', 'Access-Control-Max-Age': '86400' }; export const handler = async (event) => { const method = event.requestContext?.http?.method || 'POST'; if (method === 'OPTIONS') return { statusCode: 204, headers: CORS }; try { const apiKey = await getApiKey(); const body = event.isBase64Encoded ? Buffer.from(event.body, 'base64').toString() : (event.body || '{}'); const r = await fetch(ANTHROPIC_URL, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01' }, body }); const text = await r.text(); return { statusCode: r.status, headers: { ...CORS, 'Content-Type': 'application/json' }, body: text }; } catch (e) { return { statusCode: 500, headers: { ...CORS, 'Content-Type': 'application/json' }, body: JSON.stringify({ error: e.message }) }; } }; -
12.4Permisos para leer el secreto
- Configuration → Permissions → click en el "Role name" → IAM
- Add permissions → Attach policies → busca
SecretsManagerReadWrite→ marca → Add
-
12.5Aumentar timeout y memoria
- Configuration → General configuration → Edit
- Memory: 512 MB. Timeout: 30 seconds → Save
-
12.6Crear Function URL
- Configuration → Function URL → Create function URL
- Auth type: NONE
- ✅ Configure CORS
- Allow origin:
* - Allow methods: POST, OPTIONS
- Allow headers:
Content-Type,anthropic-version,x-api-key - Save
- Apunta la URL como <LAMBDA_URL>
-
12.7Probar Lambda
Debe devolver respuesta de Claude.$body = '{"model":"claude-haiku-4-5-20251001","max_tokens":50,"messages":[{"role":"user","content":"Di hola en una palabra"}]}' curl.exe -X POST <LAMBDA_URL> -H "Content-Type: application/json" -d $body
Sección 13 — Dominio Nominalia → Route 53
-
13.1Crear hosted zone en Route 53
- Consola AWS → Route 53 → Hosted zones → Create hosted zone
- Domain:
micampoconia.com. Type: Public - Create
- Apunta los 4 nameservers (
ns-XXX.awsdns-XX.com,.net,.co.uk,.org)
-
13.2Cambiar nameservers en Nominalia
- admin.nominalia.com → Mis productos → Dominios
- Click en
micampoconia.com - Busca Nameservers / Servidores DNS / Cambiar DNS
- Borra los actuales (ns1.nominalia.com, etc.)
- Pega los 4 de Route 53 (sin punto al final)
- Guardar
- Tarda 30 min – 24 h en propagar
-
13.3Verificar propagación
Cuando salgan losnslookup -type=ns micampoconia.comns-...awsdns-..., está listo. -
13.4Crear records DNS principales en Route 53
Nombre Tipo Valor api.micampoconia.comA <LIGHTSAIL_IP>studio.micampoconia.comA <LIGHTSAIL_IP>app.micampoconia.comA (Alias) distribución CloudFront micampoconia.com(raíz)A (Alias) misma distribución Para los Alias: marca toggle Alias → "Alias to CloudFront distribution" → selecciona del desplegable.
-
13.5Crear records DNS de SES (los del paso 10.3)
- 3 CNAMEs DKIM
xyz._domainkey.micampoconia.com→xyz.dkim.amazonses.com - MX
mail.micampoconia.com→10 feedback-smtp.eu-south-2.amazonses.com - TXT
mail.micampoconia.com→"v=spf1 include:amazonses.com ~all"
- 3 CNAMEs DKIM
-
13.6Solicitar certificado ACM (en N. Virginia ⚠️)CloudFront SOLO acepta certificados emitidos en
us-east-1. Es el único caso en toda la guía donde sales de Madrid.- Cambia región arriba a la derecha → N. Virginia (us-east-1)
- Certificate Manager → Request certificate → Public
- Domain names:
app.micampoconia.com,micampoconia.com - Validation: DNS validation
- Request
- En la pantalla de detalles → Create records in Route 53 → marca los 2 dominios → Create records
- Espera 2-10 min hasta estado Issued
- Apunta el ARN como <ACM_CERT_ARN>
-
13.7Adjuntar certificado a CloudFront
- Vuelve a Madrid (eu-south-2)
- CloudFront → tu distribución → Edit
- Alternate domain name (CNAMEs): añade
app.micampoconia.comymicampoconia.com - Custom SSL certificate: selecciona el ACM
- Save changes (CloudFront tarda 5-10 min en aplicar)
-
13.8Verificar conectividad
La última debe devolver JSON.nslookup api.micampoconia.com nslookup app.micampoconia.com curl https://api.micampoconia.com/rest/v1/ -H "apikey: <ANON_KEY>" -
13.9Verificar Caddy sacó certificados
sudo systemctl status caddy
Sección 14 — Actualizar el index.html
-
14.1Reemplazo 1 — URL SupabaseBuscar:
Reemplazar por:const SUPABASE_URL = 'https://iqjvqhelkebjnwjplyhj.supabase.co'const SUPABASE_URL = 'https://api.micampoconia.com' -
14.2Reemplazo 2 — Anon keyBuscar la línea entera
const SUPABASE_KEY = 'eyJhbGciOiJI...lGP4wmNi...'y reemplazar el valor por la<ANON_KEY>del paso 7.3. -
14.3Reemplazo 3 — URL del Worker (4 ocurrencias)Buscar TODAS las apariciones:
https://micampoconia.aliaauicha.workers.dev/
Reemplazar TODAS por:<LAMBDA_URL> -
14.4Subir versión nueva a S3
aws s3 cp index.html s3://micampoconia-frontend/index.html --content-type "text/html; charset=utf-8" --region eu-south-2 -
14.5Invalidar caché CloudFront
aws cloudfront create-invalidation --distribution-id <CLOUDFRONT_DIST_ID> --paths "/*"
Sección 15 — Probar todo
Abre https://app.micampoconia.com en ventana de incógnito (sin caché).
- 15.1La app carga
- 15.2El módulo "Precios" aparece como pantalla inicial
- 15.3Te puedes registrar / iniciar sesión con
aliaauicha@gmail.com - 15.4El login con Google funciona
- 15.5Ves tus fincas, gastos, ventas, jornadas migrados
- 15.6El asistente IA del chat responde (valida Lambda)
- 15.7Crear una finca nueva → guarda y persiste tras refrescar
- 15.8Subir una foto en Ventas funciona (valida Storage)
- 15.9Recibes email de prueba con "Forgot password" (valida SES)
- 15.10Stock muestra los items migrados
- 15.11Calendario carga
- 15.12Mensajes carga sin errores
Sección 16 — Backups automáticos
-
16.1Activar snapshots automáticos Lightsail
- Lightsail → instancia → Snapshots → Auto snapshot
- Hora: 03:00 UTC → Save
-
16.2Crear bucket de backups
aws s3 mb s3://micampoconia-backups --region eu-south-2 -
16.3Crear usuario IAM
lightsail-backup- IAM → Users → Create user → name
lightsail-backup - Attach policies → Create policy con este JSON:
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["s3:PutObject", "s3:ListBucket", "s3:DeleteObject"], "Resource": [ "arn:aws:s3:::micampoconia-backups", "arn:aws:s3:::micampoconia-backups/*" ] }] }- Nombre policy:
MicampoBackupS3→ Create - Asocia al user → Create user
- En el user → Security credentials → Create access key → CLI → guarda los dos
- IAM → Users → Create user → name
-
16.4Configurar AWS CLI dentro de la instancia (SSH)
sudo apt install -y awscli aws configure # Access Key ID: el de lightsail-backup # Secret: el de lightsail-backup # Region: eu-south-2 # Format: json -
16.5Crear script de backup
Pega:sudo nano /usr/local/bin/backup-supabase.sh
Permisos:#!/bin/bash set -e DATE=$(date +%Y%m%d-%H%M%S) DUMP=/tmp/supabase-$DATE.sql.gz docker compose -f /home/ubuntu/supabase-stack/docker-compose.yml exec -T db pg_dumpall -U postgres | gzip > $DUMP aws s3 cp $DUMP s3://micampoconia-backups/db/$DATE.sql.gz rm $DUMP aws s3 ls s3://micampoconia-backups/db/ | awk '{print $4}' | sort -r | tail -n +31 | xargs -I {} aws s3 rm s3://micampoconia-backups/db/{} echo "$DATE: backup OK"sudo chmod +x /usr/local/bin/backup-supabase.sh -
16.6Programar con cron
Añade al final:crontab -e0 3 * * * /usr/local/bin/backup-supabase.sh >> /var/log/backup-supabase.log 2>&1 -
16.7Probar el backup manualmente
/usr/local/bin/backup-supabase.sh aws s3 ls s3://micampoconia-backups/db/
Sección 17 — Costes mensuales
| Servicio | Coste/mes |
|---|---|
| Lightsail 8 GB RAM | 40 USD |
| Static IP | 0 USD |
| S3 (~2 GB) | < 1 USD |
| CloudFront (~10 GB) | ~1 USD |
| Lambda | < 1 USD |
| Route 53 hosted zone | 0,50 USD |
| ACM | 0 USD |
| SES (≤10k emails/mes) | < 1 USD |
| Secrets Manager | 0,40 USD |
| Snapshots Lightsail | ~2 USD |
| Backups S3 | < 1 USD |
| Total | ~46–48 USD/mes (~43-45 €) |
Sección 18 — Limpiar Netlify, Supabase Cloud, Cloudflare
-
18.1Pausar Supabase Cloudsupabase.com → tu proyecto → Settings → General → Pause project
-
18.2Borrar sitio de NetlifyNetlify → tu site → Site settings → Delete this site
-
18.3Borrar Worker de CloudflareWorkers & Pages → tu worker → ⋯ → Delete
-
18.4Borrar redirect URI viejo de Google OAuthGoogle Cloud Console → OAuth Client → en redirect URIs → borra el de
iqjvqhelkebjnwjplyhj.supabase.co -
18.5Tras 1 mes funcionando — borrar Supabase CloudSupabase → Settings → Delete project
Sección 19 — Problemas frecuentes
"401 Unauthorized" desde el frontend
La <ANON_KEY> no coincide con el JWT_SECRET del .env. Genera de nuevo.
"connection refused" al hacer SSH
Instancia sin RAM. En Lightsail → Reboot.
Email no llega
SES en sandbox. Verifica el destinatario en SES o solicita producción.
Caddy "re-attempting..." con certificados
DNS no propagados. Espera y sudo systemctl restart caddy.
Mensajes Realtime no actualizan
Falta keepalive 600s en Caddyfile (paso 8.3).
Login Google "redirect_uri_mismatch"
Falta el URI nuevo en Google Cloud Console (paso 10.1).
CloudFront sirve versión vieja
Lanza invalidación: aws cloudfront create-invalidation --distribution-id <ID> --paths "/*"
Lightsail no en Madrid
Cambia región dentro del propio Lightsail a París (eu-west-3).
Sección 20 — Rollback de emergencia
Si algo sale catastróficamente mal:
-
20.1Cambiar A record de
app.micampoconia.comen Route 53 al sitio Netlify (*.netlify.app) -
20.2Restaurar
index.htmlviejo a Netlify conSUPABASE_URLySUPABASE_KEYoriginales -
20.3En 5 min los DNS propagan, vuelves al estado anterior
Cualquier paso que se atasque, copia el error en el chat y lo desatascamos al momento.
Empieza por la Sección 0 ahora mismo. Es 5 minutos y es lo único urgente. 🚀