# Deploy Web - project.linkedcorp.net Arquetipo B (dos servicios separados). Primer deploy realizado el 2026-09-06. --- ## Instalación automatizada en un servidor NUEVO `scripts/install.sh` automatiza todo lo de esta sección para un servidor Debian/Ubuntu nuevo: verifica requisitos (Node.js, npm, cliente mysql, systemd, espacio, puertos libres), pregunta dominio/puertos y datos de base de datos (MariaDB local — se instala sola si hace falta — o un servidor existente), crea la base + usuario, genera `backend/.env` con secretos aleatorios, instala dependencias, corre migraciones + catálogos, compila el frontend y crea/arranca los servicios systemd. ```bash # En el servidor nuevo, ya con el repo clonado en /opt/apps/project.linkedcorp.net/source: cd /opt/apps/project.linkedcorp.net/source sudo scripts/install.sh ``` No configura el reverse proxy/TLS (paso 11 más abajo, específico de cada proveedor) ni crea ningún usuario: el primer registro público en `/registro` se vuelve superadministrador solo — no hace falta `create-admin.js` en instalaciones nuevas. Las secciones de abajo son la referencia manual (lo que hace el script paso a paso) — útiles para entender el porqué de cada cosa o para resolver un problema puntual sin volver a correr todo. **Requisito para el panel "Actualizaciones"** (Configuración → superadmin): el servidor instalado necesita poder llegar por HTTPS a `gitea.linkedcorp.net` de forma anónima (repo público + vista anónima habilitada en Gitea) para poder consultar el `CHANGELOG.md` y las migraciones nuevas. No requiere ningún token ni credencial. Si no hay conectividad a Gitea, ese panel simplemente muestra el error al buscar actualizaciones — el resto de la app funciona igual. --- ## Primer despliegue en producción (ya ejecutado — referencia) ### 1. Entrar al servidor ```bash ssh deploy@192.168.222.3 -p 2203 ``` ### 2. Crear estructura de directorios ```bash sudo mkdir -p /opt/apps/project.linkedcorp.net/{source,backend,frontend,storage,logs} sudo chown -R deploy:deploy /opt/apps/project.linkedcorp.net ``` ### 3. Clonar el repositorio ```bash cd /opt/apps/project.linkedcorp.net/source git clone http://[gitea_user]:[token]@gitea.linkedcorp.net/mgonzalez/project.linkedcorp.net.git . git remote set-url origin http://gitea.linkedcorp.net/mgonzalez/project.linkedcorp.net.git # sin token en claro ``` ### 4. Crear el `.env` de producción ```bash nano /opt/apps/project.linkedcorp.net/backend/.env ``` Variables reales (valores sensibles solo en el archivo del servidor, nunca en git): ```env PORT=4019 NODE_ENV=production DB_HOST=192.168.222.32 DB_PORT=3306 DB_NAME=project_linkedcorp DB_USER=project_linkedcorp DB_PASSWORD=[generada por crear-db-prod.sh] JWT_SECRET=[openssl rand -hex 32] JWT_EXPIRES=8h CORS_ORIGIN=https://project.linkedcorp.net STORAGE_ROOT=/opt/apps/project.linkedcorp.net/storage ``` **Nunca copiar el `.env` de desarrollo.** ### 5. Instalar dependencias del backend ```bash cd /opt/apps/project.linkedcorp.net/source/backend npm install --omit=dev cp -r node_modules /opt/apps/project.linkedcorp.net/backend/ ``` ### 6. Compilar el frontend y publicar el runtime El frontend es un proceso separado (`serve` sirviendo el build). Runtime propio en `frontend/` con un `package.json` minimo (solo depende de `serve`) — evita copiar todo `node_modules` de Vite: ```bash cd /opt/apps/project.linkedcorp.net/source/frontend npm install npm run build cp -r dist /opt/apps/project.linkedcorp.net/frontend/dist cat > /opt/apps/project.linkedcorp.net/frontend/package.json <<'EOF' { "name": "project-linkedcorp-frontend-runtime", "private": true, "version": "1.0.0", "dependencies": { "serve": "^14.2.6" } } EOF cd /opt/apps/project.linkedcorp.net/frontend && npm install --omit=dev ``` > En un redeploy solo hace falta reemplazar `frontend/dist` (borrar y volver a copiar) — el > `node_modules` del runtime frontend no cambia salvo que cambie la version de `serve`. ### 7. Ejecutar migración de base de datos ```bash cd /opt/apps/project.linkedcorp.net/source/backend set -a && source /opt/apps/project.linkedcorp.net/backend/.env && set +a node src/scripts/migrate-db.js ``` ### 8. Inicializar datos ```bash # Catalogos base (roles, prioridades, estados, tipos de proyecto) — sin datos de ejemplo en produccion: node src/scripts/seed-db.js # Usuario Administrador inicial (clave fuerte generada, se muestra UNA sola vez): node src/scripts/create-admin.js "Nombre Apellido" correo@linkedcorp.net ``` ### 9. Crear el servicio systemd del backend ```ini # /etc/systemd/system/project-linkedcorp-backend.service [Unit] Description=project.linkedcorp.net backend After=network.target [Service] Type=simple User=deploy WorkingDirectory=/opt/apps/project.linkedcorp.net/source/backend ExecStart=/usr/bin/node src/server.js EnvironmentFile=/opt/apps/project.linkedcorp.net/backend/.env Restart=on-failure RestartSec=5 StandardOutput=append:/opt/apps/project.linkedcorp.net/logs/backend.log StandardError=append:/opt/apps/project.linkedcorp.net/logs/backend-error.log [Install] WantedBy=multi-user.target ``` ### 10. Crear el servicio systemd del frontend ```ini # /etc/systemd/system/project-linkedcorp-frontend.service [Unit] Description=project.linkedcorp.net frontend After=network.target [Service] Type=simple User=deploy WorkingDirectory=/opt/apps/project.linkedcorp.net/frontend ExecStart=/usr/bin/node node_modules/.bin/serve -s dist -l 5196 Restart=on-failure RestartSec=5 StandardOutput=append:/opt/apps/project.linkedcorp.net/logs/frontend.log StandardError=append:/opt/apps/project.linkedcorp.net/logs/frontend-error.log [Install] WantedBy=multi-user.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable project-linkedcorp-backend project-linkedcorp-frontend sudo systemctl start project-linkedcorp-backend project-linkedcorp-frontend sudo systemctl status project-linkedcorp-backend project-linkedcorp-frontend ``` ### 11. Configurar Nginx Proxy Manager Proxy Host: | Campo | Valor | |-------|-------| | Domain | `project.linkedcorp.net` | | Forward Hostname/IP | `192.168.222.3` | | Forward Port | `5196` (frontend) | | Scheme | `http` | | SSL | Let's Encrypt, Force SSL | Custom Location: | Campo | Valor | |-------|-------| | Location | `/api` | | Forward Hostname/IP | `192.168.222.3` | | Forward Port | `4019` (backend) | | Scheme | `http` | ### 12. Verificar ```bash curl http://127.0.0.1:4019/health curl -o /dev/null -w "%{http_code}\n" http://127.0.0.1:5196/ curl https://project.linkedcorp.net/api/auth/login -X POST -H 'Content-Type: application/json' -d '{...}' ``` ### 13. Limpiar archivos `.md` del source ```bash find /opt/apps/project.linkedcorp.net/source -type f -iname '*.md' -delete ``` > Pendiente al 2026-09-06: no ejecutado en el primer deploy (bloqueado por el entorno del agente > que hizo el despliegue). Ejecutar manualmente o en el proximo deploy. --- ## Actualizaciones (deploys posteriores) 1. Cambios en desarrollo, `npm run build` local OK. 2. Si corresponde, subir version (`VERSIONADO.md`): actualizar `VERSION` y `CHANGELOG.md`. 3. `git add . && git commit -m "..." && git push origin main`. 4. `ssh deploy@192.168.222.3 -p 2203` 5. `cd /opt/apps/project.linkedcorp.net/source && git fetch origin main && git reset --hard origin/main` 6. Si cambio el backend: ```bash cd backend && npm install --omit=dev cp -r node_modules /opt/apps/project.linkedcorp.net/backend/ ``` 7. Si cambio el frontend: ```bash cd ../frontend && npm install && npm run build rm -rf /opt/apps/project.linkedcorp.net/frontend/dist cp -r dist /opt/apps/project.linkedcorp.net/frontend/dist ``` 8. Si cambio el schema de BD: ```bash cd ../backend set -a && source /opt/apps/project.linkedcorp.net/backend/.env && set +a node src/scripts/migrate-db.js ``` 9. Confirmar `DB_HOST=192.168.222.32` en el `.env` de produccion antes de reiniciar. 10. Reiniciar servicios: ```bash sudo systemctl restart project-linkedcorp-backend sudo systemctl restart project-linkedcorp-frontend ``` 11. **Confirmar cambio de PID** (si cambio el backend): ```bash ps -ef | grep 'node src/server.js' | grep -v grep ``` 12. Verificar: `curl http://127.0.0.1:4019/health`. 13. Limpiar `.md`: `find /opt/apps/project.linkedcorp.net/source -type f -iname '*.md' -delete`. --- ## No tocar durante deploy - `/opt/apps/project.linkedcorp.net/backend/.env` - `/opt/apps/project.linkedcorp.net/storage/` - `/opt/apps/project.linkedcorp.net/logs/` ## Notas - `.env` de produccion nunca se versiona ni se copia desde desarrollo. - BD de produccion siempre `192.168.222.32`; desarrollo siempre `192.168.222.20`. Confirmar antes de cada deploy. - `create-admin.js` es idempotente por email (`ON DUPLICATE KEY UPDATE`) — reutilizable para resetear la clave del admin si hace falta (genera una nueva clave fuerte cada vez que se corre).