[{"data":1,"prerenderedAt":190},["ShallowReactive",2],{"seo-verification":3,"blog-autoalojar-hasura-api-graphql-vps-ma-es":6,"promo-bar-likely":20},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-autoalojar-hasura-api-graphql-vps-ma-es",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":20,"publishedAt":21,"updatedAt":22,"category":23,"categories":29,"featuredImage":31,"bgImage":32,"posterImage":33,"relatedSolution":34,"intro":37,"sections":38,"ctaTitle":123,"ctaBody":124,"ctaButton":125,"ctaUrl":126,"relatedPosts":127},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,true,"2026-10-27T00:00:00+00:00","2026-11-04T16:30:29+00:00",{"id":24,"name":25,"slug":26,"color":27,"icon":28},7,"Autoalojamiento","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[30],{"id":24,"name":25,"slug":26,"color":27,"icon":28},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fself-host-hasura-vps-poster.svg",{"categorySlug":35,"appSlug":36},"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.",[39,43,53,88,91,107,111,114,117,120],{"type":40,"title":41,"body":42},"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":44,"title":45,"items":46},"ul","Lo que aporta Hasura",[47,48,49,50,51,52],"**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":54,"title":55,"headers":56,"rows":60},"comparison","Hasura frente a otras formas de exponer PostgreSQL",[5,57,58,59],"Hasura","API escrita a mano","PostgREST",[61,66,71,75,80,85],[62,63,64,65],"API generada desde el esquema","Sí, GraphQL y REST","No","Sí, REST",[67,68,69,70],"Relaciones anidadas en una petición","Sí","Según el código","Sí, por embedding",[72,73,74,64],"Tiempo real","Suscripciones GraphQL","Por desarrollar",[76,77,78,79],"Permisos","Por rol, fila y columna, en la consola","En el código","Roles y RLS de PostgreSQL",[81,82,83,84],"Lógica de negocio","Actions y triggers en webhooks","Libre","Funciones SQL",[86,87,64,64],"Interfaz de administración","Consola web",{"type":40,"title":89,"body":90},"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":92,"title":93,"steps":94},"steps","Instalar Hasura con Docker Compose",[95,98,101,104],{"title":96,"body":97},"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":99,"body":100},"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":102,"body":103},"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":105,"body":106},"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":108,"title":109,"body":110},"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":40,"title":112,"body":113},"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":40,"title":115,"body":116},"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":40,"title":118,"body":119},"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":40,"title":121,"body":122},"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","\u002Fapplications\u002Fdesarrollo\u002Fhasura",[128,152,170],{"id":129,"slug":130,"slugs":131,"title":135,"excerpt":136,"readTime":137,"views":138,"isPinned":19,"noindex":19,"publishedAt":139,"updatedAt":140,"category":141,"categories":146,"featuredImage":31,"bgImage":32,"posterImage":148,"relatedSolution":149},56,"alojar-postgresql-en-un-vps",{"fr":132,"en":133,"ar":134,"es":130},"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,1,"2026-04-25T00:00:00+00:00","2026-10-21T15:21:37+00:00",{"id":17,"name":142,"slug":143,"color":144,"icon":145},"Bases de datos","bases-de-donnees","bg-teal-500\u002F10 text-teal-400","database",[147],{"id":17,"name":142,"slug":143,"color":144,"icon":145},"\u002Fblog\u002Fcovers\u002Fheberger-postgresql-vps-poster.svg",{"categorySlug":150,"appSlug":151},"bases-de-datos","postgresql-stack",{"id":153,"slug":154,"slugs":155,"title":159,"excerpt":160,"readTime":161,"views":18,"isPinned":19,"noindex":19,"publishedAt":162,"updatedAt":163,"category":164,"categories":165,"featuredImage":31,"bgImage":32,"posterImage":167,"relatedSolution":168},60,"alojar-supabase-en-un-vps",{"fr":156,"en":157,"ar":158,"es":154},"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 detrás de Envoy. Migración PG 15→17, Kong→Envoy, CVE de GoTrue.",15,"2026-04-21T00:00:00+00:00","2026-11-08T01:13:14+00:00",{"id":17,"name":142,"slug":143,"color":144,"icon":145},[166],{"id":17,"name":142,"slug":143,"color":144,"icon":145},"\u002Fblog\u002Fcovers\u002Fheberger-supabase-vps-poster.svg",{"categorySlug":150,"appSlug":169},"supabase",{"id":171,"slug":172,"slugs":173,"title":177,"excerpt":178,"readTime":179,"views":18,"isPinned":19,"noindex":19,"publishedAt":180,"updatedAt":181,"category":182,"categories":187,"featuredImage":31,"bgImage":32,"posterImage":189,"relatedSolution":31},282,"docker-compose-healthcheck-postgresql",{"fr":174,"en":175,"ar":176,"es":172},"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":183,"name":184,"slug":185,"color":186,"icon":185},3,"Despliegue","deploiement","bg-success\u002F10 text-success",[188],{"id":183,"name":184,"slug":185,"color":186,"icon":185},"\u002Fblog\u002Fcovers\u002Fdocker-compose-depends-on-healthcheck-poster.svg",1794270553484]