[{"data":1,"prerenderedAt":188},["ShallowReactive",2],{"seo-verification":3,"blog-autoalojar-hasura-api-graphql-vps-es":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-autoalojar-hasura-api-graphql-vps-es",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":122,"ctaBody":123,"ctaButton":124,"ctaUrl":125,"relatedPosts":126},505,"autoalojar-hasura-api-graphql-vps",{"fr":12,"en":13,"ar":14,"es":10},"self-host-hasura-vps","self-host-hasura-graphql-engine-vps","استضافة-hasura-على-vps-واجهة-graphql","Hasura en un VPS: una API GraphQL instantánea sobre PostgreSQL","Instala Hasura en un VPS con Docker Compose: una API GraphQL y REST sobre PostgreSQL, permisos por rol, suscripciones en tiempo real y HTTPS.",6,0,false,"2026-10-27T00:00:00+00:00","2026-10-27T23:58:39+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Autoalojamiento","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fself-host-hasura-vps-poster.svg",{"categorySlug":34,"appSlug":35},"desarrollo","hasura","Escribir el mismo código CRUD para cada tabla, luego los mismos controles de acceso y luego la misma documentación de la API: ese es el trabajo que elimina Hasura GraphQL Engine. Este motor de código abierto (licencia Apache-2.0) se conecta a una base PostgreSQL y expone al instante una API GraphQL completa, con relaciones, filtros, agregados y suscripciones en tiempo real, protegida por permisos declarados por rol. Esta guía lo instala con Docker Compose en un VPS, junto a su propia base PostgreSQL, lo publica en HTTPS detrás de nginx y fija las reglas de seguridad que no hay que olvidar.",[38,42,52,87,90,106,110,113,116,119],{"type":39,"title":40,"body":41},"h2","Por qué una API generada en lugar de un backend escrito a mano","En la mayoría de las aplicaciones, buena parte del código de servidor solo traduce peticiones HTTP a SQL: listar, filtrar, paginar, crear, modificar, borrar, comprobando cada vez que el usuario tiene derecho a hacerlo. Ese código es repetitivo, hay que probarlo y cada nueva columna obliga a retocarlo.\n\nHasura parte del esquema de la base. Una tabla seguida se convierte en un tipo GraphQL, una clave foránea en un campo anidado, y una regla de permiso escrita una vez se aplica a todas las consultas. La lógica propia de tu negocio — un pago, un envío de correo, un cálculo — se queda en tu código, al que Hasura llama por webhook. Conservas la base PostgreSQL: nada queda encerrado en un formato propietario.",{"type":43,"title":44,"items":45},"ul","Lo que aporta Hasura",[46,47,48,49,50,51],"**API GraphQL instantánea** — consultas, mutaciones, filtros, ordenación, paginación y agregados sobre cada tabla seguida.","**Relaciones** — las claves foráneas se convierten en campos anidados, consultables en una sola petición.","**Suscripciones en tiempo real** — un cliente se suscribe a una consulta y recibe los cambios por WebSocket.","**Permisos por rol** — reglas por fila y por columna, alimentadas por los claims de un token JWT.","**Actions y triggers** — webhooks llamados por una mutación, por un cambio de datos o según un horario cron.","**Consola y endpoints REST** — administración web, explorador GraphiQL y conversión de una consulta en ruta REST.",{"type":53,"title":54,"headers":55,"rows":59},"comparison","Hasura frente a otras formas de exponer PostgreSQL",[5,56,57,58],"Hasura","API escrita a mano","PostgREST",[60,65,70,74,79,84],[61,62,63,64],"API generada desde el esquema","Sí, GraphQL y REST","No","Sí, REST",[66,67,68,69],"Relaciones anidadas en una petición","Sí","Según el código","Sí, por embedding",[71,72,73,63],"Tiempo real","Suscripciones GraphQL","Por desarrollar",[75,76,77,78],"Permisos","Por rol, fila y columna, en la consola","En el código","Roles y RLS de PostgreSQL",[80,81,82,83],"Lógica de negocio","Actions y triggers en webhooks","Libre","Funciones SQL",[85,86,63,63],"Interfaz de administración","Consola web",{"type":39,"title":88,"body":89},"Requisitos previos","Un VPS Ubuntu 24.04 con **1 GB de RAM** basta para empezar: en reposo, el motor Hasura y PostgreSQL ocupan juntos unos 200 MB. Prevé **2 GB** en cuanto la base crezca o se multipliquen las suscripciones. Necesitas Docker con el plugin Compose y un **nombre de dominio** que apunte al VPS, con nginx y un certificado HTTPS: tu API la llamarán navegadores y aplicaciones móviles, debe responder en una dirección estable y cifrada.",{"type":91,"title":92,"steps":93},"steps","Instalar Hasura con Docker Compose",[94,97,100,103],{"title":95,"body":96},"Preparar los secretos","Crea el directorio de la aplicación y un archivo `.env` con la contraseña de la base y el **admin secret**, la clave maestra de la API. Solo root puede leer el archivo.\n```bash\nmkdir -p \u002Fopt\u002Fhasura && cd \u002Fopt\u002Fhasura\ncat > .env \u003C\u003CEOF\nDB_PASSWORD=$(openssl rand -hex 16)\nADMIN_SECRET=$(openssl rand -hex 24)\nEOF\nchmod 600 .env\n```",{"title":98,"body":99},"Crear el archivo Compose","Este `docker-compose.yml` arranca PostgreSQL en la red interna de la stack, sin puerto publicado, y después Hasura cuando la base está lista. El puerto de Hasura solo se publica en la interfaz local; la consola se sirve desde la imagen, sin llamar al CDN del editor, y la telemetría está desactivada.\n```yaml\nservices:\n  postgres:\n    image: postgres:17.11-alpine\n    restart: unless-stopped\n    environment:\n      POSTGRES_DB: hasura\n      POSTGRES_USER: hasura\n      POSTGRES_PASSWORD: ${DB_PASSWORD}\n    volumes:\n      - hasura-pgdata:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U hasura -d hasura\"]\n      interval: 10s\n      retries: 10\n  hasura:\n    image: hasura\u002Fgraphql-engine:v2.51.3\n    restart: unless-stopped\n    depends_on:\n      postgres:\n        condition: service_healthy\n    ports:\n      - \"127.0.0.1:8103:8080\"\n    env_file: .env\n    environment:\n      HASURA_GRAPHQL_DATABASE_URL: postgres:\u002F\u002Fhasura:${DB_PASSWORD}@postgres:5432\u002Fhasura\n      HASURA_GRAPHQL_ADMIN_SECRET: ${ADMIN_SECRET}\n      HASURA_GRAPHQL_ENABLE_CONSOLE: \"true\"\n      HASURA_GRAPHQL_CONSOLE_ASSETS_DIR: \u002Fsrv\u002Fconsole-assets\n      HASURA_GRAPHQL_DEV_MODE: \"false\"\n      HASURA_GRAPHQL_ENABLE_TELEMETRY: \"false\"\nvolumes:\n  hasura-pgdata: {}\n```",{"title":101,"body":102},"Arrancar la stack","En el primer arranque, Hasura crea sus tablas de metadatos en el esquema `hdb_catalog` y conecta la base como fuente `default`. El endpoint `\u002Fhealthz` responde `OK` cuando el motor está listo.\n```bash\ndocker compose up -d\ncurl -fsS http:\u002F\u002F127.0.0.1:8103\u002Fhealthz   # OK\n```",{"title":104,"body":105},"Publicar en HTTPS detrás de nginx","Añade un bloque `server` para tu dominio, con un certificado Let's Encrypt. Las cabeceras `Upgrade` y `Connection` son imprescindibles: las suscripciones pasan por WebSocket.\n```nginx\nlocation \u002F {\n    proxy_pass http:\u002F\u002F127.0.0.1:8103;\n    proxy_http_version 1.1;\n    proxy_set_header Upgrade $http_upgrade;\n    proxy_set_header Connection \"upgrade\";\n    proxy_set_header Host $host;\n    proxy_set_header X-Forwarded-Proto $scheme;\n}\n```",{"type":107,"title":108,"body":109},"tip","El admin secret nunca sale del servidor","Sin `HASURA_GRAPHQL_ADMIN_SECRET`, la consola y toda la API quedan abiertas a cualquiera que conozca la dirección. Con él, otorga **todos los derechos**: leer y escribir todas las tablas, ejecutar SQL, modificar los metadatos. Resérvalo para la consola y tus scripts de administración, y nunca lo pongas en el código de un frontend o de una aplicación móvil.",{"type":39,"title":111,"body":112},"Crear una tabla y consultarla","Abre `https:\u002F\u002Fapi.example.com\u002Fconsole`, introduce el admin secret y, en la pestaña **Data**, crea una tabla `todos` con las columnas `id` (entero autoincremental), `title` (texto) y `done` (booleano). Pulsa **Track**: la tabla aparece al instante en el explorador de la pestaña **API**. Desde un script de administración, la misma consulta se envía con el admin secret:\n```bash\ncurl -s https:\u002F\u002Fapi.example.com\u002Fv1\u002Fgraphql \\\n  -H \"x-hasura-admin-secret: $ADMIN_SECRET\" \\\n  -H 'content-type: application\u002Fjson' \\\n  -d '{\"query\":\"{ todos { id title done } }\"}'\n```",{"type":39,"title":114,"body":115},"Autenticar a tus usuarios y fijar los permisos","Tus usuarios no deben usar el admin secret: presentan un token JWT emitido por tu proveedor de identidad (Logto, Authentik, Zitadel, Auth0…). Indica a Hasura dónde encontrar las claves de verificación, y qué rol dar a las peticiones sin token, en el archivo `.env`:\n```bash\nHASURA_GRAPHQL_JWT_SECRET={\"type\":\"RS256\",\"jwk_url\":\"https:\u002F\u002Fauth.example.com\u002Foidc\u002Fjwks\"}\nHASURA_GRAPHQL_UNAUTHORIZED_ROLE=anonymous\n```\n\nRelanza la stack con `docker compose up -d`: el servicio `hasura` lee este archivo mediante `env_file`. El token debe llevar los claims `x-hasura-default-role`, `x-hasura-allowed-roles` y `x-hasura-user-id`. En la pestaña **Permissions** de cada tabla, define entonces lo que cada rol puede leer, insertar o modificar — por ejemplo, el rol `user` solo ve las filas en las que `user_id` vale `X-Hasura-User-Id`.",{"type":39,"title":117,"body":118},"Solución de problemas","**La consola muestra «invalid x-hasura-admin-secret»**: el secreto introducido no coincide con el valor del `.env`. Compruébalo con `grep ADMIN_SECRET \u002Fopt\u002Fhasura\u002F.env` y recarga la página.\n\n**Hasura se reinicia en bucle**: la base no es accesible. `docker compose logs hasura` muestra el error de conexión; comprueba que la contraseña de la URL `HASURA_GRAPHQL_DATABASE_URL` es la de PostgreSQL. Si la cambiaste después del primer arranque, PostgreSQL conservó la antigua: solo lee `POSTGRES_PASSWORD` al crear el volumen.\n\n**Las suscripciones se cortan**: el proxy inverso no transmite la actualización a WebSocket. Añade las cabeceras `Upgrade` y `Connection` indicadas más arriba y aumenta `proxy_read_timeout` si tus clientes permanecen inactivos mucho tiempo.\n\n**Una tabla no aparece en la API**: existe en la base pero no está seguida. Pulsa **Track** en la pestaña **Data**, o sigue todas las tablas del esquema de una vez.",{"type":39,"title":120,"body":121},"Instalación en un clic desde el Marketplace de ServOrbit","El Marketplace de ServOrbit instala Hasura en tu VPS sin línea de comandos: despliega PostgreSQL y el motor Hasura, genera el admin secret y la contraseña de la base, conecta la base como fuente `default` y publica la API en HTTPS en un subdominio de tu dominio o en el subdominio gratuito del VPS. El admin secret aparece en tu área de cliente; solo queda abrir la consola y crear tus tablas.","Tu API GraphQL sobre PostgreSQL, en tu propio VPS","Un VPS de ServOrbit Ubuntu 24.04 con 1 GB de RAM basta para empezar con Hasura. Instalación en un clic desde el Marketplace, PostgreSQL incluido, admin secret generado para ti, HTTPS en tu dominio o en el subdominio gratuito del VPS.","Instalar Hasura","\u002Fmarketplace\u002Fdesarrollo\u002Fhasura",[127,150,168],{"id":128,"slug":129,"slugs":130,"title":134,"excerpt":135,"readTime":136,"views":18,"isPinned":19,"publishedAt":137,"updatedAt":138,"category":139,"categories":144,"featuredImage":30,"bgImage":31,"posterImage":146,"relatedSolution":147},56,"alojar-postgresql-en-un-vps",{"fr":131,"en":132,"ar":133,"es":129},"heberger-postgresql-vps","postgresql-on-a-vps-a-reliable-and-controlled-database","postgresql-على-خادم-vps-قاعدة-بيانات-موثوقة-ومتحكم-بها","PostgreSQL en VPS: base de datos fiable y controlada","Aloje PostgreSQL en VPS: configuración prod, copias pgBackRest, HA streaming, comparativa RDS\u002FSupabase\u002FNeon y resolución de fallos OOM.",9,"2026-04-25T00:00:00+00:00","2026-10-21T15:21:37+00:00",{"id":17,"name":140,"slug":141,"color":142,"icon":143},"Bases de datos","bases-de-donnees","bg-teal-500\u002F10 text-teal-400","database",[145],{"id":17,"name":140,"slug":141,"color":142,"icon":143},"\u002Fblog\u002Fcovers\u002Fheberger-postgresql-vps-poster.svg",{"categorySlug":148,"appSlug":149},"bases-de-datos","postgresql-stack",{"id":151,"slug":152,"slugs":153,"title":157,"excerpt":158,"readTime":159,"views":18,"isPinned":19,"publishedAt":160,"updatedAt":161,"category":162,"categories":163,"featuredImage":30,"bgImage":31,"posterImage":165,"relatedSolution":166},60,"alojar-supabase-en-un-vps",{"fr":154,"en":155,"ar":156,"es":152},"heberger-supabase-vps","hosting-supabase-on-a-vps","استضافة-supabase-على-خادم-vps","Alojar Supabase en un VPS en 2026","Autoaloje Supabase en su VPS: Postgres, Auth, Storage y API REST con Envoy Gateway. Migración PG 15→17, Kong→Envoy, CVE de GoTrue.",14,"2026-04-21T00:00:00+00:00","2026-10-09T22:36:10+00:00",{"id":17,"name":140,"slug":141,"color":142,"icon":143},[164],{"id":17,"name":140,"slug":141,"color":142,"icon":143},"\u002Fblog\u002Fcovers\u002Fheberger-supabase-vps-poster.svg",{"categorySlug":148,"appSlug":167},"supabase",{"id":169,"slug":170,"slugs":171,"title":175,"excerpt":176,"readTime":177,"views":18,"isPinned":19,"publishedAt":178,"updatedAt":179,"category":180,"categories":185,"featuredImage":30,"bgImage":31,"posterImage":187,"relatedSolution":30},282,"docker-compose-healthcheck-postgresql",{"fr":172,"en":173,"ar":174,"es":170},"docker-compose-depends-on-healthcheck","depends-on-is-not-enough-postgresql-healthcheck-in-compose","depends-on-لا-يكفي-healthcheck-لـ-postgresql-في-compose","depends_on no basta: healthcheck de PostgreSQL en Compose","Por qué `depends_on` por sí solo no garantiza que PostgreSQL esté listo, y cómo configurar un healthcheck fiable con `service_healthy` para evitar las race conditions.",8,"2026-08-19T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":181,"name":182,"slug":183,"color":184,"icon":183},3,"Despliegue","deploiement","bg-success\u002F10 text-success",[186],{"id":181,"name":182,"slug":183,"color":184,"icon":183},"\u002Fblog\u002Fcovers\u002Fdocker-compose-depends-on-healthcheck-poster.svg",1793146075099]