Databases

Install Hasura GraphQL Engine on Ubuntu 24.04

Hasura GraphQL Engine is an open-source tool that gives you instant, real-time GraphQL APIs over your PostgreSQL database. Instead of writing custom API endpoints, Hasura auto-generates a full GraphQL API with queries, mutations, subscriptions, and fine-grained access control – all from your existing database schema. It is backed by a strong community and used in production by teams that need to ship APIs fast without sacrificing flexibility.

Original content from computingforgeeks.com - post 11735

This guide walks through installing Hasura GraphQL Engine v2.48 on Ubuntu 24.04 using Docker Compose. We cover PostgreSQL setup, Hasura deployment, console access, authentication configuration, production hardening with Nginx reverse proxy and SSL, and firewall rules.

Prerequisites

Before starting, confirm you have the following in place:

  • A server running Ubuntu 24.04 LTS with at least 2GB RAM and 2 CPU cores
  • Root or sudo access
  • A domain name pointed to your server IP (for production SSL setup)
  • Ports 80, 443, and 8080 (TCP) available

Step 1: Install Docker and Docker Compose on Ubuntu 24.04

Hasura runs as a Docker container, so Docker and Docker Compose are required. Start by adding Docker’s official GPG key and repository.

sudo apt update
sudo apt install -y ca-certificates curl gnupg

Add the Docker GPG key and repository:

sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Install Docker Engine and the Compose plugin:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Verify Docker is running:

sudo systemctl is-active docker

The output should confirm the service is active:

active

Check the Docker Compose version to confirm the plugin installed correctly:

docker compose version

You should see the Compose version in the output:

Docker Compose version v2.32.4

Add your user to the docker group so you can run Docker commands without sudo:

sudo usermod -aG docker $USER
newgrp docker

Step 2: Install PostgreSQL for Hasura

Hasura needs a PostgreSQL database for two purposes – storing its own metadata and serving as the data source you query through GraphQL. In this setup, we run PostgreSQL inside Docker alongside Hasura, which keeps everything self-contained.

The Docker Compose file in Step 3 includes a PostgreSQL 15 container. If you already have a standalone PostgreSQL instance running on the host or on another server, you can skip the bundled container and point Hasura to your existing database instead. Just update the connection string in the environment variables.

For production workloads with large datasets, a dedicated PostgreSQL server (not containerized) is recommended for better control over backups, replication, and tuning.

Step 3: Deploy Hasura GraphQL Engine with Docker Compose

Create a directory to hold the Hasura deployment files:

mkdir -p ~/hasura && cd ~/hasura

Create the Docker Compose configuration file:

sudo vi ~/hasura/docker-compose.yml

Add the following configuration. Replace mysecretadminkey with a strong, unique password and postgrespassword with a secure database password:

services:
  postgres:
    image: postgres:15
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgrespassword
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  graphql-engine:
    image: hasura/graphql-engine:v2.48.13
    ports:
      - "8080:8080"
    restart: always
    depends_on:
      postgres:
        condition: service_healthy
    environment:
      HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      PG_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true"
      HASURA_GRAPHQL_ADMIN_SECRET: mysecretadminkey
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log

volumes:
  db_data:

Key environment variables explained:

  • HASURA_GRAPHQL_METADATA_DATABASE_URL – PostgreSQL connection string where Hasura stores its internal metadata (schema tracking, relationships, permissions)
  • PG_DATABASE_URL – The database that Hasura exposes through the GraphQL API
  • HASURA_GRAPHQL_ADMIN_SECRET – Admin password required to access the Hasura Console and make schema changes. Never leave this unset in production
  • HASURA_GRAPHQL_ENABLE_CONSOLE – Enables the web-based Hasura Console at port 8080

Start the containers in detached mode:

docker compose up -d

Verify both containers are running and healthy:

docker compose ps

You should see both services running with healthy status:

NAME                IMAGE                              STATUS                   PORTS
hasura-postgres-1   postgres:15                        Up (healthy)             5432/tcp
hasura-graphql-engine-1   hasura/graphql-engine:v2.48.13   Up                       0.0.0.0:8080->8080/tcp

Check Hasura logs to confirm startup completed without errors:

docker compose logs graphql-engine

Look for the line confirming the server is ready:

graphql-engine  | {"type":"startup","timestamp":"...","detail":{"message":"starting API server","pid":1}}
graphql-engine  | {"type":"startup","timestamp":"...","detail":{"message":"server started on port 8080"}}

Step 4: Access Hasura Console

The Hasura Console is a web-based interface for managing your GraphQL API, database schema, relationships, and permissions. With the containers running, open your browser and navigate to:

http://your-server-ip:8080/console

You will be prompted to enter the admin secret you set in HASURA_GRAPHQL_ADMIN_SECRET. Enter it and click the login button to access the console dashboard.

If the console does not load, verify port 8080 is open on your firewall and that the container is running with docker compose ps.

Step 5: Connect Database to Hasura GraphQL Engine

Hasura auto-connects to the database specified in PG_DATABASE_URL during startup, but you can also add additional databases through the console.

To verify the default connection or add a new database:

  • Open the Hasura Console at http://your-server-ip:8080/console
  • Go to the Data tab in the top navigation
  • Click Connect Database
  • Select PostgreSQL as the database type
  • Enter a display name (e.g., default)
  • For the connection string, use: postgres://postgres:postgrespassword@postgres:5432/postgres
  • Click Connect Database

For connecting an external PostgreSQL database running on another host, use the full connection string with the remote host IP, port, username, password, and database name.

Step 6: Create Tables and Relationships

With the database connected, you can create tables and define relationships directly from the Hasura Console. This generates the corresponding GraphQL types and resolvers automatically.

Go to the Data tab and click Create Table. As an example, create a users table:

  • Table Name: users
  • Columns: id (Integer, auto-increment, primary key), name (Text), email (Text, unique)
  • Click Add Table

Now create an articles table with a foreign key relationship back to users:

  • Table Name: articles
  • Columns: id (Integer, auto-increment, primary key), title (Text), content (Text), author_id (Integer)
  • Set author_id as a foreign key referencing users.id

To define the relationship, go to the articles table, click the Relationships tab, and add an object relationship:

  • Name: author
  • Type: Object relationship
  • Reference: author_id -> users.id

Hasura detects foreign keys and suggests relationships automatically. Click Add on the suggested relationships to enable them in your GraphQL schema.

You can also create tables using SQL directly. Go to the Data tab, click SQL in the sidebar, and run raw SQL statements:

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL
);

CREATE TABLE articles (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  author_id INTEGER REFERENCES users(id)
);

After running the SQL, click Track All to expose these tables through the GraphQL API.

Step 7: Run GraphQL Queries and Mutations

Navigate to the API tab in the Hasura Console to access the GraphiQL explorer. This is where you test queries and mutations against your database.

Insert a user with a mutation:

mutation {
  insert_users_one(object: {name: "John Doe", email: "[email protected]"}) {
    id
    name
    email
  }
}

The response confirms the user was created with the auto-generated ID:

{
  "data": {
    "insert_users_one": {
      "id": 1,
      "name": "John Doe",
      "email": "[email protected]"
    }
  }
}

Insert an article linked to that user:

mutation {
  insert_articles_one(object: {title: "Getting Started with Hasura", content: "Hasura provides instant GraphQL APIs.", author_id: 1}) {
    id
    title
    author {
      name
    }
  }
}

Query articles with the author relationship resolved in a single request – this is where GraphQL shines over traditional REST:

query {
  articles {
    id
    title
    content
    author {
      name
      email
    }
  }
}

The response includes the nested author data without any additional API calls:

{
  "data": {
    "articles": [
      {
        "id": 1,
        "title": "Getting Started with Hasura",
        "content": "Hasura provides instant GraphQL APIs.",
        "author": {
          "name": "John Doe",
          "email": "[email protected]"
        }
      }
    ]
  }
}

Hasura also supports subscriptions for real-time updates. Replace query with subscription in any query to get live data pushed over WebSocket when the underlying data changes.

Step 8: Configure Authentication (JWT and Webhook)

In production, the admin secret protects the Hasura API from unauthorized access, but your application users need their own authentication layer. Hasura supports two primary authentication modes – JWT and webhook.

JWT Authentication

JWT (JSON Web Token) mode works with any identity provider that issues JWTs – Auth0, Firebase, Keycloak, or a custom auth service. Hasura validates the token and extracts user roles and session variables from the claims.

Add the JWT configuration to your docker-compose.yml under the graphql-engine environment section:

sudo vi ~/hasura/docker-compose.yml

Add these environment variables to the graphql-engine service:

      HASURA_GRAPHQL_JWT_SECRET: '{"type":"RS256","jwk_url":"https://your-auth-provider.com/.well-known/jwks.json"}'

Replace the jwk_url with your identity provider’s JWKS endpoint. For Auth0, this is https://your-domain.auth0.com/.well-known/jwks.json. For Keycloak, it follows https://keycloak-host/realms/your-realm/protocol/openid-connect/certs.

Your JWT tokens must include Hasura-specific claims in the https://hasura.io/jwt/claims namespace:

{
  "https://hasura.io/jwt/claims": {
    "x-hasura-allowed-roles": ["user", "admin"],
    "x-hasura-default-role": "user",
    "x-hasura-user-id": "1234"
  }
}

Webhook Authentication

Webhook mode sends each incoming request to your custom auth endpoint for validation. Your webhook receives the request headers and returns session variables that Hasura uses for permission evaluation.

Add the webhook URL to the graphql-engine environment in docker-compose.yml:

      HASURA_GRAPHQL_AUTH_HOOK: http://your-auth-service:3000/validate

Your webhook should return a 200 response with session variables on successful authentication:

{
  "X-Hasura-Role": "user",
  "X-Hasura-User-Id": "1234"
}

Return a 401 status code to deny access. After adding the authentication configuration, restart the containers to apply changes:

cd ~/hasura
docker compose down && docker compose up -d

Step 9: Deploy Hasura in Production with Nginx Reverse Proxy and SSL

For production deployments, place Hasura behind an Nginx reverse proxy with TLS termination. This keeps port 8080 internal and serves the API over HTTPS on port 443.

Install Nginx and Certbot:

sudo apt install -y nginx certbot python3-certbot-nginx

Create the Nginx virtual host configuration:

sudo vi /etc/nginx/sites-available/hasura

Add the following server block. Replace hasura.example.com with your actual domain name:

server {
    listen 80;
    server_name hasura.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

The Upgrade and Connection headers are required for WebSocket support, which Hasura uses for GraphQL subscriptions.

Enable the site and test the configuration:

sudo ln -s /etc/nginx/sites-available/hasura /etc/nginx/sites-enabled/
sudo nginx -t

The syntax test should return OK:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Reload Nginx to apply the configuration:

sudo systemctl reload nginx

Obtain an SSL certificate with Let’s Encrypt. Certbot automatically modifies the Nginx configuration to enable HTTPS:

sudo certbot --nginx -d hasura.example.com

Follow the prompts to provide your email and accept the terms. After completion, your Hasura API is accessible at https://hasura.example.com/console.

Once SSL is working, update docker-compose.yml to bind Hasura only to localhost so it is not directly accessible on port 8080 from outside:

sudo vi ~/hasura/docker-compose.yml

Change the ports mapping for the graphql-engine service:

    ports:
      - "127.0.0.1:8080:8080"

Restart the containers to apply the change:

cd ~/hasura
docker compose down && docker compose up -d

Step 10: Configure Firewall for Hasura

Ubuntu 24.04 uses UFW as its default firewall manager. Allow the necessary ports for web traffic and SSH access.

sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

If you still need direct access to the Hasura console on port 8080 (during initial setup before Nginx is configured), allow it temporarily:

sudo ufw allow 8080/tcp

Enable UFW if it is not already active:

sudo ufw enable

Verify the firewall rules are in place:

sudo ufw status verbose

The output should show the allowed ports:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
8080/tcp                   ALLOW       Anywhere

Once the Nginx reverse proxy is working with SSL, remove the direct port 8080 access:

sudo ufw delete allow 8080/tcp

Conclusion

Hasura GraphQL Engine is running on Ubuntu 24.04 with Docker Compose, connected to PostgreSQL, and secured behind Nginx with SSL termination. You can now build your application’s frontend against the GraphQL API using queries, mutations, and real-time subscriptions.

For production hardening, set up automated database backups, configure Hasura role-based permissions for each table, enable rate limiting in Nginx, and monitor container health with a tool like Prometheus or Grafana. Review the Hasura security best practices documentation before exposing the API to public traffic.

Related Articles

Arch Linux How to install and configure Zsh on Linux Debian Install ADB and Fastboot on Ubuntu 24.04 / Linux Mint 22 / Debian 13 mariadb How to Setup MariaDB Galera Cluster on Ubuntu 24.04/22.04 with HAProxy Load Balancer Networking Install Pritunl VPN Server on Ubuntu 24.04 / 22.04

Leave a Comment

Press ESC to close