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.
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 APIHASURA_GRAPHQL_ADMIN_SECRET– Admin password required to access the Hasura Console and make schema changes. Never leave this unset in productionHASURA_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_idas a foreign key referencingusers.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.