Despliegue
Stack operativo
db: PostgreSQL 16 sin exposicion publicaapi: backend ASP.NET Core 8 con volumen en/app/storagetablet: frontend PWA servido por Nginxdocs: documentacion MkDocs servida por Nginx
URLs recomendadas
- API:
https://apifirma.jdmarquez.dev - tablet:
https://tabletfirma.jdmarquez.dev/ - docs:
https://docsfirma.jdmarquez.dev/(sugerida) - Swagger UI:
https://apifirma.jdmarquez.dev/swagger - OpenAPI JSON:
https://apifirma.jdmarquez.dev/swagger/v1/swagger.json
Variables del backend
BC_BEARER_TOKENDATABASE_URLoConnectionStrings__DefaultSTORAGE_ROOTMAX_PDF_MBPOLLING_LOCK_SECONDSREQUEST_DEFAULT_EXPIRY_MINUTESACTIVATION_CODE_LENGTHACTIVATION_CODE_TTL_MINUTESMAINTENANCE_INTERVAL_SECONDSRETENTION_DAYS_ORIGINALRETENTION_DAYS_SIGNEDRETENTION_DAYS_AUDITENABLE_HTTPS_ONLYALLOWED_ORIGINS
Variables publicas de la tablet
VITE_API_BASE_URLVITE_DEFAULT_DEVICE_IDVITE_POLLING_INTERVAL_MS
Desde ghcr.io/jdmarquezdev/bc-pdf-sign-tablet:0.1.2 estas variables se leen en runtime al arrancar el contenedor. No hace falta reconstruir la imagen para cambiar la URL de la API.
Instalacion con Coolify
Esta es la ruta de despliegue de referencia para el proyecto.
1. Preparar GHCR
Si las imagenes son privadas, configura un registry en Coolify para ghcr.io con:
- usuario GitHub
- PAT con
read:packages - autorizacion SSO si la organizacion la exige
Imagenes publicadas:
- API:
ghcr.io/jdmarquezdev/bc-pdf-sign-api:0.1.2 - tablet:
ghcr.io/jdmarquezdev/bc-pdf-sign-tablet:0.1.2
2. Crear db
- imagen
postgres:16 - sin exposicion publica
- volumen persistente
- base de datos, usuario y password dedicados
3. Crear api
- tipo Docker Image o Dockerfile
- puerto interno
8080 - dominio HTTPS publico
- volumen persistente montado en
/app/storage - healthcheck por
HTTPal path/healthsobre el puerto interno8080
Variables minimas sugeridas:
ASPNETCORE_ENVIRONMENT=Production
SWAGGER_ENABLED=true
DATABASE_URL=Host=db;Port=5432;Database=bc_pdf_sign;Username=bcpdfsign;Password=replace_me
BC_BEARER_TOKEN=replace_me
STORAGE_ROOT=/app/storage
ALLOWED_ORIGINS=https://tabletfirma.jdmarquez.dev
ENABLE_HTTPS_ONLY=true
4. Crear tablet
- tipo Docker Image
- imagen
ghcr.io/jdmarquezdev/bc-pdf-sign-tablet:0.1.2 - puerto interno
8080 - dominio HTTPS publico
- sin volumenes
- healthcheck por
HTTPal path/sobre el puerto interno8080
Variables sugeridas:
VITE_API_BASE_URL=https://apifirma.jdmarquez.dev
VITE_DEFAULT_DEVICE_ID=
VITE_POLLING_INTERVAL_MS=4000
5. Crear docs
- tipo Dockerfile
- build context: raiz del repositorio
- Dockerfile:
docs.Dockerfile - puerto interno
8080 - dominio HTTPS publico, por ejemplo
https://docsfirma.jdmarquez.dev/ - sin volumenes
- sin variables obligatorias
- healthcheck por
HTTPal path/sobre el puerto interno8080
La imagen genera el sitio con mkdocs build --strict y sirve el resultado estatico con Nginx.
6. Verificaciones iniciales
- Abrir
https://apifirma.jdmarquez.dev/health - Abrir
https://apifirma.jdmarquez.dev/swagger - Abrir
https://tabletfirma.jdmarquez.dev/ - Si publicas documentacion, abrir
https://docsfirma.jdmarquez.dev/ - Registrar una tablet y emitir codigo de activacion
- Activar la tablet desde la PWA
Instalacion sin Coolify
Esta ruta es un fallback manual para laboratorio, soporte o entornos donde no se use Coolify. La referencia principal del proyecto sigue siendo Coolify.
Opcion 1. Docker Compose en una VPS
El repositorio incluye compose.yaml para un entorno funcional local o de laboratorio.
docker compose up -d --build
Usa --build cuando quieras reconstruir las imagenes desde el codigo fuente. Si solo cambias variables runtime de la tablet en un entorno ya desplegado, no hace falta recompilar la imagen 0.1.2 o superior.
Servicios por defecto:
- API en
http://127.0.0.1:8080 - tablet en
http://127.0.0.1:3000 - docs en
http://127.0.0.1:8000 - PostgreSQL en
127.0.0.1:5432
Notas:
- En este modo la tablet usa
VITE_API_BASE_URL=http://127.0.0.1:8080 ENABLE_HTTPS_ONLYva desactivado en local- para publicar en Internet, coloca un reverse proxy delante y cambia la URL publica de la tablet y de la API
Opcion 2. Contenedores sueltos con Docker
Ejemplo simplificado:
docker network create bc-pdf-sign
docker run -d --name db --network bc-pdf-sign \
-e POSTGRES_DB=bc_pdf_sign \
-e POSTGRES_USER=bcpdfsign \
-e POSTGRES_PASSWORD=replace_me \
-v bc-pdf-sign-pgdata:/var/lib/postgresql/data \
postgres:16
docker run -d --name api --network bc-pdf-sign -p 8080:8080 \
-e ASPNETCORE_ENVIRONMENT=Production \
-e SWAGGER_ENABLED=true \
-e DATABASE_URL="Host=db;Port=5432;Database=bc_pdf_sign;Username=bcpdfsign;Password=replace_me" \
-e BC_BEARER_TOKEN=replace_me \
-e STORAGE_ROOT=/app/storage \
-e ALLOWED_ORIGINS=https://tabletfirma.jdmarquez.dev \
-e ENABLE_HTTPS_ONLY=false \
-v bc-pdf-sign-storage:/app/storage \
ghcr.io/jdmarquezdev/bc-pdf-sign-api:0.1.2
docker run -d --name tablet --network bc-pdf-sign -p 3000:8080 \
-e VITE_API_BASE_URL=https://apifirma.jdmarquez.dev \
-e VITE_DEFAULT_DEVICE_ID=tablet-recepcion-1 \
-e VITE_POLLING_INTERVAL_MS=4000 \
ghcr.io/jdmarquezdev/bc-pdf-sign-tablet:0.1.2
docker build -t bc-pdf-sign-docs -f docs.Dockerfile .
docker run -d --name docs --network bc-pdf-sign -p 8000:8080 bc-pdf-sign-docs
Publicar la documentacion en Coolify
Configuracion recomendada
- servicio nuevo:
docs - fuente: Dockerfile del repositorio
- build context: raiz del repo
- Dockerfile path:
docs.Dockerfile - puerto interno:
8080 - dominio:
https://docsfirma.jdmarquez.dev/o el que decidas - healthcheck:
HTTP, path/, puerto8080
Pasos
- Crear servicio nuevo en Coolify.
- Seleccionar el mismo repositorio.
- Elegir
docs.Dockerfilecomo Dockerfile. - Configurar dominio publico para la documentacion.
- Desplegar.
- Verificar que carga la home y que la navegacion funciona.
Cuándo reconstruir
- si cambias archivos en
docs-mkdocs/,mkdocs.ymlo dependencias, hace falta redeploy del serviciodocs - si solo cambias
apiotablet, la documentacion no necesita redeploy salvo que quieras reflejar esos cambios en el contenido
Problemas habituales de despliegue
GHCR devuelve unauthorized
Sintoma tipico:
error from registry: unauthorized
Revision recomendada:
- confirmar que el tag existe en GHCR
- comprobar si el paquete es publico o privado
- si es privado, usar PAT con
read:packages - autorizar SSO si aplica
- volver a probar con
docker login ghcr.ioydocker pull
La API intenta conectar a 127.0.0.1:5432
Sintoma tipico:
Failed to connect to 127.0.0.1:5432
Causa habitual:
DATABASE_URLmal configurado- uso de
localhostdentro del contenedor
Solucion:
- usar el hostname interno del servicio PostgreSQL, por ejemplo
Host=db;Port=5432;... - no usar
localhosten despliegue entre contenedores
El healthcheck de la tablet falla con errores SSL
Sintoma tipico:
ssl_client: SSL_connect
packet length too long
Causa habitual:
- Coolify comprueba
https://dominio:8080/dentro del contenedor - la tablet sirve HTTP en el puerto interno
8080
Solucion:
- configurar healthcheck interno por
HTTP - path
/ - puerto
8080 - no usar la URL publica HTTPS como check interno
La documentacion no abre en Coolify
Causas habituales:
- se eligio mal el build context o el Dockerfile
- el healthcheck usa HTTPS interno en vez de HTTP
- faltan dependencias de MkDocs en la build
Solucion:
- usar build context en la raiz del repo
- usar
docs.Dockerfile - configurar healthcheck
HTTPsobre/y puerto8080
La tablet sigue llamando a 127.0.0.1
Causa habitual:
- imagen antigua construida con la URL local horneada
Solucion:
- usar
ghcr.io/jdmarquezdev/bc-pdf-sign-tablet:0.1.2o superior - configurar
VITE_API_BASE_URLen runtime en Coolify
CORS bloquea llamadas desde la tablet
Sintoma tipico:
- errores en consola del navegador al llamar a la API
Solucion:
- fijar
ALLOWED_ORIGINSal dominio real de la tablet, por ejemplohttps://tabletfirma.jdmarquez.dev
Swagger en despliegue
- Swagger UI:
https://apifirma.jdmarquez.dev/swagger - OpenAPI JSON:
https://apifirma.jdmarquez.dev/swagger/v1/swagger.json - En produccion deja
SWAGGER_ENABLED=truesi quieres usarlo para soporte e integracion con BC.
Para mas detalle:
- guia de Swagger: API - Swagger
- ejemplos desde Business Central: API - Business Central