Engelsystem 3.7.1
Overview
Engelsystem is the open source shift planning system that the Chaos Communication Congress and many other festivals and conferences use to organise their volunteers, the "angels". Organisers define locations, angel types (teams such as info desk, kitchen and stage crew) and shifts. Angels sign up for the shifts they want, and organisers see who has arrived, who is working and who is free.
This guide covers launching and using the Engelsystem 3.7.1 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud ERP and CRM listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.
What you get on top of upstream Engelsystem:
- No default login. Upstream's first account
admin, with the published passwordasdfasdf, never exists on this image. First boot creates the administrator under a name unique to your instance (admin-and six hex digits) with a 24-character password generated on the instance. It writes both to/root/engelsystem-credentials.txt(root-only). - Nothing shared between instances. The image ships no database, no configuration file and no key. On your instance, first boot initialises MySQL, creates the database and its user with a fresh password, and mints Engelsystem's app key and API key. It also runs Engelsystem's database migrations and generates the TLS certificate.
- HTTPS from the first boot. nginx serves Engelsystem on port 443 with a certificate generated on your instance. Port 80 redirects to HTTPS, and requests for a host name the instance does not serve are dropped.
- Fail closed. nginx and PHP start only after first boot has finished. If it cannot finish, nothing is served.
- Closed by default. Public registration is off, and outgoing e-mail goes to a log until you configure a mail server. No single sign-on (OAuth) provider is configured and no schedule import is set up. You turn each on when you need it (Step 7).
- Rate limits. Engelsystem has no sign-in throttle of its own, so nginx limits the sign-in, registration and password reset pages to 10 requests a minute per client. It limits every state-changing request to 600 a minute and every page to 1800 a minute. A client is one IPv4 address or one IPv6 /64, taken from the connection and never from a header a client can forge.
- Hardened defaults. nginx, PHP-FPM, MySQL and the first-boot service are blocked from the instance metadata service, and the AMI requires IMDSv2. Engelsystem's PHP runs as its own user with its code read-only. That user cannot open connections to the metadata service, to other hosts in your VPC or to local services unless you allow them. The two state-changing links that a malicious page could trigger (sign out and the schedule reload) refuse cross-site requests. The access log records paths only, never the query string that carries Engelsystem's API key.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: Engelsystem 3.7.1 (the upstream release, checksum verified, with three of its PHP libraries raised to fixed releases, see Step 10), nginx 1.24, PHP 8.3 FPM with OPcache, MySQL 8.0 (all from Ubuntu 24.04), cloud-init and the AWS Systems Manager agent. PHP is Ubuntu's 8.3.6-0ubuntu0.24.04.13 build or later.
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 with a route to the internet (or a private route you use for management).
- A security group that allows TCP 22 (SSH) from your admin network. It must also allow TCP 443 (Engelsystem) and TCP 80 (redirects to HTTPS) from the networks your angels and organisers work from. MySQL has no network port to open.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick Engelsystem 3.7.1 on Ubuntu 24.04 as the software version, choose your Region, and select Launch through EC2.
Choose m5.large, your key pair and a security group as described above. The root volume holds the database, so give it room to grow (for example 30 GiB or more for a large event).
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> \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=30,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=engelsystem}]'First boot takes about a minute after the instance is running.
Connect to your instance
Connect over SSH as the ubuntu user, which is the SSH user for Engelsystem 3.7.1 on Ubuntu 24.04:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot initialises MySQL, creates the database, installs Engelsystem and the administrator, and generates the certificate. Then PHP-FPM and nginx start. Check that the services are running:
systemctl is-active nginx php8.3-fpm mysql engelsystem-egress-guard engelsystem-firstboot
sudo test -f /var/lib/sac/data/engelsystem-firstboot.done && echo FIRSTBOOT_DONEAll five units report active, and the first-boot marker is present:
active active active active active FIRSTBOOT_DONEOnly SSH and nginx listen on network ports. MySQL has no TCP listener, and PHP-FPM uses a local socket:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v ':53 ' | 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")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))Get your URL, user name and password
Read the credentials file. Only root can read it:
sudo cat /root/engelsystem-credentials.txtThe file looks like this:
# Engelsystem 3.7.1 - generated on first boot by engelsystem-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. ENGELSYSTEM_URL=https://<public-dns-name>/login ENGELSYSTEM_ADMIN_USER=admin-<6 hex digits> ENGELSYSTEM_ADMIN_PASSWORD=<ENGELSYSTEM_ADMIN_PASSWORD> ENGELSYSTEM_TLS_SHA256=<ENGELSYSTEM_TLS_SHA256>
#
# Open ENGELSYSTEM_URL in a browser (self-signed certificate minted on this instance's first boot; compare its SHA-256 # fingerprint with ENGELSYSTEM_TLS_SHA256; port 80 redirects to https) and sign in with the user name and password # above (upstream's default admin / asdfasdf does not exist on this image).
# Public self-registration is OFF: tick Admin > Config > Event > Registration enabled when volunteers should sign up.
# /metrics needs the API key in /etc/engelsystem/config.php ('api_key'): https://<host>/metrics?api_key=<key>
# Database: MySQL 8.0 on this instance (unix socket only), database and user engelsystem; the password is in
# /etc/engelsystem/config.php. Outbound e-mail ships OFF (driver 'log', no SMTP credential): see the user guide.
# Services: nginx php8.3-fpm mysql engelsystem-egress-guard Migrations:
sudo engelsystem-migrate
# Change the password:
sudo engelsystem-set-password
# Change the name it serves as:
sudo engelsystem-set-hostname <your-dns-name>
# User guide: https://secureanycloud.com/stacks/engelsystem-3-7-1/The URL uses the instance's public DNS name from the EC2 instance metadata, or its public IP address when the subnet gives no DNS name. The certificate also names the public and private IP addresses.
If you stop and start the instance without an Elastic IP, its public name changes. Set the new name with engelsystem-set-hostname (Step 8), or use your own DNS name.
Sign in
Browse to the URL from the credentials file. Your browser warns once about the self-signed certificate. Check that the SHA-256 fingerprint it shows matches ENGELSYSTEM_TLS_SHA256, then accept it (or install your own certificate, see Step 8).
Sign in with the user name (Nick) and password from the credentials file.
You can also read the fingerprint on the instance:
echo | openssl s_client -connect 127.0.0.1:443 2>/dev/null | openssl x509 -noout -fingerprint -sha256After you sign in, you land on News. The menu across the top holds News, Meetings, Shifts, Angel types, Locations, Ask Heaven (questions to the organisers) and Admin. Your own menu at the top right holds your shifts, your settings and sign out.
Set up your event
The image starts with an empty event. Set it up in this order:
- Admin > Config. Under Event, set the event name, the welcome message and the build-up, start, end and tear-down dates. The other tabs hold the feature switches, the certificate requirements (driving licence, food hygiene), the shift settings and the goodie (T-shirt or voucher) settings.
- Locations. Add each place where angels work (Main Hall, Infodesk, Kitchen).
- Angel types. Add a type for each team. Mark a type as requiring an introduction when only angels you have briefed may take its shifts. Allow self sign-up where anyone may.
- Admin > Shift types and Admin > Create shifts. Define your shift types, then create the shifts per location with the number of angels of each type they need.
- Admin > Group rights. Decide what each group (Angel, Shift Coordinator, Team Coordinator, Bureaucrat and so on) may do. Promote your organisers on their user pages under Admin > All Angels.
During the event, use these pages:
- Admin > Arrive angels records who has arrived.
- Admin > Active angels shows who has worked enough to earn a goodie.
- Admin > Free angels lists the angels who are on site and not on a shift right now.
Registration, e-mail, single sign-on and schedule import
All four ship switched off. Turn on only what you need.
Registration. Angels cannot sign up on their own until you tick Admin > Config > Event > Registration enabled. Until then, create accounts yourself under Admin > All Angels (the + button).
E-mail. Engelsystem sends mail for password resets, shift changes and news. On this image the mail driver is log, so nothing is sent and each message is written to Engelsystem's log instead.
To send mail, edit the email section of /etc/engelsystem/config.php (owned by root, readable by Engelsystem's group only) with your mail server, for example Amazon SES SMTP:
'email' => [ 'driver' => 'smtp', 'from' => [ 'address' => 'shifts@<your-domain>', 'name' => 'Engelsystem', ], 'host' => 'email-smtp.<region>.amazonaws.com', 'port' => 587, 'tls' => true, 'username' => '<smtp-user>', 'password' => '<smtp-password>', ],Then apply the change:
sudo systemctl reload php8.3-fpmSingle sign-on. Engelsystem can sign angels in with an OAuth 2 provider (Keycloak, Authentik, GitLab or your event's own identity system). Add an oauth section to /etc/engelsystem/config.php with the provider's client ID, client secret, and its authorisation, token and user info URLs. Engelsystem's config/app.php (/var/www/engelsystem/config/app.php) describes the format. Then reload PHP-FPM as above.
Schedule import. Admin > Import schedule reads a conference schedule from a URL and creates the matching shifts. The schedule uses the Frab/Pentabarf XML format that pretalx and Frab publish. Add the schedule URL there when you want it. Engelsystem fetches the URL from the instance.
Servers inside your VPC. Engelsystem's PHP may connect to servers on the internet (your mail service, OAuth provider or schedule). It may not connect to the instance metadata service, link-local or reserved ranges, local services, or any address inside your own VPC.
Suppose your mail relay, OAuth provider or schedule server has a private address in this VPC, or you reach Amazon SES through a VPC interface endpoint. Add that address to the allow list, one address or CIDR per line, and restart the guard. Replace <private-ip> with the server's private address:
echo '<private-ip>' | sudo tee -a /etc/sac/engelsystem-egress-allow.conf
sudo systemctl restart engelsystem-egress-guardYour own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name that Engelsystem is served as. The command mints a new self-signed certificate for the name and updates nginx. It also updates Engelsystem's configured URL (used in every link and e-mail) and the URL and fingerprint in /root/engelsystem-credentials.txt. The name persists across reboots.
sudo engelsystem-set-hostname <your-domain>To use a certificate from a public or private certificate authority instead (for example one issued by Let's Encrypt for <your-domain>), copy it over the generated pair and reload nginx. Running engelsystem-set-hostname again replaces it with a self-signed one.
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/engelsystem.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/engelsystem.key
sudo nginx -t && sudo systemctl reload nginxSecurity checks
The image ships a round-trip check. It verifies that:
- port 80 redirects to HTTPS
- the front controller prefix, the configuration and the sources are refused
- the health checks answer
- the administrator signs in through Engelsystem's own sign-in form (with its CSRF token) with this instance's password, while a wrong password and upstream's default are refused
/metricsneeds the API key
Passwords are handed to the sign-in helper in root-only temporary files, never on a command line. Run the check:
sudo /usr/local/sbin/engelsystem-cred-roundtripENGELSYSTEM_ROUNDTRIP_OK https 301 + no index.php/config/sources + health + administrator sign-in (Engelsystem's own sign-in form, CSRF token) + wrong and default passwords refused + /metrics needs the API keyThe configuration, the PHP libraries, the sources and the front controller prefix answer 404. Plain HTTP redirects to HTTPS on the configured name, and a host name the instance does not serve gets no answer at all:
H=$(sudo grep '^ENGELSYSTEM_URL=' /root/engelsystem-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#') for p in /login /healthz /index.php /index.php/login /config/config.php /vendor/autoload.php /composer.json /.env /bin/migrate; do curl -sk -o /dev/null -w "%{http_code} $p\n" --resolve "$H:443:127.0.0.1" "https://$H$p" done curl -s -o /dev/null -w 'http:// -> %{http_code}\n' --resolve "$H:80:127.0.0.1" "http://$H/login" curl -sk -o /dev/null -w 'unknown host name -> %{http_code}\n' --resolve "other.example:443:127.0.0.1" https://other.example/ || true200 /login 200 /healthz 404 /index.php 404 /index.php/login 404 /config/config.php 404 /vendor/autoload.php 404 /composer.json 404 /.env 404 /bin/migrate http:// -> 301 unknown host name -> 000The certificate was generated on this instance and names the instance's own addresses:
H=$(sudo grep '^ENGELSYSTEM_URL=' /root/engelsystem-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#')
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -subject -ext subjectAltNamesubject=CN = <public-dns-name>, O = sac X509v3 Subject Alternative Name: DNS:<public-dns-name>, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhostNone of these services can reach the instance metadata service:
systemctl show nginx php8.3-fpm mysql engelsystem-firstboot -p Id -p IPAddressDenyIPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=nginx.service IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=php8.3-fpm.service IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=mysql.service IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=engelsystem-firstboot.serviceOn top of that, an nftables table built at every boot stops Engelsystem's own user (the one PHP runs as) from reaching the metadata service, reserved ranges, local services and the addresses of your VPC. The table reads those VPC addresses from the instance metadata at boot. Every other user on the instance is unaffected:
sudo nft list table inet sac_es_egress | grep -E 'comment|elements'The rate limits are keyed on the address of the connection (an IPv4 address, or the /64 network of an IPv6 address), so a client cannot dodge them with a forged X-Forwarded-For header. A client that goes over a limit briefly receives HTTP 429:
grep -h 'limit_req_zone' /etc/nginx/conf.d/sac-engelsystem.conflimit_req_zone $es_login_key zone=es_login:10m rate=10r/m; limit_req_zone $es_post_key zone=es_post:10m rate=600r/m; limit_req_zone $sac_client_key zone=es_php:10m rate=1800r/m;MySQL runs without networking. Engelsystem's database user engelsystem can reach only its own database, and only from the instance. root works only from the instance itself, as the operating system's root (sudo mysql):
sudo mysql -e "SELECT @@skip_networking, @@local_infile, @@log_bin, @@general_log; SELECT user, host, plugin FROM mysql.user ORDER BY user;"@@skip_networking @@local_infile @@log_bin @@general_log 1 0 0 0 user host plugin engelsystem localhost caching_sha2_password mysql.infoschema localhost caching_sha2_password mysql.session localhost caching_sha2_password mysql.sys localhost caching_sha2_password root localhost auth_socketEngelsystem's Prometheus metrics at /metrics answer only with the API key from /etc/engelsystem/config.php:
H=$(sudo grep '^ENGELSYSTEM_URL=' /root/engelsystem-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/.*#\1#')
K=$(sudo php -r '$c = require "/etc/engelsystem/config.php"; echo $c["api_key"];')
curl -sk -o /dev/null -w 'without the key -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/metrics"
curl -sk --resolve "$H:443:127.0.0.1" "https://$H/metrics?api_key=$K" | grep -c '^engelsystem_'Without the key, the answer is 403. With the key, the second command counts the engelsystem_ metrics it returns:
without the key -> 403 <number of metrics>Versions and where things are
cat /var/www/engelsystem/storage/app/VERSION; echo php -r 'echo PHP_VERSION."\n";' mysqld --version nginx -v head -4 /usr/share/doc/engelsystem/SOURCE.txtv3.7.1 8.3.6 /usr/sbin/mysqld Ver 8.0.46-0ubuntu0.24.04.4 for Linux on x86_64 ((Ubuntu)) nginx version: nginx/1.24.0 (Ubuntu) Engelsystem 3.7.1 on Ubuntu 24.04 by sac - source and changes Upstream: the Engelsystem 3.7.1 release zip, https://github.com/engelsystem/engelsystem/releases/download/v3.7.1/engelsystem-v3.7.1.zip (sha256 1613d95b4746fec93c04344d789e524d3c0a6485561805686290e370e2832587; GitHub tag v3.7.1, commit 2ffb80f84a05f63b45dbf6707abff144ec1676eb).Three of the PHP libraries bundled with the release were raised to versions that fix published advisories, within the release's own version constraints:
- symfony/http-foundation 7.4.19 to 7.4.23
- symfony/mime 8.1.7 to 7.4.22 (the 8.1 line also needs PHP 8.4, and Ubuntu 24.04 ships 8.3)
- symfony/yaml 7.4.18 to 7.4.23
composer audit of the shipped libraries reports no advisories. /usr/share/doc/engelsystem/SOURCE.txt lists every change.
Engelsystem's database migrations were written for MariaDB, and two of them give text columns a default value, which MySQL refuses in its default strict mode. /etc/engelsystem/config.php therefore sets Engelsystem's database session to MariaDB's default mode without strict mode ('modes' => ['ERROR_FOR_DIVISION_BY_ZERO', 'NO_ENGINE_SUBSTITUTION']). Keep that line if you edit the database section.
Where things are:
- Engelsystem (read-only, owned by root): /var/www/engelsystem
- Engelsystem configuration: /etc/engelsystem/config.php (root, readable by the engelsystem group)
- Engelsystem cache: /var/lib/engelsystem/cache
- MySQL database: /var/lib/mysql (database engelsystem)
- PHP-FPM pool: /etc/php/8.3/fpm/pool.d/engelsystem.conf (runs as the user engelsystem)
- nginx site and limits: /etc/nginx/sites-available/sac-engelsystem, /etc/nginx/conf.d/sac-engelsystem.conf
- Certificate and key: /etc/nginx/ssl/
- Logs: /var/log/nginx/, /var/log/php8.3-fpm.log, /var/log/mysql/
- Boot services: /usr/local/sbin/engelsystem-firstboot.sh, /usr/local/sbin/engelsystem-egress-guard
- Egress allow list: /etc/sac/engelsystem-egress-allow.conf
- Helpers: /usr/local/sbin/engelsystem-set-hostname, engelsystem-set-password, engelsystem-migrate, engelsystem-cred-roundtrip
- Credentials: /root/engelsystem-credentials.txt (mode 0600)
Changing passwords
- The administrator: change the password in Engelsystem (your menu at the top right, Settings > Password) or on the instance. The helper below sets a new random password through Engelsystem's own password handling. It also removes any password reset links, signs every session out and writes the new password to
/root/engelsystem-credentials.txt. To choose the password yourself, pipe it in with--stdin(20 to 72 letters and digits), so it never appears on a command line:
sudo engelsystem-set-password
sudo grep '^ENGELSYSTEM_ADMIN_PASSWORD=' /root/engelsystem-credentials.txt- Angels: they reset their own password from the sign-in page (I forgot my password) once outgoing mail is set up (Step 7). The reset link always points at the configured URL, never at a host name taken from the request.
Backup and maintenance
Everything Engelsystem stores is in the MySQL database engelsystem. The simplest backup is an EBS snapshot of the root volume.
To back up on the instance while Engelsystem is running:
sudo mysqldump --single-transaction --routines --triggers engelsystem | gzip > <backup-dir>/engelsystem-$(date +%F).sql.gz
sudo cp /etc/engelsystem/config.php <backup-dir>/engelsystem-config-$(date +%F).phpThe configuration file holds the app key, the API key and the database password, so keep the copy as safe as the database.
To restore into a fresh instance of the same version, stop PHP-FPM, load the dump and start PHP-FPM again:
sudo systemctl stop php8.3-fpm gunzip -c <backup-dir>/engelsystem-<date>.sql.gz | sudo mysql engelsystem
sudo systemctl start php8.3-fpmOperating system, nginx, PHP and MySQL security updates install automatically from Ubuntu. To apply everything else, run sudo apt-get update && sudo apt-get upgrade.
To move to a newer Engelsystem release, launch the newer version from the listing and restore your database into it. The new instance applies any new migrations with sudo engelsystem-migrate. You can also contact SecureAnyCloud support. Take a snapshot first.
Security recommendations
- Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your angels and organisers use.
- Use your own DNS name and a certificate your browsers trust (Step 8).
- Give organisers their own accounts in the smallest group that fits, and keep the administrator account for administration.
- Turn registration on only while you are recruiting angels, and set up mail first so they can reset their passwords.
- Change the administrator password if it may have been shared (Step 11), keep the operating system patched, and snapshot the volume regularly.
- The compiled front end that ships in the Engelsystem release includes the JavaScript library deepmerge, which has two published advisories of low severity. It runs only in the browser on data the page itself builds, never on the server. The release cannot be rebuilt without changing Engelsystem, so it ships as released.
Support and licensing
Engelsystem is open source software licensed under the GNU General Public License version 2 or later. SecureAnyCloud ships its code unmodified, with three bundled PHP libraries raised to fixed releases. The source location, checksums and changes are in /usr/share/doc/engelsystem/SOURCE.txt.
There is no per-user licence fee. The AMI price covers SecureAnyCloud's hardening, first-boot setup and support. Engelsystem is developed by its contributors, and SecureAnyCloud is not affiliated with or endorsed by the Engelsystem project.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- Support: 24/7, with a 24-hour response SLA
Deploy on AWS
Launch Engelsystem 3.7.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