Apache Sling 14 on AWS User Guide
Overview
This guide covers launching and using the Apache Sling 14 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg BookStack, CMS, Blogs and Wikis listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
Apache Sling is a web framework for content-centric applications. Content lives in a Java Content Repository (Apache Jackrabbit Oak), every piece of content is a resource with a URL, and scripts or Java servlets render it based on simple naming rules, so content can be created, read and changed over plain HTTP. The Apache Sling Starter 14 bundles the framework with an embedded repository, the Apache Felix web console, the Composum repository browser and a set of scripting engines, ready to run.
The cloudimg image adds:
- Two security-updated bundles. Sling Starter 14 ships Apache Sling XSS 2.4.8 and the Felix HTTP Jetty bundle 1.1.8 (Jetty 12.0.32). Both have since had security releases, so this image runs Sling XSS 2.4.12 (fixes CVE-2026-73192, CVE-2026-91852, CVE-2026-91928, CVE-2026-91999 and CVE-2026-92001) and Felix HTTP Jetty 1.2.8 with Jetty 12.1.13 (fixes CVE-2026-10051, rated high, plus CVE-2026-6790, CVE-2026-8384 and the Jetty fixes of October 2026). The old bundles are not on the image at all. Everything else is the official Starter 14 release; every download is checked against a pinned checksum.
- No shared repository and no default password. The image contains no content repository. Your instance's first boot creates its own, with Sling listening on localhost only and the web server not yet started, and immediately changes the
adminpassword from the repository default to a password generated on your instance. It checks thatadmin/adminis refused before the web server starts. The Starter's sample application (Slingshot), which creates two users whose passwords equal their user names, is removed. - Every page needs a sign-in. Anonymous visitors see only the login form. Content, user lists, the JSON views of the repository, the web console and Composum all require a signed-in user, and anonymous writes are refused.
- HTTPS from the first boot. nginx serves Sling on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS.
- Sling on localhost, with no outbound network access. Sling listens on
127.0.0.1:8080only, behind nginx, and runs all its components from a local repository on the image, so it never needs the network. The service is allowed no outbound connections except to localhost. - Internal endpoints stay internal. The DavEx and WebDAV servers, the health check pages and the topology connector are not served through nginx. Reach them over an SSH tunnel (Step 9).
- A rate-limited login. nginx limits sign-in requests (a POST to any address ending in
/j_security_check) and password changes to 6 a minute from one address after a burst of 5, requests that carry a user name and password in an HTTP Basic header to 60 a minute after a burst of 60, and every address to 600 requests a minute after a burst of 200. All limits use the address of the connection, never a header a client sends. - Hardened defaults. Sling runs as its own unprivileged account in a systemd sandbox that can write only to its repository. The Sling installation belongs to root and is read only to Sling. nginx and Sling are blocked from the instance metadata service, the AMI requires IMDSv2, requests for a host name the instance does not serve are dropped, and redirects always name the host you configure, never one a request claims.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Apache Sling Starter 14 (with the two updated bundles above), the Apache Sling Feature Launcher 1.3.6, OpenJDK 21 (Ubuntu package), nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent. The repository is on a separate 30 GiB EBS volume mounted at /var/lib/sling.
Prerequisites
- An AWS account subscribed to the listing, an EC2 key pair and a VPC subnet with a route to the internet (or a private route you use for management).
- A security group that allows TCP 22 (SSH), TCP 443 (Sling) and TCP 80 (redirects to HTTPS) from the networks that should reach them. Keep 22 to your own networks, and keep 443 to the people who use Sling.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick Apache Sling 14 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large, your key pair and a security group as above. Keep the second volume (the repository) in the launch settings; you can make it larger there.
With the AWS CLI (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=apache-sling}]'
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| Apache Sling 14 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot takes about a minute: it creates the repository, starts every Sling component and sets the admin password. Then Sling, nginx and the first boot unit are active:
systemctl is-active apache-sling nginx apache-sling-firstboot
active
active
active
nginx serves ports 80 and 443. Sling (the java process) listens on localhost only:
sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|java/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer
LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN 0.0.0.0:22 users:(("sshd"),("systemd"))
LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::ffff:127.0.0.1]:8080 users:(("java"))
LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))
LISTEN [::]:22 users:(("sshd"),("systemd"))
LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx"))
The Java and nginx versions, and the repository volume:
java -version 2>&1 | head -1
nginx -v
findmnt -no TARGET,FSTYPE,SIZE /var/lib/sling
openjdk version "21.0.12.1" 2026-08-18
nginx version: nginx/1.24.0 (Ubuntu)
/var/lib/sling ext4 29.4G
Step 4: Get your sign-in details
The credentials file holds the address Sling is served as (your instance's public DNS name by default), the web console address, and the admin user name and password generated on this instance. Show it with:
sudo cat /root/apache-sling-credentials.txt
SLING_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
SLING_CONSOLE_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/system/console
SLING_ADMIN_USER=admin
SLING_ADMIN_PASSWORD=<24 letters and digits>
Step 5: Sign in
Open SLING_URL in your browser. The certificate is self signed (generated on your instance), so accept the browser warning once, or install your own certificate (Step 11). You are sent to the login form:

Sign in with the user admin and SLING_ADMIN_PASSWORD. You arrive at the Sling Starter page, with links to the content browser, the HTL scripts REPL and the web console:

The Starter page mentions WebDAV on the root URL; on this image WebDAV is reached through an SSH tunnel instead (Step 9).
Step 6: The web console and the updated bundles
The Apache Felix web console (SLING_CONSOLE_URL, or System Console on the Starter page) manages the OSGi bundles, configurations and services that make up Sling. The Bundles page shows all bundles active, including the two security updates:

The same check from the command line. apache-sling-curl is a small helper on the image that calls Sling over HTTPS as admin, reading the password from the credentials file so it never appears on a command line:
sudo apache-sling-curl /system/console/bundles.json | python3 -c '
import json, sys
d = json.load(sys.stdin)
print(d["status"])
for b in d["data"]:
if b["symbolicName"] in ("org.apache.sling.xss", "org.apache.felix.http.jetty12", "org.apache.felix.framework"):
print(b["symbolicName"], b["version"], b["state"])'
Bundle information: 233 bundles in total - all 233 bundles active.
org.apache.felix.framework 7.0.5 Active
org.apache.felix.http.jetty12 1.2.8 Active
org.apache.sling.xss 2.4.12 Active
The checksums of everything the image was built from are listed in /usr/share/doc/apache-sling/RELEASE:
cat /usr/share/doc/apache-sling/RELEASE
Step 7: Create and read content over HTTP
Every resource in Sling has a URL. A POST creates or changes content (the Sling POST servlet) and a GET with the .json extension reads it back (the default GET servlet). Create a node, read it, check that an anonymous request is refused, then delete it:
sudo apache-sling-curl /content/hello -o /dev/null -w '%{http_code}\n' -F 'jcr:primaryType=nt:unstructured' -F 'title=Hello from the content API'
sudo apache-sling-curl /content/hello.json; echo
H=$(sudo grep '^SLING_URL=' /root/apache-sling-credentials.txt | sed -E 's#^SLING_URL=https://([^/]+)/$#\1#')
curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w 'anonymous: %{http_code}\n' "https://$H/content/hello.json"
sudo apache-sling-curl /content/hello -o /dev/null -w 'delete: %{http_code}\n' -F ':operation=delete'
201
{"jcr:primaryType":"nt:unstructured","title":"Hello from the content API"}
anonymous: 401
delete: 200
From your own computer, use the same requests with curl -u admin against SLING_URL (curl then asks for the password), or sign in through the login form and use the session cookie. See the Sling documentation for the POST servlet's operations and the GET servlet's selectors.
Step 8: Browse the repository with Composum
Composum (SLING_URL + bin/browser.html, or Browse Content on the Starter page) is a browser for the repository: the node tree, properties, access control and a query tool. It also has a package manager (bin/packages.html) and a user manager (bin/users.html).

Step 9: Users, passwords and the internal endpoints
To change the admin password (a new random password is written to the credentials file; Sling keeps running):
sudo apache-sling-set-password
To choose the password yourself, pipe it in (24 to 64 letters and digits): sudo apache-sling-set-password --stdin. Create further users in Composum's user manager or the web console (Sling > Users); give them only the access they need.
The DavEx server (/server, used by repository tools), the WebDAV server (/dav), the health check pages (/system/health) and the topology connector are not served through nginx. Reach them with an SSH tunnel from your computer, then use http://localhost:8080/ locally and sign in as admin:
ssh -i <your-key.pem> -L 8080:127.0.0.1:8080 ubuntu@<public-ip>
Step 10: Security checks
Anonymous requests get 401 everywhere except the login form, the internal endpoints are not served, the repository default admin/admin is refused, and requests for a host name the instance does not serve are dropped:
H=$(sudo grep '^SLING_URL=' /root/apache-sling-credentials.txt | sed -E 's#^SLING_URL=https://([^/]+)/$#\1#')
for p in / /.json /home/users.infinity.json /system/console /bin/browser.html /server/ /dav/ /system/health; do
printf '%-26s %s\n' "$p" "$(curl -sk --resolve "$H:443:127.0.0.1" -o /dev/null -w '%{http_code}' "https://$H$p")"
done
curl -sk --resolve "$H:443:127.0.0.1" -u admin:admin -o /dev/null -w 'admin/admin: %{http_code}\n' "https://$H/system/console/bundles.json"
curl -s -o /dev/null -w 'unknown host on 80: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || true
/ 401
/.json 401
/home/users.infinity.json 401
/system/console 401
/bin/browser.html 401
/server/ 404
/dav/ 404
/system/health 404
admin/admin: 401
unknown host on 80: 000
A browser that requests / without signing in is redirected to the login form instead of getting 401. 000 means nginx closed the connection without an answer.
Sling has no outbound network access except to localhost (the metadata service is blocked for nginx as well):
systemctl show -p IPAddressDeny -p IPAddressAllow apache-sling
IPAddressAllow=::1/128 127.0.0.0/8
IPAddressDeny=0.0.0.0/0 ::/0
If your application needs Sling to reach another server (for example a Maven repository to install bundles from, or an external API), allow just that destination with a drop-in, then restart Sling:
sudo systemctl edit apache-sling
# add:
# [Service]
# IPAddressAllow=<destination-ip>/32
sudo systemctl restart apache-sling
Step 11: Your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name Sling is served as. This mints a new self signed certificate for the name, makes nginx serve it and name it in every redirect, updates the addresses in /root/apache-sling-credentials.txt and keeps the name across reboots:
sudo apache-sling-set-hostname <your-domain>
To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx (running apache-sling-set-hostname again replaces it with a self signed one):
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/apache-sling.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/apache-sling.key
sudo nginx -t && sudo systemctl reload nginx
Step 12: Your data
The repository (Oak segment store and indexes), the OSGi framework cache and Sling's logs are on the separate volume at /var/lib/sling:
sudo du -sh /var/lib/sling/launcher/repository /var/lib/sling/launcher/framework
sudo ls /var/lib/sling/launcher
63M /var/lib/sling/launcher/repository
12M /var/lib/sling/launcher/framework
framework
install
logs
repository
resources
Sling's own logs are in /var/lib/sling/launcher/logs (error.log, request.log, access.log); nginx logs are in /var/log/nginx. To back up, stop Sling (sudo systemctl stop apache-sling), snapshot the volume (or copy /var/lib/sling/launcher/repository), then start it again. EBS snapshots of the whole volume are the simplest way to keep point-in-time copies. Grow the volume in the EC2 console and run sudo resize2fs on its device when the repository needs more room.
Step 13: Server components
| Component | Version | Where |
|---|---|---|
| Apache Sling Starter | 14 (Oak Segment Tar) | /opt/sling/repository, /opt/sling/features |
| Apache Sling XSS | 2.4.12 (security update of 2.4.8) | OSGi bundle |
| Apache Felix HTTP Jetty | 1.2.8 with Jetty 12.1.13 (security update of 1.1.8 / Jetty 12.0.32) | OSGi bundle |
| Apache Sling Feature Launcher | 1.3.6 | /opt/sling/feature-launcher |
| OpenJDK | 21 (Ubuntu package) | /usr/lib/jvm/java-21-openjdk-amd64 |
| nginx | 1.24 (Ubuntu package) | /etc/nginx/sites-available/cloudimg-sling |
The services are apache-sling (Sling) and nginx. Sling's Java heap is half the instance's memory. The Sling service unit and its sandbox are in /etc/systemd/system/apache-sling.service and the drop-ins next to it.
Step 14: Security recommendations
- Keep port 22 and port 443 open only to the networks that need them.
- Change the admin password if you share the credentials file, and create separate users with only the access they need.
- Put your own DNS name and a certificate from a public authority in front of Sling (Step 11).
- Allow only the outbound destinations your application needs (Step 10).
- Snapshot the repository volume regularly (Step 12).
- Unattended upgrades install Ubuntu security updates (OpenJDK and nginx included) automatically. Sling itself is updated by replacing the Starter release; watch the Apache Sling security page.
Support and licensing
Apache Sling, the Sling Starter, the Feature Launcher, Apache Felix and Apache Jackrabbit Oak are open source software from the Apache Software Foundation under the Apache License 2.0 (the licence and notices are in /usr/share/doc/apache-sling/); the third-party libraries in the Starter carry their own permissive licences. There is no per user or per CPU licence fee. This image runs the unmodified Starter 14 release with the two updated bundles described above, without the Slingshot sample, plus cloudimg's configuration (sign-in required, Composum's HTTP proxy off). The AMI price covers cloudimg's hardening, first boot setup and support. Apache, Apache Sling, Apache Felix and Apache Jackrabbit are trademarks of the Apache Software Foundation; cloudimg is not affiliated with or endorsed by the Apache Software Foundation.
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
- Support: 24/7, with a 24 hour response SLA