You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11 KiB

Deploy en Produccion (Docker + CI/CD) - Direccion de Admision 2026

Todo el proyecto se dockeriza y se despliega mediante GitHub Actions. Las imagenes se construyen en GitHub y se suben a GitHub Container Registry (GHCR). El VPS solo descarga y ejecuta.

Resumen rapido — ¿Que hago yo?

Setup inicial (solo una vez, ~25 min)

Paso Que haces Donde Tiempo
1 Pegar 6 secrets en GitHub Navegador (GitHub Settings) 5 min
2 Conectar al VPS, clonar repo, crear .env.prod y editar valores Terminal SSH 10 min
3 Copiar/pegar 2 comandos para MySQL + importar dump Terminal SSH 2 min
4 Clic en "Run workflow" en GitHub Actions y esperar Navegador (GitHub Actions) 3 min
5 Copiar/pegar 2 comandos (storage link + seeders) Terminal SSH 1 min
6 Copiar/pegar server block de nginx + correr certbot Terminal SSH 5 min

Deploys del dia a dia

Tu haces Que pasa
git push a main Nada (hasta que tu decidas)
Clic en "Run workflow" en GitHub Actions Build + Push al registry + Deploy al VPS (~3 min)

No tocas terminal, no compilas, no haces SSH. Solo un clic desde el navegador.


Arquitectura de deploy

  Tu PC                 GitHub                  GHCR              VPS
    |                      |                      |                |
    | git push            |                      |                |
    | ──────────►   [main branch]                |                |
    |                      |                      |                |
    |              [GitHub Actions]               |                |
    |              (trigger manual)               |                |
    |                      |                      |                |
    |              Build backend  ──────►  ghcr.io/.../backend    |
    |              Build frontend ──────►  ghcr.io/.../frontend   |
    |                      |                      |                |
    |              SSH al VPS ────────────────────────────►       |
    |                      |                      |    docker pull |
    |                      |                      |    docker up   |
    |                      |                      |     App lista  |

Arquitectura de contenedores

                    Puerto 80/443
                         |
                  [nginx del host]  ← SSL/Certbot
                         |
                    proxy_pass
                         |
                  127.0.0.1:8080
                         |
                  [nginx container]  (reverse proxy)
                    /         \
         /api/*   /           \   /*
                 /             \
          [backend]         [frontend]
          PHP-FPM            nginx+SPA
          :9000               :80
              |
           [mysql]
            :3306

De donde sale cada credencial

Hay 3 lugares donde se ponen credenciales. Esta tabla explica cada una y como obtenerla:

A. Archivo .env.prod (en el VPS)

Credencial Como la obtienes
APP_KEY Ejecutas php -r "echo 'base64:'.base64_encode(random_bytes(32)).PHP_EOL;" en tu PC y copias el resultado
DB_PASSWORD La inventas tu. Para generar una segura: openssl rand -base64 32
APP_URL Tu dominio (ej: https://admision.tu-universidad.edu.pe)
SESSION_DOMAIN Tu dominio sin https (ej: admision.tu-universidad.edu.pe)
SANCTUM_STATEFUL_DOMAINS Igual que SESSION_DOMAIN
GITHUB_REPO Tu usuario/repo de GitHub (ej: juanperez/direccion_de_admision_2026)
MAIL_PASSWORD Te lo da tu proveedor SMTP (Gmail, Mailgun, etc.)

B. GitHub Secrets (en el navegador)

Secret Como lo obtienes
VPS_HOST La IP de tu droplet, la ves en el panel de DigitalOcean
VPS_USER Normalmente root
VPS_SSH_KEY El contenido de la clave privada SSH (ver paso 1 abajo)
VPS_PORT Normalmente 22
VPS_PROJECT_PATH La ruta donde clonas el repo (ej: /root/direccion_de_admision_2026)
CR_PAT Token que generas en GitHub > Settings > Developer settings > Tokens

C. Se generan automaticamente (no los tocas)

Credencial Descripcion
GITHUB_TOKEN GitHub Actions lo crea solo en cada ejecucion
MYSQL_ROOT_PASSWORD Docker lo lee de DB_PASSWORD del .env.prod

Setup inicial (solo la primera vez)

1. Crear clave SSH en el VPS y configurar secrets en GitHub

GitHub Actions necesita conectarse al VPS por SSH. Si actualmente entras con contraseña, necesitas crear una clave SSH.

En el VPS (conectate con tu contraseña como siempre):

# Generar clave SSH para GitHub Actions
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions -N ""

# Agregar la clave publica a las claves autorizadas
cat ~/.ssh/github_actions.pub >> ~/.ssh/authorized_keys

# Mostrar la clave PRIVADA (la que copias a GitHub)
cat ~/.ssh/github_actions

Copia TODO el contenido que muestra el ultimo comando (desde -----BEGIN hasta -----END). Esa es la clave que pegas en GitHub como secret VPS_SSH_KEY.

En GitHub (navegador):

  1. Ir a tu repo > Settings > Secrets and variables > Actions
  2. Clic en "New repository secret" y agregar uno por uno:
Secret Que pegar
VPS_HOST La IP de tu droplet (ej: 164.92.xxx.xxx)
VPS_USER root
VPS_SSH_KEY El contenido completo de ~/.ssh/github_actions (clave privada)
VPS_PORT 22
VPS_PROJECT_PATH /root/direccion_de_admision_2026
CR_PAT El token generado en el siguiente paso

Generar el CR_PAT (Personal Access Token)

  1. Ir a GitHub > tu foto (esquina superior derecha) > Settings
  2. Ir a Developer settings > Personal access tokens > Tokens (classic)
  3. Clic en "Generate new token (classic)"
  4. Nombre: deploy-admision | Expiracion: 90 dias o sin expiracion
  5. Marcar permisos: read:packages, write:packages
  6. Clic en "Generate token"
  7. Copiar el token y guardarlo como secret CR_PAT en el repo

2. Preparar el VPS

En el VPS (por SSH):

# Instalar Docker si no lo tienes
curl -fsSL https://get.docker.com | sh

# Clonar el repo
git clone <url-del-repo> direccion_de_admision_2026
cd direccion_de_admision_2026

# Configurar variables de entorno
cp .env.prod.example .env.prod

Editar .env.prod:

nano .env.prod

Cambiar estos valores obligatoriamente:

APP_KEY=               # Pegar la clave generada (ver abajo)
APP_URL=https://tu-dominio.com
DB_PASSWORD=           # Pegar la password generada (ver abajo)
SESSION_DOMAIN=tu-dominio.com
SANCTUM_STATEFUL_DOMAINS=tu-dominio.com
GITHUB_REPO=tu-usuario/tu-repo

Para generar APP_KEY (en tu PC local si no hay PHP en el VPS):

php -r "echo 'base64:'.base64_encode(random_bytes(32)).PHP_EOL;"

Para generar DB_PASSWORD:

openssl rand -base64 32

Asegurar permisos del archivo:

chmod 600 .env.prod

Credenciales de la base de datos

La base de datos MySQL se crea automaticamente con estos valores (definidos en .env.prod):

Variable Valor Descripcion
DB_HOST mysql Nombre del contenedor Docker (no cambiar)
DB_PORT 3306 Puerto interno de MySQL (no cambiar)
DB_DATABASE admision_2026 Nombre de la base de datos
DB_USERNAME root Usuario de MySQL
DB_PASSWORD Lo que pongas en .env.prod La misma password para todo: MySQL root y conexion Laravel

Importante: La password que pongas en DB_PASSWORD es la que usa Docker para crear el usuario root de MySQL y la que usa Laravel para conectarse. Debe ser la misma en ambos casos porque es una sola variable. Esta misma password es la que usas en los comandos de importacion donde dice TU_PASSWORD.


3. Levantar MySQL e importar la base de datos

docker compose --env-file .env.prod -f docker-compose.prod.yml up -d mysql

Esperar ~10 segundos y luego importar:

docker exec -i admision_prod_db mysql -uroot -pTU_PASSWORD admision_2026 < admision_2006-vI.sql

Verificar:

docker exec admision_prod_db mysql -uroot -pTU_PASSWORD admision_2026 -e "SHOW TABLES;"

4. Primer deploy

Ir a GitHub > pestaña Actions > seleccionar "Build & Deploy" > clic en "Run workflow" > marcar "Desplegar en el VPS" > confirmar.

GitHub Actions construira las imagenes, las subira al registry y las desplegara en el VPS.


5. Post-deploy (solo la primera vez)

# Crear enlace de storage
docker exec admision_prod_backend php artisan storage:link

# Ejecutar seeders
docker exec admision_prod_backend php artisan db:seed --class=RoleSeeder --force

6. Configurar nginx del host como proxy

Crear o editar el server block:

sudo nano /etc/nginx/sites-available/tu-dominio.com
server {
    listen 80;
    server_name tu-dominio.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        client_max_body_size 25M;
    }
}
sudo ln -sf /etc/nginx/sites-available/tu-dominio.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Para HTTPS:

sudo certbot --nginx -d tu-dominio.com

Deploys posteriores

Solo necesitas ir a GitHub > Actions > Run workflow. Eso es todo.

O si prefieres activar deploy automatico en cada push a main, edita .github/workflows/deploy.yml y agrega:

on:
  workflow_dispatch:
  push:
    branches: [main]

Comandos utiles en el VPS

# Ver logs
docker compose --env-file .env.prod -f docker-compose.prod.yml logs -f

# Ver logs de un servicio
docker compose --env-file .env.prod -f docker-compose.prod.yml logs -f backend

# Reiniciar todo
docker compose --env-file .env.prod -f docker-compose.prod.yml restart

# Detener todo
docker compose --env-file .env.prod -f docker-compose.prod.yml down

# Ejecutar comandos artisan
docker exec admision_prod_backend php artisan migrate --force
docker exec admision_prod_backend php artisan cache:clear

# Ver que imagenes estan corriendo
docker compose --env-file .env.prod -f docker-compose.prod.yml ps

Rollback (volver a una version anterior)

Cada imagen se etiqueta con el SHA del commit. Para volver a una version anterior:

# En .env.prod cambiar IMAGE_TAG al SHA del commit deseado
IMAGE_TAG=abc123def456

# Recrear contenedores
docker compose --env-file .env.prod -f docker-compose.prod.yml up -d --force-recreate backend frontend nginx

Notas de produccion

  • Los datos de MySQL se persisten en un volumen Docker (mysql_data)
  • El storage de Laravel se persiste en un volumen Docker (backend_storage)
  • El archivo .env.prod nunca debe subirse al repositorio (esta en .gitignore)
  • Siempre usar --env-file .env.prod en los comandos de Docker Compose
  • Las imagenes en GHCR son privadas (solo tu cuenta las ve)
  • Para HTTPS, usar Certbot en el nginx del host