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
-----BEGINhasta-----END). Esa es la clave que pegas en GitHub como secretVPS_SSH_KEY.
En GitHub (navegador):
- Ir a tu repo > Settings > Secrets and variables > Actions
- 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)
- Ir a GitHub > tu foto (esquina superior derecha) > Settings
- Ir a Developer settings > Personal access tokens > Tokens (classic)
- Clic en "Generate new token (classic)"
- Nombre:
deploy-admision| Expiracion: 90 dias o sin expiracion - Marcar permisos:
read:packages,write:packages - Clic en "Generate token"
- Copiar el token y guardarlo como secret
CR_PATen 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_PASSWORDes 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 diceTU_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_2026_estructura.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.prodnunca debe subirse al repositorio (esta en.gitignore) - Siempre usar
--env-file .env.proden 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