Deployment guide

REDAXO CMS 5.21.6

Overview

This guide covers launching and using the REDAXO CMS 5.21.6 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. The image is one version of the SecureAnyCloud BookStack, CMS, Blogs and Wikis listing on AWS Marketplace. You select it as the software version when you subscribe and launch.

REDAXO is a free and open source content management system written in PHP. You build a site from a page tree (Structure), your own Templates and Modules, a Mediapool for files and the Media Manager for image sizes, with users and roles, multilingual content and a large addon ecosystem installed through REDAXO's Installer.

What you get:

  • The current release, verified. REDAXO 5.21.6 is the official release file, checked against its published SHA-256 and, file by file, against a manifest of the whole release. Releases 5.21.3 to 5.21.6 fix a critical advisory and several high-severity advisories that affect 5.21.2 and earlier (among them GHSA-px8f-whj8-hrpq, an authentication bypass in the history plugin).
  • No reachable setup wizard, no shared database. REDAXO's browser setup creates the site and the first administrator for whoever opens it first. This image ships no database at all (the MariaDB data directory is empty) and no configuration file. Your instance's first boot initialises its own database and runs REDAXO's own console setup before the web server starts. Afterwards, the configuration records that setup is finished, and nginx refuses every request for the setup wizard.
  • Secrets unique to your instance, never on a command line. The database password, the administrator password and the TLS key are generated on your instance, and nothing from the image build is reused. REDAXO's console reads the passwords from a file that only it and root can read, never from its command line, so they never reach a process list or a log.
  • HTTPS from the first boot. nginx serves REDAXO on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS, and REDAXO itself is set to HTTPS with secure session cookies.
  • Fail closed. nginx does not start until first boot has finished. If first boot cannot complete, the site stays offline rather than open.
  • Only REDAXO's front controllers run PHP. The site runs through /index.php and the backend through /redaxo/. No other PHP file is ever run, and REDAXO's source, data (with the configuration), cache and console folders are never served. The folders that PHP writes to and serves, media and assets, are static only. Every file gets nosniff and a sandboxing content security policy, and only passive types (images, PDF, fonts, audio and video) open in the browser. Anything else, SVG and HTML included, is sent as a download (stylesheets and scripts still load on pages).
  • A rate-limited sign-in. nginx allows 10 backend sign-in attempts a minute from one address (after a burst of 10), using the address of the connection, never a header that a client sends. REDAXO adds its own delay after three failed attempts on an account.
  • Links from other sites cannot act for you. Backend pages, the backend's sign-out and safe-mode switches, and REDAXO's API calls only work when they come from your site itself (Step 9).
  • The real host and client address. nginx hands REDAXO the host name you configure and nothing that a request claims, and REDAXO's website address is set to it. nginx removes X-Forwarded-For, Client-IP and the other forwarding headers, and REDAXO records the address of the connection.
  • Hardened defaults. REDAXO's own design needs PHP to write its assets, media, redaxo/cache, redaxo/data and redaxo/src folders (its Installer adds addons there), so those belong to the web server with no access for other users, and the front controllers belong to root. Root never runs REDAXO's code: the SecureAnyCloud tools run REDAXO's console as the web server's user. PHP cannot run shell commands and is confined to the site folder. MariaDB has no network listener at all (REDAXO talks to it over a local socket), and its root account signs in only through the socket as the operating system's root. nginx, PHP, MariaDB and the first-boot service are blocked from the instance metadata service, the AMI requires IMDSv2, and requests for a host name that the instance does not serve are dropped.
  • Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.

What is on the image: REDAXO 5.21.6 (the upstream release, checksum verified), MariaDB 10.11, PHP 8.3 FPM, nginx, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.

Default user: ubuntu. Architecture: x86_64. Recommended instance type: m5.large.

Prerequisites

Before you deploy this image, you need:

  • 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 that you use for management).
  • A security group that allows TCP 22 (SSH), TCP 443 (REDAXO) and TCP 80 (redirects to HTTPS) from the networks that should reach them. Restrict port 22 to your own networks. Open port 443 to your visitors for a public site, or only to your team while you build it.
1

Launch the instance

In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick REDAXO CMS 5.21.6 on Ubuntu 24.04 as the software version, select your Region, and choose Launch through EC2.

Choose m5.large, your key pair and a security group as described above. The root volume holds the site, the database and your media, so size it for your content.

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=redaxo}]'
2

Connect to your instance

Connect over SSH. For REDAXO CMS 5.21.6 on Ubuntu 24.04, the SSH user is ubuntu.

ssh -i <your-key.pem> ubuntu@<public-ip>
3

Check the services

First boot takes under a minute, because it creates the database and runs REDAXO's setup. Afterwards, nginx, PHP, MariaDB and the first-boot unit are all active. Check them:

systemctl is-active nginx php8.3-fpm mariadb redaxo-firstboot
active active active active

nginx serves ports 80 and 443. PHP and MariaDB listen on local sockets only, so the only open ports are 22, 80 and 443:

sudo ss -tlnp | awk 'NR==1 || /nginx|sshd|php|maria/' | awk '{print $1, $4, $6}' | sed -E 's/,pid=[0-9]+,fd=[0-9]+//g'
State Local Peer LISTEN 0.0.0.0:22 users:(("sshd"),("systemd")) LISTEN 0.0.0.0:80 users:(("nginx"),("nginx"),("nginx")) LISTEN 0.0.0.0:443 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:22 users:(("sshd"),("systemd")) LISTEN [::]:80 users:(("nginx"),("nginx"),("nginx")) LISTEN [::]:443 users:(("nginx"),("nginx"),("nginx"))

Confirm how the download was verified, and that every file is still the release's:

cat /usr/share/doc/redaxo/RELEASE cd /var/www/redaxo && sudo sha256sum -c --quiet /usr/share/doc/redaxo/REDAXO-5.21.6.sha256 && echo "1953 files match the REDAXO 5.21.6 release" php -v | head -1 mariadb --version
REDAXO 5.21.6 source https://github.com/redaxo/redaxo/releases/download/5.21.6/redaxo_5.21.6.zip sha256 efc5f39151c52114700b040a075b93736e711921f846932966adb90e429e2dff licence MIT (LICENSE.md sha256 7559f14ab6f510dacdd03cb1cb82c60dd8e0da0db7226524a7e68debc89b01da; attribution rider: the backend keeps the www.redaxo.org link and the REDAXO logo) 1953 files match the REDAXO 5.21.6 release PHP 8.3.6 (cli) (built: Oct 19 2026 15:16:58) (NTS) mariadb Ver 15.1 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64) using EditLine wrapper

Files that REDAXO adds later, such as your media and its caches, are not in the list. The check covers every file that the release shipped.

4

Get your sign-in details

The credentials file holds the address that REDAXO is served as (your instance's public DNS name by default), the backend address, the administrator's user name and password, and the database credentials, all generated on this instance. Show it with:

sudo cat /root/redaxo-credentials.txt
REDAXO_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/ REDAXO_BACKEND_URL=https://ec2-<public-ip-dashed>.<region>.compute.amazonaws.com/redaxo/ REDAXO_ADMIN_USERNAME=sac REDAXO_ADMIN_PASSWORD=<24 letters and digits> REDAXO_DB_NAME=redaxo REDAXO_DB_USER=redaxo REDAXO_DB_PASSWORD=<48 hexadecimal characters>
5

Visit the site and sign in

Open REDAXO_URL in your browser. The certificate is self-signed (generated on your instance), so your browser warns once. Compare the certificate's SHA-256 fingerprint with the one on the instance (sudo openssl x509 -in /etc/nginx/ssl/redaxo.crt -noout -fingerprint -sha256) and continue, or install a certificate from your own certificate authority (Step 11).

A fresh site shows a starter page, which is an ordinary REDAXO article that you can edit or delete.

Open REDAXO_BACKEND_URL and sign in with REDAXO_ADMIN_USERNAME and REDAXO_ADMIN_PASSWORD. The backend opens on Structure, the page tree, with the starter article Home.

Open the backend from /redaxo/ and move around by its menu. Links into the backend that come from another site, a bookmark or the address bar are refused (Step 9), while /redaxo/ itself always opens.

The administrator can do everything. For editors, create accounts and roles under User with only the permissions they need.

6

Build your site

REDAXO separates the page tree from its presentation. Templates hold the page layout, Modules define the content blocks that editors fill in, and articles in Structure combine them. Open an article to edit its content blocks.

The starter page uses a template called SecureAnyCloud Starter with no modules. Create your own template and modules, then switch the article over or replace it. Upload images and documents in the Mediapool. They are served from /media/ as static files.

Addons extend REDAXO. AddOns lists the installed ones, and the Installer downloads more from the REDAXO repository, for example yrewrite for friendly URLs (this image's nginx configuration already routes them to REDAXO) or yform for forms. The Installer contacts www.redaxo.org only when you open it.

7

Settings and REDAXO's console

System shows the website address (set to your host name), the website name, the error e-mail address and REDAXO's version.

Set your own Email address in case of errors there. It starts as admin@example.com.

REDAXO's command-line console runs as the web server's user through redaxo-console. It prints a notice that REDAXO's top folder belongs to root, which is deliberate on this image:

sudo redaxo-console --version sudo redaxo-console config:get use_https | tail -1 sudo grep -x 'setup: false' /var/www/redaxo/redaxo/data/core/config.yml
[WARNING] Current user: www-data Owner of redaxo: root Running the console with a different user might cause unexpected side-effects. REDAXO 5.21.6 true setup: false

sudo redaxo-console list shows every command (clearing the cache, users, addons, database dumps). Never pass a password to it as an argument. Use redaxo-set-password instead (Step 12).

REDAXO sends a content security policy that keeps the backend out of other sites' frames, and nginx adds one that lets its pages connect only to your own server. Browsers apply both. Check the headers:

H=$(sed -n 's/^set \$redaxo_host "\(.*\)";$/\1/p' /etc/nginx/redaxo-host.conf)
curl -sk -D - -o /dev/null --resolve "$H:443:127.0.0.1" "https://$H/redaxo/" | tr -d '\r' | grep -i '^content-security-policy'
content-security-policy: frame-ancestors 'self' content-security-policy: connect-src 'self'; frame-ancestors 'self'
8

Your data

Your site is stored in three places:

  • The redaxo database in MariaDB holds everything that makes up your site.
  • /var/www/redaxo/media holds your files.
  • /var/www/redaxo/redaxo/data holds REDAXO's own data (the configuration and addon data).

The caches in /var/www/redaxo/redaxo/cache are rebuilt automatically. Keep redaxo/data/core/config.yml with your backup, because it holds this site's database password.

Back up the database to a file that only root can read, and back up the files. MariaDB's root account signs in over the local socket without a password, so no password appears on the command line:

sudo sh -c 'umask 077; mysqldump --single-transaction redaxo > /root/redaxo-$(date +%F).sql'
sudo tar -C /var/www/redaxo -czf /root/redaxo-files-$(date +%F).tgz media redaxo/data

REDAXO's Backup addon in the backend also exports the database. For a whole-instance copy, snapshot the EBS volume.

9

Security checks

Port 80 sends browsers to HTTPS, and the health endpoint answers load balancer checks. The configuration, REDAXO's source, cache and console, the setup wizard and stray PHP files in the writable folders are not reachable. Run this check:

H=$(sed -n 's/^set \$redaxo_host "\(.*\)";$/\1/p' /etc/nginx/redaxo-host.conf)
curl -s -o /dev/null -w 'port 80: %{http_code} -> %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/redaxo/" | sed -E 's#https://[^/]+#https://<your host>#'
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/healthz" for p in /redaxo/data/core/config.yml /redaxo/src/core/boot.php /redaxo/bin/console /redaxo/cache/ '/redaxo/index.php?page=setup' '/redaxo/index.php?setup_token=x' /media/x.php /assets/x.php; do
curl -sk -o /dev/null -w "$p: %{http_code}\n" -H 'Sec-Fetch-Site: same-origin' --resolve "$H:443:127.0.0.1" "https://$H$p" done
curl -s -o /dev/null -w 'unknown host name: %{http_code}\n' -H 'Host: example.com' http://127.0.0.1/ || true
port 80: 301 -> https://<your host>/redaxo/ ok /redaxo/data/core/config.yml: 404 /redaxo/src/core/boot.php: 404 /redaxo/bin/console: 404 /redaxo/cache/: 404 /redaxo/index.php?page=setup: 404 /redaxo/index.php?setup_token=x: 404 /media/x.php: 404 /assets/x.php: 404 unknown host name: 000

The value 000 means that nginx closed the connection without an answer.

A backend page opens when the request comes from your own site, and is refused when it comes from anywhere else (another site, a bookmark, the address bar). A link on another site therefore cannot make your signed-in browser act in the backend:

H=$(sed -n 's/^set \$redaxo_host "\(.*\)";$/\1/p' /etc/nginx/redaxo-host.conf) for s in same-origin cross-site none; do curl -sk -o /dev/null -w "Sec-Fetch-Site $s: %{http_code}\n" -H "Sec-Fetch-Site: $s" --resolve "$H:443:127.0.0.1" "https://$H/redaxo/index.php?page=system/settings" done
Sec-Fetch-Site same-origin: 200 Sec-Fetch-Site cross-site: 403 Sec-Fetch-Site none: 403

The rule covers backend pages (/redaxo/index.php?page=...), the sign-out and safe-mode switches, and REDAXO's API calls (rex-api-call) anywhere on the site. It lives in /etc/nginx/conf.d/sac-xsite-guard.conf, pinned to your host name by redaxo-set-hostname.

The credentials file is readable by root only, the configuration by the web server only, and the front controllers belong to root. MariaDB has no network listener, and nginx, PHP, MariaDB and first boot cannot reach the instance metadata service. Verify this:

sudo stat -c '%a %U:%G %n' /root/redaxo-credentials.txt /var/www/redaxo/redaxo/data/core/config.yml /var/www/redaxo/redaxo/data /var/www/redaxo/index.php /var/www/redaxo/redaxo/index.php
sudo mysql -N -e 'SELECT @@skip_networking, @@bind_address' for u in nginx php8.3-fpm mariadb redaxo-firstboot; do printf '%s: %s\n' "$u" "$(systemctl show -p IPAddressDeny --value $u)"; done
600 root:root /root/redaxo-credentials.txt 640 www-data:www-data /var/www/redaxo/redaxo/data/core/config.yml 750 www-data:www-data /var/www/redaxo/redaxo/data 644 root:root /var/www/redaxo/index.php 644 root:root /var/www/redaxo/redaxo/index.php 1 127.0.0.1 nginx: 169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 php8.3-fpm: 169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 mariadb: 169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128 redaxo-firstboot: 169.254.169.254/32 168.63.129.16/32 fd00:ec2::254/128

Run sudo redaxo-cred-roundtrip to sign in through the real backend form with the password from the credentials file and to check that wrong passwords are refused.

10

Behind a proxy or load balancer

nginx removes X-Forwarded-For, X-Real-IP, Client-IP and Forwarded from every request, and REDAXO reads the client address from the connection, so the backend's session list and the logs use the address of the connection.

Behind an AWS load balancer, that is the load balancer's address, and nginx's own access log (/var/log/nginx/access.log) records it the same way. To record visitors' addresses, use nginx's real_ip module with set_real_ip_from set to your load balancer's subnet only.

11

Your own DNS name and certificate

Point a DNS record at the instance, then set the name that REDAXO is served as. The command below mints a new self-signed certificate for the name, updates nginx (which hands the name to REDAXO), the cross-site rule and REDAXO's website address, clears REDAXO's cache, updates the addresses in /root/redaxo-credentials.txt and keeps the name across reboots:

sudo redaxo-set-hostname <your-domain>

To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running redaxo-set-hostname again replaces it with a self-signed certificate.

sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/redaxo.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/redaxo.key
sudo nginx -t && sudo systemctl reload nginx

Once browsers trust the certificate, you can also add an HSTS header (add_header Strict-Transport-Security "max-age=31536000" always;) to /etc/nginx/snippets/sac-redaxo-headers.conf. The image does not send one, because browsers ignore HSTS from a site whose certificate they do not trust.

12

Passwords, e-mail, addons and upgrades

redaxo-set-password gives the administrator a new random password with REDAXO's own console, signs out every session and records the password in /root/redaxo-credentials.txt. Run it without arguments, or pass your own password (24 to 72 letters and digits) on stdin. Users change their own passwords under their profile.

sudo redaxo-set-password printf '%s\n' '<your-new-password>' | sudo redaxo-set-password --stdin

The setup wizard. REDAXO's backend offers to run setup again (System), but on this image nginx refuses the wizard's page, so nobody can open it in a browser. To re-run setup, use the console: sudo redaxo-console setup:run.

E-mail. REDAXO's core sends no mail. Before you rely on e-mail from addons, install the PHPMailer addon (shipped, not active) under AddOns and set an SMTP server there.

Addons. Install and update addons through the Installer or AddOns in the backend. REDAXO writes them to redaxo/src/addons and copies their assets to assets. Install only addons you trust, because they run with the web server's rights.

Upgrades. The Installer also offers REDAXO core updates (Installer > Update). Take a snapshot first. After an update, /usr/share/doc/redaxo/REDAXO-5.21.6.sha256 describes the old release, so the check in Step 3 then reports the changed files.

13

Server components

These are the component locations on the instance:

  • REDAXO (site front controller, root-owned): /var/www/redaxo
  • Backend front controller and console: /var/www/redaxo/redaxo/index.php, /var/www/redaxo/redaxo/bin/console
  • Configuration (this instance's database password): /var/www/redaxo/redaxo/data/core/config.yml
  • Media and addon assets: /var/www/redaxo/media, /var/www/redaxo/assets
  • Caches (rebuilt automatically): /var/www/redaxo/redaxo/cache
  • Database (MariaDB datadir): /var/lib/mysql
  • nginx site, request limits and cross-site link rules: /etc/nginx/sites-available/sac-redaxo, /etc/nginx/conf.d/sac-redaxo-guard.conf, /etc/nginx/conf.d/sac-xsite-guard.conf, /etc/nginx/snippets/sac-redaxo-*.conf
  • PHP settings: /etc/php/8.3/fpm/conf.d/99-sac-redaxo.ini
  • MariaDB settings: /etc/mysql/mariadb.conf.d/99-sac-redaxo.cnf
  • Certificate and key: /etc/nginx/ssl/
  • First-boot script and helpers: /usr/local/sbin/redaxo-firstboot.sh, /usr/local/lib/sac/redaxo/
  • Helpers: /usr/local/sbin/redaxo-console, redaxo-set-hostname, redaxo-set-password, redaxo-cred-roundtrip
  • Licence, release, manifest and image notes: /usr/share/doc/redaxo/
  • Credentials: /root/redaxo-credentials.txt (mode 0600)
14

Security recommendations

  • Allow port 22 in the security group from your own networks only.
  • Keep the administrator password secret and rotate it if it may have been shared (Step 12). Give editors their own accounts with limited roles.
  • Keep config.yml and your database backups secret (Step 8).
  • Use your own DNS name and a certificate that your browsers trust (Step 11).
  • Keep REDAXO and its addons on their newest releases (Step 12), and install only addons you trust.
  • Keep the operating system patched. Unattended security upgrades are on, and sudo apt-get update && sudo apt-get upgrade applies everything else. MariaDB and PHP-FPM with its zip and intl extensions come from Ubuntu's universe repository. Run sudo pro security-status --esm-apps to see whether Ubuntu Pro (ESM Apps) has security updates for them (none were pending when the image was built).

Support and licensing

REDAXO is open-source software by Yakamara Media GmbH & Co. KG under the MIT licence (a copy is at /usr/share/doc/redaxo/LICENSE.md). The licence asks that the backend keeps the link to www.redaxo.org and the REDAXO logo visible, which the image's stock backend does. The bundled libraries carry their own open-source licences (MIT, LGPL-2.1 for PHPMailer, GPL-2.0-or-later for svg-sanitize).

There is no per-user or per-CPU licence fee and no licence key. This image installs the unmodified upstream release plus the SecureAnyCloud first-boot setup, settings and helpers described above. The AMI price covers SecureAnyCloud's hardening, first-boot setup and support.

  • Email: sales@secureanycloud.com
  • Website: https://secureanycloud.com
  • Support: 24/7, with a 24 hour response SLA

Deploy on AWS

Launch REDAXO CMS 5.21.6 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

Deploy on AWS