Cube Semantic Layer on AWS User Guide
Overview
Cube is the open source headless business intelligence platform and semantic layer (formerly Cube.js). It sits in front of your own data warehouse or database and exposes a single, consistent data model through REST, GraphQL and SQL APIs, with built in caching and access control, so every dashboard, notebook and application queries the same governed metrics.
Cube is the server, not a data store: you point it at your existing data source and it serves your metrics. This cloudimg image runs Cube 1.6.60 from the official Docker image as a systemd service behind an nginx reverse proxy on port 80, ships a small self contained sample dataset and a matching data model so the Cube Playground works out of the box, generates a unique API secret and a unique Playground admin password on the first boot of every instance, and stores the data model, sample dataset and query cache on a dedicated EBS data volume. Backed by 24/7 cloudimg support.
What is included:
- Cube 1.6.60 (Apache-2.0) run from the official
cubejs/cubeDocker image, managed bycube.service - The Cube REST, GraphQL and SQL APIs and the developer Playground published on port 80 via nginx (with WebSocket upgrade for the Playground)
- HTTP Basic auth in front of the Playground so the developer UI is not open to the internet
- A self contained sample dataset and data model (orders and users) so the Playground shows real cubes, measures and dimensions immediately
- A dedicated EBS data volume at
/var/lib/cubefor the data model, the sample dataset, the.envand the query cache - A unique
CUBEJS_API_SECRET(JWT signing key) and a unique admin password generated on first boot, written to a root only credentials file cube.service+nginx.serviceas systemd units, enabled and active- 24/7 cloudimg support
Connecting to your instance
Connect over SSH on port 22 as the default login user for your image variant:
| OS variant | SSH login user |
|---|---|
| Ubuntu 24.04 | ubuntu |
Prerequisites
An AWS account, an EC2 key pair in the target region, and a VPC subnet with a public IP. The recommended instance type is m5.large (2 vCPU / 8 GiB RAM). Security group inbound: allow 22/tcp from your management network and 80/tcp for the APIs and the Playground (front with TLS for public exposure - see Enabling HTTPS).
Step 1 - Launch from the AWS Marketplace
Sign in to the AWS Marketplace, search for Cube by cloudimg, and choose Continue to Subscribe then Continue to Configuration. Select the region and the latest version, then Continue to Launch. Choose the m5.large instance type, your VPC subnet, your EC2 key pair, and a security group that allows 22/tcp and 80/tcp, then Launch.
Step 2 - Launch from the AWS CLI
aws ec2 run-instances \
--image-id <cube-ami-id> \
--instance-type m5.large \
--key-name <your-key> \
--security-group-ids <sg-with-22-and-80> \
--subnet-id <your-subnet> \
--associate-public-ip-address \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=cube}]'
The AMI id for your region is shown on the listing's Launch page.
Step 3 - Connect to your instance
ssh ubuntu@<instance-public-ip>
Step 4 - Confirm the services are running
systemctl is-active cube.service nginx.service
Both report active. On the first boot of your instance Cube generates a unique API secret and a unique Playground admin password.
Step 5 - Retrieve your admin credentials
The admin password and the API secret are generated uniquely on the first boot of your instance and written to a root only file:
sudo cat /root/cube-credentials.txt
This file contains CUBE_ADMIN_USER (admin), CUBE_ADMIN_PASSWORD and CUBEJS_API_SECRET. Store them somewhere safe.
Step 6 - Check the health and readiness endpoints
nginx serves a static health endpoint and proxies Cube's readiness probe, both unauthenticated (each returns 200):
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/health
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/readyz
Step 7 - Confirm your credentials gate the Playground
The Cube Playground is fronted by HTTP Basic auth. A valid login returns 200, a missing or wrong password returns 401:
curl -s -o /dev/null -w '%{http_code}\n' -u 'admin:<CUBE_ADMIN_PASSWORD>' http://localhost/
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/
The first command prints 200, the second prints 401.
Step 8 - Open the Cube Playground
Browse to http://<instance-public-ip>/ and sign in with admin and the password from Step 5. On the Playground tab, select the orders cube, add the count measure and the status dimension, then click Run Query. The results table shows live data from the bundled sample dataset:

The Generated SQL tab shows the exact SQL Cube compiled from the semantic model and pushed down to your data source - one definition, consistent everywhere:

The Data Model tab shows the bundled sample model (cubes/orders.yml and cubes/users.yml) with its joins, dimensions and measures - the single source of truth for your metrics:

The SQL API, REST API and GraphQL API tabs show ready to use snippets for each interface, so you can wire the same governed metrics into any tool:

Step 9 - Explore the data model over the REST API
The REST API is the same interface your applications use. List the cubes, measures and dimensions in the loaded model:
curl -s -u 'admin:<CUBE_ADMIN_PASSWORD>' http://localhost/cubejs-api/v1/meta | jq '.cubes[].name'
This returns the sample cubes "orders" and "users".
Step 10 - Run a query through the REST API
Run an aggregating query (the total number of orders) through the Cube load endpoint:
curl -s -u 'admin:<CUBE_ADMIN_PASSWORD>' -G \
--data-urlencode 'query={"measures":["orders.count"]}' \
http://localhost/cubejs-api/v1/load | jq '.data'
Cube compiles the query against the sample dataset and returns the result, for example [{ "orders.count": "2000" }]. Group it by a dimension by adding "dimensions":["orders.status"] to the query.
Step 11 - Confirm the data lives on the dedicated volume
The data model, the sample dataset, the .env and the query cache are stored on the dedicated EBS data volume so they can be resized and snapshotted independently of the OS disk:
findmnt /var/lib/cube
The mount is backed by a separate EBS volume captured into the image and re-provisioned on every instance.
Point Cube at your own data source
The image ships a self contained sample dataset so the Playground works out of the box. Cube itself does not store your data - to connect it to your own warehouse, edit the environment file on the data volume and replace the sample data model.
Edit /var/lib/cube/.env and set the connection variables for your database. For example, for PostgreSQL:
CUBEJS_DB_TYPE=postgres
CUBEJS_DB_HOST=your-warehouse.example.com
CUBEJS_DB_PORT=5432
CUBEJS_DB_NAME=analytics
CUBEJS_DB_USER=cube
CUBEJS_DB_PASS=your-db-password
Cube supports many data sources (PostgreSQL, MySQL, Snowflake, BigQuery, Redshift, Databricks, ClickHouse, DuckDB and more) - set CUBEJS_DB_TYPE and the matching CUBEJS_DB_* variables for your warehouse. Replace the sample model under /var/lib/cube/model/cubes/ with cubes that describe your own tables, then restart Cube:
sudo systemctl restart cube
The Playground Data Model tab can generate a starting model from your warehouse tables for you.
Using the API secret
Applications authenticate to the Cube REST, GraphQL and SQL APIs with a JSON Web Token signed by the per instance CUBEJS_API_SECRET from your credentials file. Because the secret is generated freshly on the first boot of every instance, two instances launched from this image never share a signing key. Generate a token signed with your secret and send it in the Authorization header of your API requests - see the Cube authentication docs for token claims and security context. The nginx Basic auth in this image protects the developer Playground; your production applications authenticate with the API secret.
Enabling HTTPS
The nginx reverse proxy terminates plain HTTP on port 80. For public exposure, put a certificate in front of it - add a DNS name for the instance and install a certificate with your-domain and certbot, or use the companion cloudimg nginx TLS reverse proxy image. Keep Cube bound to loopback (127.0.0.1:4000) so the only public surface is the TLS terminated proxy.
Maintenance
- Backups: snapshot the
/var/lib/cubeEBS volume to back up the data model, the data source connection and the query cache. - Playground password: rotate it with
sudo htpasswd /etc/nginx/.htpasswd adminthensudo systemctl reload nginx. - Service:
sudo systemctl restart cubeafter configuration changes; logs viasudo journalctl -u cubeorsudo docker logs cube. - Security patches: the OS continues to receive security updates through the standard Ubuntu channels.
Support
cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.
Cube is a trademark of Cube Dev, Inc. This image is produced by cloudimg and is not affiliated with or endorsed by Cube Dev, Inc.