AgensGraph 2.18.6.0 on AWS User Guide
Overview
This guide covers launching and verifying AgensGraph 2.18.6.0 on Ubuntu 24.04 from cloudimg on Amazon EC2. It is one version of the cloudimg Hardened PostgreSQL 18, PostGIS & Postgres Extension AMIs listing on AWS Marketplace; you pick it as the software version when you subscribe and launch. The other PostgreSQL builds and extensions in the listing are described on the listing's guide hub.
AgensGraph is a multi-model graph database built into PostgreSQL, developed by SKAI Worldwide and released under the Apache License 2.0 over PostgreSQL 18.6 (The PostgreSQL License). It is not an extension added to stock PostgreSQL: the graph data model, the openCypher and GQL query languages and the graph catalogue are part of the server itself. Relational tables and property graphs live in the same database, and a single query or transaction can use both. Because it is PostgreSQL 18.6 underneath, every PostgreSQL client and driver works with it (psycopg, JDBC, pgx, Npgsql and the rest), and so do roles, indexes, pg_dump and the PostgreSQL extensions.
The image is built from the upstream release tag v2.18.6.0 (commit 567835248c944ad370d55f458143807fd29a1b5e, released 2026-10-21), which is based on PostgreSQL 18.6 and carries its security fixes. In 2.18.6.0, Cypher writes enforce row-level security policies and fixed-length patterns apply the row-level security and privileges of the labels they touch. The running server reports exactly that build: PostgreSQL 18.6 (AgensGraph 2.18.6.0).
What this image is not:
- Not a cluster. It is a single AgensGraph server. Replication and failover can be set up with the standard PostgreSQL tools, but none is configured.
- No web interface. There is no dashboard or HTTP surface. You use the
agensshell (AgensGraph'spsql) or any PostgreSQL client. AgensGraph's separate graph visualiser is not included.
What is on the image:
- AgensGraph 2.18.6.0 (
agensgraph.service), compiled from the pinned upstream source into/opt/agensgraph, with the client tools (agens,psql,pg_dump,pg_restore,pg_basebackup,pg_isready,ag_ctl) on the defaultPATH - A
graphdbdatabase owned by the non-superuser application roleagensapp, with a smalldemograph (three people and twoknowsrelationships) so you can run a Cypher query in the first minute, and theagenssuperuser; both passwords are generated on your instance's first boot - 61 extensions from the PostgreSQL 18.6 contrib set (
pgcrypto,pg_stat_statements,pg_trgm,hstore,postgres_fdw,uuid-osspand more), the PL/Perl, PL/Python3 and PL/Tcl languages, and AgensGraph's ownmetaextension - TLS with a certificate generated on your instance's first boot (TLS 1.2 minimum)
- A credential guard that runs on every boot and refuses to serve if a published or example password ever authenticates
- The build provenance, the upstream licences and a dependency licence inventory under
/usr/share/agensgraph/
Default user: ubuntu · Architecture: x86_64 · Root volume: 16 GiB gp3
Security posture
- No database ships in the image. The image contains no AgensGraph cluster at all, so it carries no role, password, graph, data or key from the build. First boot creates a fresh cluster, the
graphdbdatabase with its demo graph and two different passwords, one foragensand one foragensapp, and writes them to/root/agensgraph-credentials.txt, readable by root only. Locally, theagenssuperuser is also reachable as theagenssystem user (peer authentication on the local socket). - Nothing is served before first boot finishes. AgensGraph will not start until first boot has created the cluster, the certificate and the passwords. While it sets them, the server listens on its local socket only, with no TCP port.
- Per-instance TLS certificate. First boot creates this instance's own private key and self-signed certificate (
/var/lib/agensgraph/data/server.crt) and turns TLS on, so no two instances share a key. - Localhost only. AgensGraph listens on
127.0.0.1:5432, and the listing's security group opens SSH (22) only. Reach the database through an SSH tunnel, or open it to your VPC as described in Step 7. - Remote connections require TLS.
pg_hba.confaccepts non-loopback clients only overhostsslwithscram-sha-256and rejects plain-text remote connections; there is notrustormd5rule. A start-time guard refuses to start AgensGraph if the configuration is weakened (atrustrule, a non-TLS remote rule,md5password hashing, or a remote listener with TLS off). - No metadata access for the database. A database superuser can make AgensGraph open outbound connections (for example
COPY ... FROM PROGRAM,dblinkorpostgres_fdw), so the AgensGraph service and both first-boot services are blocked from reaching the instance metadata service (169.254.169.254 and fd00:ec2::254). Amazon Time Sync (169.254.169.123) still works. If you add backups to S3 from inside the database, give them explicit credentials; they cannot use the instance role. - No core dumps. The database and first-boot services may not write core files, so process memory holding a password never lands on disk.
- IMDSv2 required. The AMI is registered with
ImdsSupport v2.0, so instances launched from it refuse token-less (IMDSv1) metadata requests. - Fails closed. If first boot cannot finish, AgensGraph stays stopped and first boot tries again on the next boot.
- Per-instance identity. SSH host keys and the machine ID are generated fresh on every instance. SSH allows key login only, root cannot log in over SSH, and root has no password.
- No build tools. The compiler, linker and every development package used to build AgensGraph were removed from the image after the build, along with the source tree.
- What we changed in Ubuntu: the
fwupd-refreshtimer is masked (EC2 has no firmware that fwupd can update), the C header packages the base image carried are removed, and only the running kernel is kept.
Prerequisites
- An AWS account and permission to launch EC2 instances and create security groups
- An EC2 key pair in the Region you launch in
- A VPC subnet, with a public IP on the instance if you connect over the internet
Recommended instance type: m5.large. The shipped settings (shared_buffers 512 MB, effective_cache_size 2 GB, max_connections 200) suit development, testing and small production graphs; for larger workloads choose a bigger instance, raise shared_buffers towards a quarter of the memory and give the root volume more space.
Connecting to your instance
| Version | Operating system | SSH user |
|---|---|---|
| AgensGraph 2.18.6.0 on Ubuntu 24.04 | Ubuntu 24.04 LTS | ubuntu |
Step 1: Launch the instance
Option A: AWS Marketplace console
- Open the cloudimg Hardened PostgreSQL 18, PostGIS & Postgres Extension AMIs listing on AWS Marketplace and choose View purchase options, then Subscribe. One subscription covers every version in the listing.
- Once the subscription is active, choose Launch your software.
- Choose One-click launch from AWS Marketplace (or Launch from EC2 Console for the full launch wizard). In Version, choose AgensGraph 2.18.6.0 on Ubuntu 24.04, then choose your Region.
- Pick an instance type (
m5.largerecommended; the software charge is $0.04 per vCPU per hour) and your key pair. - Security group: the listing's default group allows SSH (22) only. Restrict it to your own IP address. Do not open 5432 to the internet.
- Choose your VPC and subnet, leave the metadata defaults (the image already requires IMDSv2), then choose Launch.
Option B: AWS CLI
Run this on your own workstation. Replace the AMI ID with the one shown for your Region on the Marketplace launch page, and the VPC, subnet, key pair and CIDR with your own:
SG=$(aws ec2 create-security-group --group-name agensgraph \
--description "AgensGraph" --vpc-id vpc-0123456789abcdef0 \
--query GroupId --output text)
aws ec2 authorize-security-group-ingress --group-id "$SG" --protocol tcp --port 22 --cidr <your-mgmt-cidr>
aws ec2 run-instances \
--image-id ami-0123456789abcdef0 \
--instance-type m5.large \
--key-name my-key-pair \
--security-group-ids "$SG" \
--subnet-id subnet-0123456789abcdef0 \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=agensgraph}]'
You do not need --metadata-options: the AMI already makes IMDSv2 required. To give the database more room, add a --block-device-mappings entry for /dev/sda1 with a bigger VolumeSize.
Step 2: Connect and read your credentials
Connect as ubuntu with the key pair you chose:
ssh -i ~/.ssh/my-key-pair.pem ubuntu@<public-ip>
First boot finishes within a minute of launch. Show the connection details (the two password lines are left out here; read them with sudo cat /root/agensgraph-credentials.txt and keep them in your secrets manager):
sudo grep -v -e '^AGENSGRAPH_SUPERUSER_PASSWORD=' -e '^AGENSGRAPH_APP_PASSWORD=' /root/agensgraph-credentials.txt | head -18
# AgensGraph 2.18.6.0 (PostgreSQL 18.6) on Ubuntu 24.04 (cloudimg AWS Marketplace image)
# Generated on THIS instance's first boot by agensgraph-firstboot.service; these passwords exist nowhere else.
# Rotate a password (never on a command line): sudo -u agens agens -h /run/agensgraph -d postgres
# then \password agensapp and update this file to match (agensgraph-credguard reads it at every boot).
AGENSGRAPH_HOST=127.0.0.1
AGENSGRAPH_PORT=5432
AGENSGRAPH_SUPERUSER=agens
AGENSGRAPH_APP_ROLE=agensapp
AGENSGRAPH_APP_DATABASE=graphdb
AGENSGRAPH_DEMO_GRAPH=demo
AGENSGRAPH_SSLMODE=require
AGENSGRAPH_TLS_CERT=/var/lib/agensgraph/data/server.crt
AGENSGRAPH_TLS_CERT_SHA256=02:3A:EF:29:B6:B0:3E:DE:C3:75:E9:B2:87:D7:E4:39:B9:B8:68:03:73:B0:51:ED:D3:9D:AA:D3:F5:CD:67:7D
# Application database 'graphdb' (owner agensapp, a non-superuser; graph_path defaults to the 'demo' graph)
# on 127.0.0.1:5432. Connect with TLS:
# agens "host=127.0.0.1 dbname=graphdb user=agensapp sslmode=require"
The certificate fingerprint is different on every instance. The commands below read the agensapp password from that file at run time, so it never appears on screen. In your own sessions you can instead put it in ~/.pgpass (mode 0600) as 127.0.0.1:5432:graphdb:agensapp:<agensgraph-app-password>.
Step 3: Confirm AgensGraph is running
agens --version
systemctl is-active agensgraph.service agensgraph-firstboot.service agensgraph-credguard.service
sudo ss -Hltn
agens (PostgreSQL) 18.6 (AgensGraph 2.18.6.0)
active
active
active
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 4096 127.0.0.54:53 0.0.0.0:*
LISTEN 0 400 127.0.0.1:5432 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 [::]:22 [::]:*
AgensGraph listens on 127.0.0.1:5432 only; port 53 on 127.0.0.53/127.0.0.54 is the operating system's local DNS stub. Now connect as agensapp over TLS and ask the server what it is:
export PGPASSWORD="$(sudo sed -n 's/^AGENSGRAPH_APP_PASSWORD=//p' /root/agensgraph-credentials.txt)"
agens "host=127.0.0.1 dbname=graphdb user=agensapp sslmode=require" \
-c "SELECT version();" -c "SELECT agversion();" \
-c "SELECT ssl, version AS tls_version FROM pg_stat_ssl WHERE pid = pg_backend_pid();" \
-c "SHOW graph_path;"
version
-------------------------------------------------------------------------------------------------------------------------------
PostgreSQL 18.6 (AgensGraph 2.18.6.0) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0, 64-bit
(1 row)
agversion
-----------
2.18.6.0
(1 row)
ssl | tls_version
-----+-------------
t | TLSv1.3
(1 row)
graph_path
------------
demo
(1 row)
graph_path is the graph your Cypher queries run against; in graphdb it defaults to the demo graph.
Step 4: Query the demo graph with Cypher
Cypher queries go straight into the same session as SQL. List the people, the relationships between them, and everyone Alice can reach in one or two hops:
export PGPASSWORD="$(sudo sed -n 's/^AGENSGRAPH_APP_PASSWORD=//p' /root/agensgraph-credentials.txt)"
agens "host=127.0.0.1 dbname=graphdb user=agensapp sslmode=require" <<'SQL'
MATCH (p:person) RETURN p.name, p.city ORDER BY p.name;
MATCH (a:person)-[k:knows]->(b:person) RETURN a.name, k.since, b.name ORDER BY k.since;
MATCH (:person {name: 'alice'})-[:knows*1..2]->(f:person) RETURN f.name ORDER BY f.name;
SQL
name | city
---------+-----------
"alice" | "London"
"bob" | "Leeds"
"carol" | "Bristol"
(3 rows)
name | since | name
---------+-------+---------
"alice" | 2019 | "bob"
"bob" | 2021 | "carol"
(2 rows)
name
---------
"bob"
"carol"
(2 rows)
Properties come back as jsonb values, which is why strings are quoted. The graph's labels are ordinary database objects with an owner, so the usual PostgreSQL permissions apply to them:
sudo -u agens agens -h /run/agensgraph -d graphdb -c "SELECT graphname, nspid::regnamespace AS schema FROM ag_graph;" -c "\dGl"
graphname | schema
-----------+--------
demo | demo
(1 row)
List of labels
Graph | Name | Type | Owner
-------+-----------+--------+----------
demo | ag_edge | edge | agensapp
demo | knows | edge | agensapp
demo | ag_vertex | vertex | agensapp
demo | person | vertex | agensapp
(4 rows)
Step 5: Combine graphs and tables
A graph and a relational table can be used in one query. As agensapp, create a small graph and a price table, join a Cypher pattern match with the table in SQL, then remove both:
export PGPASSWORD="$(sudo sed -n 's/^AGENSGRAPH_APP_PASSWORD=//p' /root/agensgraph-credentials.txt)"
agens "host=127.0.0.1 dbname=graphdb user=agensapp sslmode=require" -v ON_ERROR_STOP=1 <<'SQL'
SET client_min_messages = warning;
CREATE GRAPH shop;
SET graph_path = shop;
CREATE (:customer {name: 'Ada'})-[:bought {qty: 2}]->(:product {sku: 'P-100'});
CREATE TABLE prices (sku text PRIMARY KEY, price numeric(10,2));
INSERT INTO prices VALUES ('P-100', 24.99);
SELECT g.name #>> '{}' AS customer, (g.qty #>> '{}')::int AS qty, p.price,
(g.qty #>> '{}')::int * p.price AS total
FROM (MATCH (c:customer)-[b:bought]->(x:product) RETURN c.name, b.qty, x.sku) AS g(name, qty, sku)
JOIN prices p ON p.sku = g.sku #>> '{}';
DROP TABLE prices;
DROP GRAPH shop CASCADE;
SQL
SET
CREATE GRAPH
SET
UPDATE 3
CREATE TABLE
INSERT 0 1
customer | qty | price | total
----------+-----+-------+-------
Ada | 2 | 24.99 | 49.98
(1 row)
DROP TABLE
DROP GRAPH
The image also carries a self-test that proves the appliance end to end with this instance's own credentials (a wrong password is refused, a TLS session works, a Cypher traversal and 5,000 rows survive a full restart of AgensGraph). It restarts AgensGraph once, so run it when nothing else is connected:
sudo /usr/local/sbin/agensgraph-roundtrip-check.sh 2>/dev/null
PASS a wrong password is refused over TCP with an authentication error
PASS the per-VM credential connects as agensapp over TLSv1.3
PASS running engine: PostgreSQL 18.6 (AgensGraph 2.18.6.0) on x86_64-pc-linux-gnu
PASS Cypher on the shipped demo graph: 2 knows edges
PASS Cypher round trip: graph created, n1 reaches n2,n3 within 3 hops, edge property read back
PASS SQL round trip: 5000 rows written, indexed, analysed and aggregated back
PASS all 5000 rows and the 3-vertex graph survived a full engine restart
PASS 61 extensions available
AGENSGRAPH_ROUNDTRIP_SUCCESS
Step 6: Check the security controls
The AgensGraph unit carries the metadata block, agensapp is not a superuser, AgensGraph listens on loopback with this instance's own certificate and scram-sha-256 hashing, and the fwupd refresh timer is masked:
systemctl show -p IPAddressDeny agensgraph.service
sudo -u agens agens -h /run/agensgraph -d postgres -Atc "SELECT rolname, rolsuper FROM pg_roles WHERE rolname IN ('agens', 'agensapp') ORDER BY 1;" \
-c "SHOW listen_addresses;" -c "SHOW ssl_cert_file;" -c "SHOW password_encryption;"
systemctl is-enabled fwupd-refresh.timer 2>/dev/null || true
IPAddressDeny=169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128
agens|t
agensapp|f
127.0.0.1
/var/lib/agensgraph/data/server.crt
scram-sha-256
masked
A wrong password is refused by scram-sha-256:
OUT="$(PGPASSWORD=wrong-password agens "host=127.0.0.1 dbname=graphdb user=agensapp sslmode=require" -c "SELECT 1" 2>&1 || true)"
echo "${OUT#*failed: }"
FATAL: password authentication failed for user "agensapp"
Step 7: Connect from your application
AgensGraph accepts connections on localhost only. Two ways to reach it:
- SSH tunnel (no change to the instance). On your workstation run
ssh -N -L 15432:127.0.0.1:5432 ubuntu@<public-ip>, then connect your client to127.0.0.1:15432asagensappto thegraphdbdatabase withsslmode=require. - Open it to your VPC. In
/var/lib/agensgraph/data/postgresql.conf, change the cloudimg linelisten_addresses = '127.0.0.1'(near the end of the file) tolisten_addresses = '*', restart AgensGraph, then add an inbound rule for 5432 to the instance's security group from your application subnet or VPC CIDR only (never 0.0.0.0/0). Remote clients must use TLS (sslmode=require, orverify-fullwith this instance's certificate/var/lib/agensgraph/data/server.crt) and the role's password. A plain-text (non-TLS) connection from another host is refused bypg_hba.conf.
sudo sed -i "s/^listen_addresses = '127.0.0.1'/listen_addresses = '*'/" /var/lib/agensgraph/data/postgresql.conf
sudo systemctl restart agensgraph.service
Any PostgreSQL driver works. Run Cypher through it as an ordinary statement, for example SET graph_path = demo; followed by MATCH (p:person) RETURN p.name;.
Maintenance
- Change a password. Run
sudo -u agens agens -h /run/agensgraph -d postgresand type\password agensapp(or\password agens) at the prompt; it asks for the new password twice and never puts it on a command line. Then update/root/agensgraph-credentials.txt(the credential guard reads it on every boot) and your secrets manager. - Configuration. The cloudimg settings are the block at the end of
/var/lib/agensgraph/data/postgresql.conf(listener, port, password hashing, TLS, memory, logging);pg_hba.confis in the same directory. Apply changes withsudo systemctl restart agensgraph.service. The start-time guard refuses to start AgensGraph if a change would weaken authentication or expose it without TLS;journalctl -u agensgraph.serviceshows why. - Updates. Ubuntu security updates are applied automatically by unattended upgrades. AgensGraph itself is compiled from source, so it is not updated through
apt: new AgensGraph releases arrive as new versions of this AMI in the listing. Back up (below), launch the new version and restore. - Backups. Take EBS snapshots of the root volume, or logical backups with
pg_dump(graphs included):sudo -u agens pg_dump -h /run/agensgraph -Fc graphdb > graphdb.dump. - Logs.
/var/log/agensgraph/andjournalctl -u agensgraph.service; first boot and the credential guard log tojournalctl -u agensgraph-firstboot.serviceandjournalctl -u agensgraph-credguard.service. - Licences and provenance. AgensGraph is under the Apache License 2.0 and PostgreSQL under The PostgreSQL License.
/usr/share/agensgraph/holds the upstreamLICENSE,NOTICEandCOPYRIGHT, the build provenance (tag, commit, configure flags) and the licence inventory of the system libraries AgensGraph uses.
sed -n '1,15p' /usr/share/agensgraph/BUILD-PROVENANCE.txt
AgensGraph - cloudimg image build provenance
============================================
upstream repository : https://github.com/skaiworldwide-oss/agensgraph.git
pinned tag : v2.18.6.0 (GitHub Release 2026-10-21)
pinned commit : 567835248c944ad370d55f458143807fd29a1b5e
built version string: PostgreSQL 18.6 (AgensGraph 2.18.6.0)
install prefix : /opt/agensgraph
built on : 2026-10-26 (UTC)
base OS : Ubuntu 24.04.5 LTS
licence : Apache License 2.0 (root LICENSE + NOTICE at the pinned commit),
over PostgreSQL 18.6 under the PostgreSQL Licence (COPYRIGHT).
extensions installed: 61 (extensions.txt)
configure flags : configure-flags.txt
dependency licences : dependency-licences.txt
source manifest : source-tree-manifest.txt (7457 paths at the pinned commit)
Support
cloudimg supports this image by email at support@cloudimg.co.uk. Include the instance ID, the version (AgensGraph 2.18.6.0 on Ubuntu 24.04) and what you were doing.
AgensGraph is a trademark of its owner. PostgreSQL is a trademark of the PostgreSQL Community Association of Canada. Ubuntu is a trademark of Canonical Ltd. cloudimg is not affiliated with or endorsed by these organisations.