Video tutorial 1

Instalar CRM-LAB en un VPS con un agente de IA

Vas a llevar un servidor Ubuntu vacío hasta un CRM con HTTPS, la primera cuenta de administrador y copias cifradas cada seis horas. El agente ejecuta los comandos por SSH desde tu computadora; vos revisás y aprobás cada paso.

Narrado en español, con subtítulos. Los datos de ejemplo (IP, dominio, inmobiliaria) se reemplazan por los tuyos.

Comandos del video

Los mismos pasos del video, con cada comando listo para copiar.

1Antes de empezar

Necesitás:

  • Un VPS nuevo con Ubuntu 24.04 o 26.04 LTS y acceso root por SSH. El piloto funciona en 1 vCPU, 4 GB de RAM y 50 GB de disco.
  • Un dominio o subdominio para el CRM, por ejemplo crm.tuinmobiliaria.com.ar, con acceso a su panel DNS.
  • Un agente de IA de programación instalado en tu computadora: Claude Code, Codex u otro que pueda ejecutar comandos en terminal con tu aprobación.
  • Un correo reservado para la cuenta de administrador.
Usá un servidor nuevo. Los scripts asumen un Ubuntu limpio: crean usuarios, cambian la configuración de SSH y el firewall. No son una herramienta de migración para un servidor con otros servicios.
Tres reglas para trabajar con el agente. No le pegues contraseñas, tokens ni claves privadas. Pedile que nunca imprima el contenido de secrets/. Y no le permitas contratar servicios o generar cargos: cualquier gasto lo decidís vos.

2Clave SSH y repositorio

Si todavía no tenés una clave SSH, generala en tu computadora. La parte privada nunca sale de tu equipo; al servidor solo se copia el archivo .pub.

tu computadora
ssh-keygen -t ed25519 -C "crm-lab"

Cloná el repositorio. El agente va a leer los scripts desde acá antes de copiarlos al VPS.

tu computadora
git clone https://github.com/javierdicamillo/CRM-LAB.git
cd CRM-LAB

3Abrir el agente con el contexto correcto

Iniciá el agente dentro de la carpeta del repositorio (por ejemplo, claude o codex) y pegale este mensaje inicial. Reemplazá la IP, el dominio y el nombre de tu inmobiliaria.

prompt
Vamos a instalar CRM-LAB en un VPS nuevo siguiendo infra/README.md y docs/09-entrega-crm-mvp.md de este repositorio.

Datos:
- IP del VPS: 203.0.113.10
- Dominio del CRM: crm.tuinmobiliaria.com.ar
- Inmobiliaria: "Tu Inmobiliaria"
- Mi clave pública: ~/.ssh/id_ed25519.pub

Reglas:
1. Antes de cada comando que modifique el servidor, explicame qué hace y esperá mi aprobación.
2. Leé cada script antes de ejecutarlo y avisame si algo no coincide con un Ubuntu nuevo.
3. Nunca imprimas ni leas en voz alta el contenido de /opt/crm-lab/secrets ni del .env.
4. No contrates servicios ni generes cargos.
5. No publiques el puerto 5432 ni cambies el Compose sin mostrarme el diff.

Empezá inspeccionando el servidor sin modificar nada.

El resto del tutorial muestra los comandos que el agente debería proponerte. Te sirven para controlar lo que hace, o para seguir a mano si preferís.

4Inspeccionar el VPS

Primero, solo lectura: sistema, disco, memoria y servicios que ya estén escuchando.

tu computadora
ssh root@203.0.113.10 'cat /etc/os-release; df -h /; free -h; ss -tlnp'

Al conectarte por primera vez, compará la huella de la clave del servidor con la que muestra la consola web de tu proveedor. Si hay otros servicios en los puertos 80 o 443, frená y revisá antes de seguir.

5Preparar el servidor y proteger el acceso

bootstrap-ubuntu.sh instala Docker, UFW, restic y actualizaciones automáticas de seguridad, y crea el usuario crmadmin con tu clave pública.

tu computadora
scp infra/scripts/bootstrap-ubuntu.sh infra/scripts/harden-ssh.sh ~/.ssh/id_ed25519.pub root@203.0.113.10:/root/
ssh root@203.0.113.10 'bash /root/bootstrap-ubuntu.sh /root/id_ed25519.pub'

Abrí una conexión nueva como crmadmin y comprobá que sudo funciona sin contraseña:

tu computadora
ssh crmadmin@203.0.113.10 'sudo -n id'

Solo si eso respondió uid=0(root), deshabilitá el acceso por contraseña y activá el firewall:

tu computadora
ssh crmadmin@203.0.113.10 'sudo bash /root/harden-ssh.sh'
No cierres tu sesión root todavía. Mantené una terminal abierta y el acceso a la consola web del proveedor hasta confirmar que podés volver a entrar como crmadmin.

6Dominio y DNS

En el panel DNS de tu dominio creá:

TipoNombreValor
Acrm (o @)IPv4 del VPS
CNAMEwww.crm (o www)el dominio del CRM

Borrá cualquier registro AAAA que apunte a otro servidor y no toques MX ni TXT del correo. Verificá desde tu computadora:

tu computadora
dig +short crm.tuinmobiliaria.com.ar A
dig +short crm.tuinmobiliaria.com.ar AAAA

7Levantar PostgreSQL y Caddy

Copiá al VPS los archivos de Compose, Caddy y los scripts de despliegue y respaldo:

tu computadora
ssh crmadmin@203.0.113.10 'mkdir -p ~/crm-lab-setup'
scp infra/crm-base/{compose.yaml,compose.app.yaml,Caddyfile,Caddyfile.app,crm-lab-backup.service,crm-lab-backup.timer} \
    infra/scripts/{deploy-base.sh,prepare-app.sh,backup-app.sh,verify-app-backup.sh} \
    crmadmin@203.0.113.10:~/crm-lab-setup/

En el VPS, instalá la base. El script genera la contraseña de PostgreSQL en el servidor y fija las imágenes oficiales por digest:

VPS · crmadmin
sudo install -d -m 755 /opt/crm-lab
sudo cp ~/crm-lab-setup/{compose.yaml,compose.app.yaml,Caddyfile} /opt/crm-lab/
sudo bash ~/crm-lab-setup/deploy-base.sh

Al terminar, docker compose ps debe mostrar db como healthy. PostgreSQL usa una red interna y no publica puertos.

8Construir y preparar CRM-LAB

La imagen se construye en el propio VPS desde la raíz del repositorio. No hace falta un registry pago.

VPS · crmadmin
sudo apt-get install -y git
sudo git clone https://github.com/javierdicamillo/CRM-LAB.git /opt/crm-lab/source
cd /opt/crm-lab/source
sudo docker build -f CRM-LAB/Dockerfile -t crm-lab:0.2.0 .

Los archivos de despliegue todavía referencian la etiqueta del piloto. Pedile al agente que la actualice y te muestre el diff:

VPS · crmadmin
sudo sed -i 's/crm-lab:0.1.0/crm-lab:0.2.0/' /opt/crm-lab/compose.app.yaml
sed -i 's/crm-lab:0.1.0/crm-lab:0.2.0/' ~/crm-lab-setup/prepare-app.sh
grep -n 'crm-lab:' /opt/crm-lab/compose.app.yaml ~/crm-lab-setup/prepare-app.sh

Generá los secretos de la aplicación y creá las bases de producción y de prueba, con un rol crm_app sin privilegios de superusuario. No se imprime ningún secreto:

VPS · crmadmin
sudo bash ~/crm-lab-setup/prepare-app.sh crm.tuinmobiliaria.com.ar "Tu Inmobiliaria" admin@tuinmobiliaria.com.ar

9Activar HTTPS y crear la primera cuenta

Reemplazá el Caddyfile temporal por el de la aplicación, validalo y levantá app y worker:

VPS · crmadmin
cd /opt/crm-lab
echo 'CRM_DOMAIN=crm.tuinmobiliaria.com.ar' | sudo tee -a .env
sudo cp Caddyfile Caddyfile.http-backup
sudo cp ~/crm-lab-setup/Caddyfile.app Caddyfile
sudo docker compose run --rm --no-deps caddy caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
sudo docker compose -f compose.yaml -f compose.app.yaml up -d --wait

Caddy obtiene el certificado de Let's Encrypt en cuanto el DNS apunta al VPS. Comprobalo desde afuera:

tu computadora
curl -fsS https://crm.tuinmobiliaria.com.ar/healthz
curl -s -o /dev/null -w '%{http_code}\n' https://crm.tuinmobiliaria.com.ar/api/state

El primero responde 200 y el segundo, 401 (sin sesión). Para activar la cuenta de administrador necesitás el token de arranque. Leelo vos, en tu propia terminal, no a través del agente:

tu terminal
ssh -t crmadmin@203.0.113.10 "sudo grep BOOTSTRAP_TOKEN /opt/crm-lab/secrets/app.env"

Abrí https://crm.tuinmobiliaria.com.ar/#activar=TOKEN, completá nombre, el correo reservado y una contraseña de al menos 12 caracteres. El enlace deja de funcionar una vez creado el primer administrador.

10Programar copias y verificar

Instalá el respaldo cifrado con restic: dump de PostgreSQL, fotos, configuración y secretos, cada seis horas.

VPS · crmadmin
sudo install -m 750 ~/crm-lab-setup/backup-app.sh /usr/local/sbin/crm-lab-backup
sudo cp ~/crm-lab-setup/crm-lab-backup.{service,timer} /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now crm-lab-backup.timer
sudo systemctl start crm-lab-backup.service
sudo bash ~/crm-lab-setup/verify-app-backup.sh

La verificación restaura la copia en una base temporal, comprueba los archivos y elimina solo sus temporales.

Las copias quedan en el mismo VPS. No te protegen si perdés el disco o la cuenta del proveedor. Antes de cargar datos reales, configurá una copia externa y guardá la clave de restic (/opt/crm-lab/secrets/restic_password) en un lugar privado fuera del servidor.

Lista final:

  • Entrás por SSH como crmadmin con clave; el acceso por contraseña está deshabilitado.
  • https:// tu dominio responde con certificado válido y www redirige al principal.
  • Iniciaste sesión, creaste una propiedad de prueba y la borraste.
  • systemctl list-timers crm-lab-backup.timer muestra la próxima copia.
  • La restauración de prueba terminó sin errores.