Deploy Relaticle CRM en Hetzner: problemas y fixes #1

Open
opened 2026-06-29 02:21:44 +00:00 by rafa · 0 comments
Owner

Contexto

Despliegue de Relaticle CRM en /home/rafa/apps/triptyk-crm/ usando Docker Compose + Traefik (red de Coolify). Stack: postgres + redis + app (serversideup/php:8.4-fpm-nginx) + horizon + scheduler.

Comando de arranque: docker compose -f compose.yml -f compose.prod.yml up -d


Problema 1: Puerto 8080 ya ocupado

Síntoma: docker compose up falla con port 8080 already allocated.

Causa: El compose.yml original tiene ports: ["${APP_PORT:-80}:8080"]. Traefik de Coolify ocupa el 8080 del host.

Fix: Cambiar ports por expose en compose.yml para el servicio app. El acceso externo lo gestiona Traefik vía labels, no un port binding directo.


Problema 2: PostgreSQL falla auth por IPv6

Síntoma: connection to server at "postgres" (fd7e:da47:12d6::4), port 5432 failed: FATAL: password authentication failed

Causa: Docker 27+ asigna automáticamente IPs IPv6 a los contenedores aunque el network tenga enable_ipv6: false. SCRAM-SHA-256 falla sobre esa ruta IPv6.

Fix en compose.prod.yml:

services:
  app:
    extra_hosts:
      - "postgres:10.0.3.10"  # fuerza IPv4
  postgres:
    networks:
      default:
        ipv4_address: 10.0.3.10
networks:
  default:
    enable_ipv6: false
    ipam:
      config:
        - subnet: 10.0.3.0/24

Problema 3: REDIS_PASSWORD bakeada en la imagen

Síntoma: WRONGPASS invalid username-password pair or user is disabled en Redis.

Causa: El .env del build tenía REDIS_PASSWORD=xxx. Ese fichero se copia en la imagen Docker. Laravel lo lee del filesystem antes de que Docker Compose pueda sobreescribir la var del servidor (que estaba vacía).

Fix: Override explícito vacío en compose.prod.yml:

services:
  app:
    environment:
      REDIS_PASSWORD: ""
  horizon:
    environment:
      REDIS_PASSWORD: ""
  scheduler:
    environment:
      REDIS_PASSWORD: ""

Problema 4: Redis de Coolify colisiona con el Redis propio

Síntoma: NOAUTH Authentication required — la app intenta conectar al Redis de Coolify (que sí tiene password) en lugar del propio.

Causa: El servicio app está en dos redes: default (tiene nuestro triptyk-crm-redis-1) y coolify (tiene coolify-redis con password). Docker DNS resuelve el hostname redis al contenedor de la red coolify primero.

Fix: Anclar el Redis propio con IP fija y forzar la resolución en todos los servicios que lo usan:

services:
  app:
    extra_hosts:
      - "redis:10.0.3.20"
  horizon:
    extra_hosts:
      - "redis:10.0.3.20"
  scheduler:
    extra_hosts:
      - "redis:10.0.3.20"
  redis:
    networks:
      default:
        ipv4_address: 10.0.3.20

Problema 5: Import de DB falla con schema ya creado

Síntoma: pg_dump completo causa errores de constraints duplicados; tablas de negocio quedan con 0 filas.

Causa: El contenedor corre migraciones automáticas al arrancar (AUTORUN_ENABLED). El dump completo intenta re-crear tablas/constraints ya existentes, y cuando hay error en un COPY la transacción aborta dejando la tabla vacía.

Fix: Usar dump solo de datos + limpiar antes:

# En local — dump solo datos
pg_dump -h 127.0.0.1 -U relaticle -d relaticle \
  --data-only --no-owner --no-acl --disable-triggers \
  -f dump_data.sql

# En prod — limpiar primero (CASCADE vacía todas las tablas relacionadas)
docker exec postgres-1 psql -U relaticle -d relaticle \
  -c "TRUNCATE users, teams, team_user, team_invitations CASCADE;"

# En prod — importar
docker exec -i postgres-1 psql -U relaticle -d relaticle < dump_data.sql

Resultado: 624 empresas y 71 contactos importados correctamente.


Estado final

  • Stack healthy: postgres + redis + app + horizon + scheduler
  • Traefik enrutando por labels (redes default + coolify)
  • compose.prod.yml en /home/rafa/apps/triptyk-crm/ en el servidor
  • Datos locales importados (624 companies, 71 people, usuario Rafa activo)
  • Pendiente DNS: crm.triptykdsb.com188.40.120.157

Lección principal

Cuando una app comparte la red coolify con otros servicios del panel, los hostnames de servicios propios (redis, postgres, db) pueden colisionar con contenedores de Coolify que usen el mismo nombre. Siempre usar extra_hosts con IPs fijas para los servicios propios en compose.prod.yml.

## Contexto Despliegue de Relaticle CRM en `/home/rafa/apps/triptyk-crm/` usando Docker Compose + Traefik (red de Coolify). Stack: postgres + redis + app (serversideup/php:8.4-fpm-nginx) + horizon + scheduler. Comando de arranque: `docker compose -f compose.yml -f compose.prod.yml up -d` --- ## Problema 1: Puerto 8080 ya ocupado **Síntoma:** `docker compose up` falla con `port 8080 already allocated`. **Causa:** El `compose.yml` original tiene `ports: ["${APP_PORT:-80}:8080"]`. Traefik de Coolify ocupa el 8080 del host. **Fix:** Cambiar `ports` por `expose` en `compose.yml` para el servicio `app`. El acceso externo lo gestiona Traefik vía labels, no un port binding directo. --- ## Problema 2: PostgreSQL falla auth por IPv6 **Síntoma:** `connection to server at "postgres" (fd7e:da47:12d6::4), port 5432 failed: FATAL: password authentication failed` **Causa:** Docker 27+ asigna automáticamente IPs IPv6 a los contenedores aunque el network tenga `enable_ipv6: false`. SCRAM-SHA-256 falla sobre esa ruta IPv6. **Fix en `compose.prod.yml`:** ```yaml services: app: extra_hosts: - "postgres:10.0.3.10" # fuerza IPv4 postgres: networks: default: ipv4_address: 10.0.3.10 networks: default: enable_ipv6: false ipam: config: - subnet: 10.0.3.0/24 ``` --- ## Problema 3: REDIS_PASSWORD bakeada en la imagen **Síntoma:** `WRONGPASS invalid username-password pair or user is disabled` en Redis. **Causa:** El `.env` del build tenía `REDIS_PASSWORD=xxx`. Ese fichero se copia en la imagen Docker. Laravel lo lee del filesystem antes de que Docker Compose pueda sobreescribir la var del servidor (que estaba vacía). **Fix:** Override explícito vacío en `compose.prod.yml`: ```yaml services: app: environment: REDIS_PASSWORD: "" horizon: environment: REDIS_PASSWORD: "" scheduler: environment: REDIS_PASSWORD: "" ``` --- ## Problema 4: Redis de Coolify colisiona con el Redis propio **Síntoma:** `NOAUTH Authentication required` — la app intenta conectar al Redis de Coolify (que sí tiene password) en lugar del propio. **Causa:** El servicio `app` está en dos redes: `default` (tiene nuestro `triptyk-crm-redis-1`) y `coolify` (tiene `coolify-redis` con password). Docker DNS resuelve el hostname `redis` al contenedor de la red `coolify` primero. **Fix:** Anclar el Redis propio con IP fija y forzar la resolución en todos los servicios que lo usan: ```yaml services: app: extra_hosts: - "redis:10.0.3.20" horizon: extra_hosts: - "redis:10.0.3.20" scheduler: extra_hosts: - "redis:10.0.3.20" redis: networks: default: ipv4_address: 10.0.3.20 ``` --- ## Problema 5: Import de DB falla con schema ya creado **Síntoma:** `pg_dump` completo causa errores de constraints duplicados; tablas de negocio quedan con 0 filas. **Causa:** El contenedor corre migraciones automáticas al arrancar (AUTORUN_ENABLED). El dump completo intenta re-crear tablas/constraints ya existentes, y cuando hay error en un COPY la transacción aborta dejando la tabla vacía. **Fix:** Usar dump solo de datos + limpiar antes: ```bash # En local — dump solo datos pg_dump -h 127.0.0.1 -U relaticle -d relaticle \ --data-only --no-owner --no-acl --disable-triggers \ -f dump_data.sql # En prod — limpiar primero (CASCADE vacía todas las tablas relacionadas) docker exec postgres-1 psql -U relaticle -d relaticle \ -c "TRUNCATE users, teams, team_user, team_invitations CASCADE;" # En prod — importar docker exec -i postgres-1 psql -U relaticle -d relaticle < dump_data.sql ``` Resultado: 624 empresas y 71 contactos importados correctamente. --- ## Estado final - Stack healthy: postgres + redis + app + horizon + scheduler - Traefik enrutando por labels (redes `default` + `coolify`) - `compose.prod.yml` en `/home/rafa/apps/triptyk-crm/` en el servidor - Datos locales importados (624 companies, 71 people, usuario Rafa activo) - Pendiente DNS: `crm.triptykdsb.com` → `188.40.120.157` ## Lección principal Cuando una app comparte la red `coolify` con otros servicios del panel, los hostnames de servicios propios (`redis`, `postgres`, `db`) pueden colisionar con contenedores de Coolify que usen el mismo nombre. **Siempre usar `extra_hosts` con IPs fijas** para los servicios propios en `compose.prod.yml`.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rafa/server#1