eXist-db 6.4.1
Overview
This guide covers launching and using eXist-db 6.4.1 on Ubuntu 24.04 from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud Hardened Apache Cassandra, FerretDB & NoSQL Database AMIs listing on AWS Marketplace. You pick it as the software version when you subscribe and launch. The other databases in the listing are described on the listing's guide hub.
eXist-db is an open source native XML database. It stores XML, JSON and binary documents in a hierarchy of collections, indexes them (structural, range, full-text and n-gram indexes) and queries them with XQuery 3.1, XPath and XSLT.
You work with it through the Dashboard and the eXide XQuery IDE in a browser, the REST API, WebDAV (editors such as oXygen, or any WebDAV client) and XML-RPC. eXist's own Java admin client and language bindings use XML-RPC.
A stock eXist-db database opens with an admin account that has an empty password, a guest account whose password is guest, and an account for each bundled application whose password is its own name. Anyone who can reach the server can also run XQuery anonymously. This SecureAnyCloud image changes that.
What you get:
- No default login, a password unique to your instance. The image ships no database at all. First boot creates the database with eXist's client in embedded mode, when no network listener is open yet. It sets the
adminpassword from a private temporary file (never a command line, a query text or a log) and writes it to the root-only file/root/existdb-credentials.txt. Theguestaccount and the bundled applications' accounts are disabled and re-keyed to random values nobody knows. eXist-db refuses to start until first boot has finished. The emptyadminpassword andguest/guestare refused on the Dashboard, the REST API, WebDAV, XML-RPC and eXist's Java admin client. - No anonymous queries. nginx refuses REST, WebDAV and XML-RPC requests that carry no credentials. XML-RPC never falls back to the guest account, and eXide runs queries only for a signed-in user. Anonymous visitors see the Dashboard sign-in page and the documentation.
- HTTPS from the first boot. nginx is the only network entry point. It publishes eXist on port 443 with a certificate generated on your instance's first boot, and port 80 only redirects to HTTPS. Only the Dashboard and its applications, the REST API, WebDAV and XML-RPC are published.
- eXist-db on localhost only. eXist's web server (Jetty) listens on
127.0.0.1:8080. Its HTTPS connector and the distribution's sample keystore are removed, and the JMX status servlet is switched off. Never open port 8080 in a security group. - XQuery confined. eXist-db runs as its own
existdbuser with no capabilities and a read-only system. XQuery can write only the data volume and cannot read the TLS key, nginx, the system logs, the credentials file or/etc/shadow. Thefile,process,sql,jndi,mail,contentextractionandxslfoXQuery modules are switched off. Neither eXist nor nginx can reach the EC2 instance metadata endpoint, so an XQueryhttp:send-requestcannot read instance credentials. - Fixed host name and real client addresses. Requests for a host name the instance does not serve are dropped. nginx logs the real client address, and client-supplied
X-Forwarded-Forheaders are overwritten. Session cookies are HTTPS only, cross-site browser requests that change state are refused, and Dashboard sign-ins are rate limited. - Your data on its own disk. The database, its journal and indexes, the package repository and the eXist logs live on a dedicated 20 GiB EBS volume mounted at
/var/lib/existdb. You can resize it independently of the root volume. - Verified download. The eXist-db 6.4.1 release was checked against a pinned SHA-256 that matches the digest published for the eXist release. Its
exist-corelibrary carries exactly the classes of the PGP-signedorg.exist-db:exist-core:6.4.1artifact on Maven Central. - Key-only SSH. Password logins, root logins and X11 forwarding are switched off.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: eXist-db 6.4.1 (/opt/existdb, LGPL-2.1) with the Dashboard, eXide, the eXist documentation and the XQuery function documentation, Ubuntu's OpenJDK 17 runtime, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The Monex monitoring application is not pre-installed (Step 11).
Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet.
- A security group that allows TCP 22 (SSH) from your own networks and TCP 443 (Dashboard, REST, WebDAV and XML-RPC) from the networks and applications that use eXist-db. TCP 80 only redirects to HTTPS and is optional. Do not open port 8080.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick eXist-db 6.4.1 on Ubuntu 24.04 as the software version and select your Region. Then choose Launch through EC2.
Choose m5.large, your key pair and a security group as described above. The AMI brings its own 20 GiB data volume for eXist-db. Increase its size on the launch page if you expect more data (Step 10).
To launch with the AWS CLI instead, replace the values in angle brackets:
aws ec2 run-instances --region <region> --image-id <ami-id-from-the-listing> \
--instance-type m5.large --key-name <your-key-pair> \
--security-group-ids <your-security-group> --subnet-id <your-subnet> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=existdb}]'Connect to your instance
For the eXist-db 6.4.1 on Ubuntu 24.04 version, the SSH user is ubuntu. Connect with:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot generates the certificate, creates the database, deploys the bundled applications and sets the admin password. Then eXist-db and nginx start. Allow about a minute after the instance reaches the running state, then check the services:
systemctl is-active existdb nginx exist-db-firstboot
sudo test -f /var/lib/sac/data/exist-db-firstboot.done && echo FIRSTBOOT_DONE ls /opt/existdb/lib/exist-core-*.jar java -version 2>&1 | head -1active active active FIRSTBOOT_DONE /opt/existdb/lib/exist-core-6.4.1.jar openjdk version "17.0.20.1" 2026-08-18Only SSH and nginx listen on public addresses. eXist-db (Jetty, 8080) is on loopback:
sudo ss -Hlntp | awk '{print $4, $6}' | grep -v '127.0.0.5' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g' | sort0.0.0.0:22 users:(("sshd"),("systemd")) 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) 127.0.0.1:8080 users:(("java")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))Get your URLs and password
The URLs and the user name are in the root-only credentials file:
sudo grep -E '^EXISTDB_(URL|DASHBOARD_URL|REST_URL|WEBDAV_URL|XMLRPC_URL|ADMIN_USER)=' /root/existdb-credentials.txtEXISTDB_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/ EXISTDB_DASHBOARD_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/apps/dashboard/ EXISTDB_REST_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/rest/db EXISTDB_WEBDAV_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/webdav/db/ EXISTDB_XMLRPC_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/xmlrpc EXISTDB_ADMIN_USER=adminThe password is the EXISTDB_ADMIN_PASSWORD line of the same file: sudo grep '^EXISTDB_ADMIN_PASSWORD=' /root/existdb-credentials.txt. Store it in your password manager. It is unique to this instance, and admin is the eXist-db superuser (a member of the dba group).
The URLs use the instance's public DNS name from EC2 instance metadata (IMDSv2), or its public or private IPv4 address when it has no public name. The certificate names that host plus the instance's public and private IP addresses:
openssl x509 -in /etc/ssl/existdb/existdb.crt -noout -subject -ext subjectAltName -enddatesubject=CN = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhost notAfter=<date about 27 months after first boot>Without the password, the REST API answers 401 and the empty admin password and guest/guest are refused. The Dashboard shows its sign-in page, and port 80 redirects to HTTPS.
The commands below read the password from the credentials file into a shell variable and pass it to curl through a file descriptor, so it never appears in the process list or your shell history:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt) R=(--cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1") curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/exist/" curl -s -o /dev/null -w 'REST, no login -> HTTP %{http_code}\n' "${R[@]}" "https://$H/exist/rest/db" curl -s -o /dev/null -w 'REST, admin, empty pw -> HTTP %{http_code}\n' "${R[@]}" -K <(printf 'user = "admin:"\n') "https://$H/exist/rest/db" curl -s -o /dev/null -w 'REST, guest:guest -> HTTP %{http_code}\n' "${R[@]}" -K <(printf 'user = "guest:guest"\n') "https://$H/exist/rest/db" curl -s -o /dev/null -w 'REST, your password -> HTTP %{http_code}\n' "${R[@]}" -K <(printf 'user = "admin:%s"\n' "$PW") "https://$H/exist/rest/db" curl -s -o /dev/null -w 'Dashboard, no login -> HTTP %{http_code}\n' "${R[@]}" "https://$H/exist/apps/dashboard/index.html" curl -s -w ' <- /healthz (no login) HTTP %{http_code}\n' "${R[@]}" "https://$H/healthz"http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/exist/ REST, no login -> HTTP 401 REST, admin, empty pw -> HTTP 401 REST, guest:guest -> HTTP 401 REST, your password -> HTTP 200 Dashboard, no login -> HTTP 200 ok <- /healthz (no login) HTTP 200--resolve sends the request to this instance while keeping the real host name, so the certificate check passes. From another machine, drop --resolve and use the URL directly. The Dashboard answers 200 without a login because it shows its sign-in page.
Store and query documents over REST
The REST API takes the same user and password with HTTP Basic authentication over HTTPS.
This example stores an XML document in a new /db/library collection with PUT. It runs three XQuery expressions against the collection, sent in the body of a POST so the query never appears in a URL. It then reads one value with a query on the document's own URL. The small ex function reads the password as above and hands it to curl through a file descriptor:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt) ex() { curl -s --cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") "$@"; echo; } xq() { printf '<query xmlns="http://exist.sourceforge.net/NS/exist" wrap="no"><text><![CDATA[%s]]></text></query>' "$1" | ex -H 'Content-Type: application/xml' --data-binary @- "https://$H/exist/rest/db"; } ex -o /dev/null -w 'store /db/library/books.xml -> HTTP %{http_code}' -X PUT -H 'Content-Type: application/xml' --data-binary '<library> <book id="b1"><title>XQuery</title><author>Priscilla Walmsley</author><year>2015</year></book> <book id="b2"><title>XML in a Nutshell</title><author>Elliotte Rusty Harold</author><year>2004</year></book> <book id="b3"><title>Designing Data-Intensive Applications</title><author>Martin Kleppmann</author><year>2017</year></book> </library>' "https://$H/exist/rest/db/library/books.xml" xq 'string-join(for $b in collection("/db/library")//book order by xs:integer($b/year) descending return $b/title/string(), codepoints-to-string(10))' xq 'string-join(collection("/db/library")//book[xs:integer(year) gt 2010]/author, ", ")' xq 'serialize(map { "books": count(collection("/db/library")//book), "newest": max(collection("/db/library")//year ! xs:integer(.)) }, map { "method": "json" })' ex "https://$H/exist/rest/db/library/books.xml?_query=//book%5B@id='b2'%5D/title&_wrap=no"store /db/library/books.xml -> HTTP 201 Designing Data-Intensive Applications XQuery XML in a Nutshell Priscilla Walmsley, Martin Kleppmann {"books":3,"newest":2017} <title>XML in a Nutshell</title>GET on a collection or document URL returns it, DELETE removes it, and stored XQuery modules (.xq, .xql) run when you GET them.
Keep passwords and other secrets out of query strings. eXist's web server logs every request line, query string included, to /var/lib/existdb/logs/<date>.request.log. See the eXist-db documentation on the REST interface for the full set of operations.
Use the Dashboard and eXide
Open the EXISTDB_DASHBOARD_URL from Step 4 (https://<your-host>/exist/apps/dashboard/) in a browser. The certificate is self-signed, so the browser warns once. Accept it, or install your own certificate (Step 12). Anonymous visitors see the launcher with the documentation and a Login button.
Choose Login and sign in as admin with the password from the credentials file. The Dashboard then adds the Package Manager, User Manager, Backup and Settings.
Open eXide - XQuery IDE from the launcher. It uses your Dashboard session. Write a query and choose Eval, and the results appear below the editor. For example, a FLWOR expression can list the books stored in Step 5, newest first.
On this image, eXide runs queries only for signed-in users, and an anonymous visitor is sent to its sign-in page. The User Manager lists the accounts and creates new users and groups.
Give applications their own user with permissions on just the collections they need rather than the admin superuser.
WebDAV, XML-RPC and the Java admin client
WebDAV serves the database at EXISTDB_WEBDAV_URL (https://<your-host>/exist/webdav/db/): add it as a network location in your editor (for example oXygen XML Editor's eXist-db or WebDAV connection) with the admin user or one of your own.
XML-RPC at EXISTDB_XMLRPC_URL is the protocol that eXist's Java admin client and the XML:DB API use. Both protocols need credentials, and neither accepts the empty admin password or guest. Verify this with:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt) R=(--cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1") curl -s "${R[@]}" -K <(printf 'user = "admin:%s"\n' "$PW") -X PROPFIND -H 'Depth: 1' "https://$H/exist/webdav/db/library/" | grep -o '<d:href>[^<]*</d:href>' curl -s -o /dev/null -w 'WebDAV, no login -> HTTP %{http_code}\n' "${R[@]}" -X PROPFIND -H 'Depth: 0' "https://$H/exist/webdav/db/" curl -s -o /dev/null -w 'WebDAV, guest:guest -> HTTP %{http_code}\n' "${R[@]}" -K <(printf 'user = "guest:guest"\n') -X PROPFIND -H 'Depth: 0' "https://$H/exist/webdav/db/" RPC='<?xml version="1.0"?><methodCall><methodName>hasCollection</methodName><params><param><value><string>/db/library</string></value></param></params></methodCall>' printf 'XML-RPC, your password -> %s\n' "$(curl -s "${R[@]}" -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Content-Type: text/xml' --data-binary "$RPC" "https://$H/exist/xmlrpc" | grep -o '<boolean>[01]</boolean>')" printf 'XML-RPC, admin, empty -> %s\n' "$(curl -s "${R[@]}" -K <(printf 'user = "admin:"\n') -H 'Content-Type: text/xml' --data-binary "$RPC" "https://$H/exist/xmlrpc" | grep -o 'Wrong password[^<]*\|<boolean>[01]</boolean>' | head -1)"<d:href>/exist/webdav/db/library/</d:href> <d:href>/exist/webdav/db/library/books.xml</d:href> WebDAV, no login -> HTTP 401 WebDAV, guest:guest -> HTTP 401 XML-RPC, your password -> <boolean>1</boolean> XML-RPC, admin, empty -> Wrong password for user [admin]To use eXist's Java admin client (a desktop application) from your workstation, install eXist-db 6.4.1 locally and point the client at this instance through an SSH tunnel. The client then talks to eXist on the instance's loopback address, and nothing extra is opened:
ssh -i <your-key.pem> -N -L 8080:127.0.0.1:8080 ubuntu@<public-ip>Then start the client (bin/client.sh on Linux or macOS, bin\client.bat on Windows) and connect to xmldb:exist://localhost:8080/exist/xmlrpc as admin with the password from the credentials file. Close the tunnel when you have finished.
On the instance itself, the client is installed as /opt/existdb/bin/client.sh. It takes the password only with -P, which would put it in the process list, so prefer the REST API or the tunnel for scripted work.
Accounts and anonymous access
Only admin can sign in. guest and the accounts the bundled applications created are disabled, and eXide refuses anonymous use. SYSTEM is eXist's internal account and can never sign in. nobody has no password and is used only for anonymous ownership. List the accounts with:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt) xq() { printf '<query xmlns="http://exist.sourceforge.net/NS/exist" wrap="no"><text><![CDATA[%s]]></text></query>' "$1" | curl -s --cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Content-Type: application/xml' --data-binary @- "https://$H/exist/rest/db"; echo; } xq 'string-join(for $u in sm:list-users() return $u || (if (sm:is-account-enabled($u)) then " enabled" else " disabled"), codepoints-to-string(10))' xq '"eXide guest use: " || doc("/db/apps/eXide/configuration.xml")//restrictions/@guest'SYSTEM enabled admin enabled eXide disabled guest disabled nobody enabled packageservice disabled eXide guest use: noUsers you create in the User Manager (or with sm:create-account) can sign in everywhere admin can, with the permissions you give them.
On the instance itself, eXist's own loopback port 8080 still answers anonymous REST reads as the built-in guest identity, as eXist ships it. That port is never reachable from the network.
XQuery confinement and instance metadata
XQuery runs inside the eXist-db service as the unprivileged existdb user. It cannot read secrets on the system, the modules that reach outside the database are switched off, and requests to the instance metadata address are dropped. Verify this with:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt) xq() { printf '<query xmlns="http://exist.sourceforge.net/NS/exist" wrap="no"><text><![CDATA[%s]]></text></query>' "$1" | curl -s --cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") -H 'Content-Type: application/xml' --data-binary @- "https://$H/exist/rest/db" | sed -E 's/.*<message>([^[]*).*/\1/'; echo; } xq 'util:system-property("user.name")' xq 'try { unparsed-text("file:///etc/shadow") } catch * { "refused: " || $err:code }' xq 'try { unparsed-text("file:///root/existdb-credentials.txt") } catch * { "refused: " || $err:code }' xq 'import module namespace file = "http://exist-db.org/xquery/file"; file:exists("/etc")' xq 'declare namespace http = "http://expath.org/ns/http-client"; try { http:send-request(<http:request method="put" timeout="5"><http:header name="X-aws-ec2-metadata-token-ttl-seconds" value="60"/></http:request>, "http://169.254.169.254/latest/api/token")[1]/@status/string() } catch * { "refused: " || $err:description }'existdb refused: err:FOUT1170 refused: err:FOUT1170 err:XQST0059 error found while loading module file: failed to load module: 'http://exist-db.org/xquery/file' from: 'http://exist-db.org/xquery/file', location: 'http://exist-db.org/xquery/file'. Source not found. refused: Connect to 169.254.169.254:80 [/169.254.169.254] failed: Connect timed outThese are the service settings behind it:
systemctl show existdb -p User -p NoNewPrivileges -p ProtectSystem -p ProtectHome -p PrivateTmp -p IPAddressDeny
systemctl show nginx -p IPAddressDenyIPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 User=existdb PrivateTmp=yes ProtectHome=yes ProtectSystem=strict NoNewPrivileges=yes IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32The switched-off modules are commented out in /opt/existdb/etc/conf.xml (search for sac: disabled). If you need one, for example file to synchronise collections to disk, re-enable it there and run sudo systemctl restart existdb. It will still be confined to the data volume.
Storage, memory and logs
eXist-db keeps its database files, journal and indexes under /var/lib/existdb/data, its logs under /var/lib/existdb/logs and its temporary files under /var/lib/existdb/tmp, all on the dedicated EBS volume. The JVM runs with a 2 GB heap. Inspect the layout with:
df -h /var/lib/existdb | tail -1 | awk '{print $2" total, "$4" free on "$6}'
sudo ls /var/lib/existdb
sudo grep -oE -- '-Xmx[0-9a-z]+' /etc/existdb/existdb.env
sudo ls /var/lib/existdb/logs | grep -E '^(exist|xmldb|restxq)\.log$|request\.log$' | sed -E 's/^[0-9_]+\./<date>./'20G total, 19G free on /var/lib/existdb data logs lost+found tmp -Xmx2g <date>.request.log exist.log restxq.log xmldb.log- Heap. On a larger instance raise
-Xmx2gin/etc/existdb/existdb.env(about half of the instance's memory is a good start). Then runsudo systemctl restart existdb. - Disk. To grow the volume, modify it in the EC2 console (Volumes, Modify volume). Then extend the file system online with
sudo resize2fs "$(findmnt -no SOURCE /var/lib/existdb)". - Backups. Run a backup from the Dashboard (Backup), or schedule eXist's consistency check and backup job in
/opt/existdb/etc/conf.xml. Backups are written to the data volume. For a full copy, stop eXist-db (sudo systemctl stop existdb) and take an EBS snapshot of the data volume. Restore a snapshot as a whole volume. First boot never runs again on an instance that has completed it, and eXist-db refuses to start on an empty data directory, because it would otherwise create a database with an empty admin password. - Logs.
exist.logis the main eXist log,<date>.request.logthe web server's request log.journalctl -u existdbshows the service output, andjournalctl -u exist-db-firstbootshows what first boot did.
Applications and Monex
The Dashboard's Package Manager installs further eXist applications and libraries from the public eXist package repository. The instance needs outbound HTTPS for that. New applications follow the permissions their packages set, so review what an application exposes to anonymous visitors before you install it.
Monex, eXist's monitoring application, is not pre-installed. Its live view reads eXist's JMX status servlet, which this image switches off because that servlet trusts every request arriving through the local proxy. Monitor eXist-db with journalctl -u existdb, exist.log and your usual EC2 and CloudWatch tools instead.
Use your own DNS name or certificate
The served host name is fixed by configuration, never taken from a request. To serve eXist-db under your own DNS name, point the name at the instance and run the helper. The helper records the name, regenerates the self-signed certificate for it, updates the credentials file and reloads nginx:
sudo exist-set-hostname <your-dns-name>If the instance's public DNS name changes after a stop and start, run the same command again, because a request for a name the instance does not serve is dropped. An Elastic IP avoids this.
To use a certificate from your own CA or a public CA instead, replace /etc/ssl/existdb/existdb.crt (full chain) and /etc/ssl/existdb/existdb.key (mode 0600, owner root), then run sudo nginx -t && sudo systemctl reload nginx.
Security notes
SSH accepts keys only. Passwords, root logins and X11 forwarding are switched off in /etc/ssh/sshd_config.d/00-sac.conf, which sorts before every other SSH setting. Check the effective values:
sudo sshd -T | grep -E '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|x11forwarding|pubkeyauthentication) 'permitrootlogin no pubkeyauthentication yes passwordauthentication no kbdinteractiveauthentication no x11forwarding noAlso note the following:
- To change the admin password, sign in to the Dashboard, open User Manager, then admin, and set a new password. Then update
/root/existdb-credentials.txt. adminand every member of thedbagroup can read files theexistdbuser can read, query other web services and install packages through XQuery. Use separate users withoutdbamembership for applications.- nginx logs the real client address of every request, and
X-Forwarded-Forheaders sent by clients are ignored. The AMI requires IMDSv2. Restrict port 443 to the networks that use eXist-db. - Bundled libraries. eXist-db 6.4.1 is the newest eXist release (7.0 is still in beta). It ships libraries that a scanner reports with known advisories. None is reachable from the network in this configuration:
- Apache MINA, the JLine telnet server and the Spring Framework 2.5.6 jars are not used by any eXist component that is switched on.
- HSQLDB, Apache Tika, Apache FOP and Batik are reached only through the sql, contentextraction and xslfo modules, which are switched off.
- Jetty 9.4.58 (request smuggling with chunk extensions, CVE-2026-2332, and a DIGEST authentication issue, CVE-2026-10050) is reached only through nginx, which re-frames every request. eXist uses no DIGEST authentication.
- The Bouncy Castle advisories concern algorithms and certificate checks that eXist does not use.
- commons-beanutils and JDOM are used by the WebDAV server only after a user has signed in.
When you have finished with the example collection from Step 5, remove it with:
H=$(sudo sed -n 's#^EXISTDB_URL=https://\([^/]*\)/.*#\1#p' /root/existdb-credentials.txt)
PW=$(sudo sed -n 's/^EXISTDB_ADMIN_PASSWORD=//p' /root/existdb-credentials.txt)
curl -s -o /dev/null -w 'remove /db/library -> HTTP %{http_code}\n' --cacert /etc/ssl/existdb/existdb.crt --resolve "$H:443:127.0.0.1" -K <(printf 'user = "admin:%s"\n' "$PW") -X DELETE "https://$H/exist/rest/db/library"remove /db/library -> HTTP 200Support and licensing
SecureAnyCloud supports this image by email at sales@secureanycloud.com. Include the instance ID, the version (eXist-db 6.4.1 on Ubuntu 24.04) and what you were doing.
eXist-db is open source software under the GNU Lesser General Public License, version 2.1. The licence is on the instance at /opt/existdb/LICENSE. There is no per-user or per-CPU licence fee. The AMI price covers SecureAnyCloud's hardening, first boot setup and support.
eXist-db is a trademark of the eXist-db Project. Ubuntu is a trademark of Canonical Ltd. Java is a trademark of Oracle and/or its affiliates. Eclipse Jetty is a trademark of the Eclipse Foundation. SecureAnyCloud is not affiliated with or endorsed by these organisations.
Deploy on AWS
Launch eXist-db 6.4.1 on Ubuntu 24.04 on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com