Developer Tools AWS

WunderGraph Cosmo Router on AWS User Guide

| Product: WunderGraph Cosmo Router on AWS

Overview

This guide covers the deployment and configuration of WunderGraph Cosmo Router on AWS using cloudimg's preconfigured Amazon Machine Image (AMI). Cosmo Router is the open source, Apache-2.0 licensed data plane of the WunderGraph Cosmo GraphQL federation platform: a single, statically compiled Go binary that federates many independent GraphQL services, called subgraphs, into one unified graph that clients query through a single endpoint. It plans and executes federated queries across your subgraphs, resolves shared entities by key, and returns one joined response, so a client can ask for fields that live in several services in a single round trip.

The cloudimg image runs the router standalone against a locally composed execution config, so it never needs the Cosmo Cloud control plane or a graph API token. To make federation provable the moment the instance boots, the image ships a small two subgraph demo (a products service and an inventory service) composed at build time with the Cosmo CLI. The router listens on the loopback interface and is fronted by nginx on port 80; the federated /graphql endpoint is gated by an API key generated uniquely for each instance on first boot, written to a 0600 root:root credentials file, while a public /health endpoint stays open for liveness checks. Backed by 24/7 cloudimg support.

WunderGraph and Cosmo are trademarks of their respective owner. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by WunderGraph. It ships the free and open source, Apache-2.0 licensed Cosmo Router, unmodified. The Cosmo Studio SaaS control plane is not included.

The Cosmo Router version 0.333.2, the two demo subgraph services, the router and nginx all active, and the listeners showing nginx on port 80 with the router and the two subgraphs bound to loopback only

What is included:

  • WunderGraph Cosmo Router v0.333.2 (the open source, Apache-2.0 licensed federation router), the official release binary run unmodified
  • A working demo supergraph composed at build time from two Apollo Federation v2 subgraphs (products on 127.0.0.1:4001, inventory on 127.0.0.1:4002), both bound to loopback only
  • nginx on port 80 reverse proxying the router, serving a public /health endpoint and gating /graphql behind a per instance API key
  • cosmo-subgraph-products.service, cosmo-subgraph-inventory.service, cosmo-router.service and nginx.service as systemd units, enabled and active on boot
  • A unique API key generated per instance on first boot, never baked into the image, written to /root/wundergraph-cosmo-credentials.txt
  • Ubuntu 24.04 LTS base with latest security patches applied at build time
  • cloud-init for seamless SSH key injection and instance integration
  • 24/7 cloudimg support with guaranteed 24 hour response SLA

Prerequisites

  • An AWS account with permission to launch EC2 instances
  • An EC2 key pair (or the ability to create one) for SSH access
  • A subscription to the WunderGraph Cosmo Router listing on AWS Marketplace

Recommended instance type: m5.large (2 vCPU, 8 GB RAM) is a sensible starting point. For higher request volumes use a larger general purpose or compute optimised type. Security group inbound: allow 22/tcp from your management network and 80/tcp for the GraphQL endpoint from the networks that call it.

Connecting to your instance

Connect over SSH as the default login user for your operating system variant:

OS variant SSH login user
Ubuntu 24.04 ubuntu
ssh -i /path/to/<key-name>.pem ubuntu@<public-ip>

Step 1: Launch from the AWS Marketplace

In the AWS Marketplace find WunderGraph Cosmo Router by cloudimg and choose Continue to Subscribe, then Continue to Configuration and Continue to Launch. Pick your region, the m5.large instance type, your VPC and subnet, and a security group that allows inbound 22/tcp (from your management network) and 80/tcp (from the networks that will call the GraphQL endpoint). Select your key pair and launch.

Step 2: Launch from the AWS CLI

aws ec2 run-instances \
  --image-id ami-<cosmo-router-ami> \
  --instance-type m5.large \
  --key-name <key-name> \
  --security-group-ids <sg-id> \
  --subnet-id <subnet-id> \
  --tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=cosmo-router-01}]'

Open 22/tcp to your management network and 80/tcp to your GraphQL clients on the referenced security group before use.

Step 3: Verify the services

SSH to the instance as ubuntu and confirm the router, its two demo subgraphs and nginx are running, then check the listeners:

/opt/cosmo/router --version
systemctl is-active cosmo-subgraph-products cosmo-subgraph-inventory cosmo-router nginx | paste -sd' ' -
sudo ss -tln | grep -E ':80 |:3002|:4001|:4002' | awk '{print "LISTEN  "$4}' | sort -u

The version prints 0.333.2, all four services report active, and the listeners show nginx on 0.0.0.0:80 with the router on 127.0.0.1:3002 and the two subgraphs on 127.0.0.1:4001 and 127.0.0.1:4002 — the router and subgraphs are bound to the loopback interface, so the only public entry point is nginx on port 80:

Router:
  Version: 0.333.2
active active active active
LISTEN  0.0.0.0:80
LISTEN  127.0.0.1:3002
LISTEN  127.0.0.1:4001
LISTEN  127.0.0.1:4002

Step 4: Check the health endpoint

The router exposes a public, unauthenticated /health liveness endpoint, served through nginx on port 80, ideal for a load balancer health probe:

curl -s -o /dev/null -w 'GET /health -> HTTP %{http_code}\n' http://localhost/health
curl -s http://localhost/health; echo

This returns HTTP 200 with the body OK. No authentication is required for this endpoint; the federated GraphQL endpoint below is gated separately.

Step 5: Review the per instance API key

The federated /graphql endpoint is protected by an API key that is generated uniquely on the first boot of each instance. It is written, along with the resolved public URL, to a 0600 root:root credentials file. View it (the key is masked in the guide, but the real value is on your instance):

sudo stat -c '%A %U:%G %n' /root/wundergraph-cosmo-credentials.txt
sudo grep -E '^COSMO_API_KEY=|^COSMO_URL=' /root/wundergraph-cosmo-credentials.txt \
  | sed -r 's/(COSMO_API_KEY)=.*/\1=REDACTED_PER_INSTANCE_64_HEX_KEY/'

The file is -rw------- root:root. The COSMO_API_KEY is a 64 hex character value unique to this instance, generated by openssl rand -hex 32 on first boot before nginx started serving traffic. There is no default or known key in the image, and the same key gates every call to the federated endpoint.

The wundergraph-cosmo-credentials.txt file at mode 0600 root root showing the per instance API key masked and the resolved public URL, with a note that the key is generated uniquely on first boot

Step 6: Verify the API security model

The federated /graphql endpoint requires the per instance API key in the X-API-Key header. Confirm that a missing or wrong key is rejected with 401, while the per instance key is accepted with 200:

KEY=$(sudo grep '^COSMO_API_KEY=' /root/wundergraph-cosmo-credentials.txt | cut -d= -f2-)
Q='{"query":"{ topProducts { id } }"}'
curl -s -o /dev/null -w '/graphql (no key)    -> HTTP %{http_code}\n' -X POST -H 'Content-Type: application/json' -d "$Q" http://localhost/graphql
curl -s -o /dev/null -w '/graphql (wrong key) -> HTTP %{http_code}\n' -X POST -H 'Content-Type: application/json' -H 'X-API-Key: wrong' -d "$Q" http://localhost/graphql
curl -s -o /dev/null -w '/graphql (real key)  -> HTTP %{http_code}\n' -X POST -H 'Content-Type: application/json' -H "X-API-Key: $KEY" -d "$Q" http://localhost/graphql

The no key and wrong key calls are rejected with 401, and the call with the real per instance key returns 200. This is the security model: the health probe is open, and the federated GraphQL endpoint is gated by the per instance key, so the router is never left as an open, unauthenticated data gateway.

curl showing the federated GraphQL endpoint rejecting a missing key and a wrong key with HTTP 401 and accepting the per instance key with HTTP 200, and the public health endpoint returning HTTP 200

Step 7: Run a real federated query

This is the point of a federation router: one query, one endpoint, data joined from several subgraphs. The topProducts field is served by the products subgraph, while inStock and deliveryEstimate for the same products are served by the inventory subgraph. The router plans the query, calls both subgraphs, resolves the shared Product entity by its key, and returns a single joined response:

KEY=$(sudo grep '^COSMO_API_KEY=' /root/wundergraph-cosmo-credentials.txt | cut -d= -f2-)
curl -s -X POST http://localhost/graphql \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $KEY" \
  -d '{"query":"{ topProducts { id name price inStock deliveryEstimate } }"}' \
  | python3 -m json.tool

The response joins name and price from the products subgraph with inStock and deliveryEstimate from the inventory subgraph, for each product, in a single result:

{
    "data": {
        "topProducts": [
            {
                "id": "1",
                "name": "Cosmo Router T-Shirt",
                "price": 24.99,
                "inStock": true,
                "deliveryEstimate": "2-3 business days"
            },
            {
                "id": "2",
                "name": "GraphQL Federation Mug",
                "price": 12.5,
                "inStock": false,
                "deliveryEstimate": "3-4 weeks"
            },
            {
                "id": "3",
                "name": "WunderGraph Cap",
                "price": 18,
                "inStock": true,
                "deliveryEstimate": "1-2 business days"
            }
        ]
    }
}

Neither subgraph on its own can answer this query — the products service does not know stock levels, and the inventory service does not know names or prices. The router is what makes them queryable as one graph.

A federated GraphQL query returning topProducts with name and price from the products subgraph joined with inStock and deliveryEstimate from the inventory subgraph in a single response

Step 8: Swap in your own subgraphs

The demo supergraph is composed from two local subgraph schemas and a small graph config. To federate your own services, inspect the graph config and the composed execution config:

sudo cat /etc/cosmo/graph.yaml
sudo head -c 300 /etc/cosmo/execution-config.json; echo

To point at your own subgraphs: replace the routing_url and schema.file entries in /etc/cosmo/graph.yaml with your services, install the Cosmo CLI (npm install -g wgc), recompose with sudo wgc router compose -i /etc/cosmo/graph.yaml -o /etc/cosmo/execution-config.json, then sudo systemctl restart cosmo-router. The two bundled Node demo subgraphs are systemd services (cosmo-subgraph-products, cosmo-subgraph-inventory) you can disable once you have wired in your own upstreams. For production graphs managed across a team, connect the router to the Cosmo Cloud schema registry instead of a static file — see the WunderGraph Cosmo documentation.

Step 9: Call the endpoint from your own machine

From anywhere that can reach the instance on port 80, call the federated endpoint at the instance public IP with your per instance API key. The /health check needs no credentials:

curl http://<public-ip>/health
curl -s -X POST http://<public-ip>/graphql \
  -H 'Content-Type: application/json' \
  -H "X-API-Key: $KEY" \
  -d '{"query":"{ topProducts { id name inStock } }"}'

Fetch the key from /root/wundergraph-cosmo-credentials.txt on the instance (sudo grep '^COSMO_API_KEY=' /root/wundergraph-cosmo-credentials.txt) and export it as KEY on your client. Distribute it to your GraphQL clients as their gateway credential, or rotate it by editing /etc/nginx/conf.d/cosmo-apikey.conf and reloading nginx.

Step 10: Use your own domain and HTTPS (production)

The image serves the endpoint over plain HTTP on port 80, which is convenient behind a load balancer or private network. For production you should terminate TLS in front of the router so credentials and payloads travel encrypted:

  • Front the instance with an Application Load Balancer or Network Load Balancer with an AWS Certificate Manager certificate, or a CloudFront distribution, and forward to nginx on port 80.
  • Or install your own certificate: add a TLS server block to /etc/nginx/sites-available/wundergraph-cosmo referencing your certificate and key, open 443/tcp on the security group, then sudo systemctl reload nginx.
  • Point a DNS name you control at the instance (or the load balancer) and use that name (and https://) for your GraphQL consumers.

Step 11: Server components

Component Version / Detail
Federation router WunderGraph Cosmo Router v0.333.2 (open source, Apache-2.0)
Router endpoint /graphql on loopback 127.0.0.1:3002, fronted by nginx on :80
API front nginx on :80 reverse proxying to 127.0.0.1:3002
Demo subgraphs products (127.0.0.1:4001) + inventory (127.0.0.1:4002), Apollo Federation v2, loopback only
Execution config static, composed at build time by the Cosmo CLI (wgc router compose) — no control plane needed
Health endpoint /health (public, no auth)
API key per instance, generated first boot into /root/wundergraph-cosmo-credentials.txt, required on /graphql via X-API-Key

Support

Every cloudimg image is backed by 24/7 support with a guaranteed 24 hour response SLA. For help with this image, contact support@cloudimg.co.uk.

WunderGraph and Cosmo are trademarks of their respective owner. This image ships the free and open source, Apache-2.0 licensed Cosmo Router, unmodified, and is not affiliated with or endorsed by WunderGraph. The Cosmo Studio SaaS control plane is not included.