LibreBooking 7.2.0
Overview
LibreBooking is an open-source, self-hosted scheduling and reservation application, the maintained community fork of phpScheduleIt and Booked. Your team books meeting rooms, desks, vehicles, lab equipment or any other shared resource on a calendar. You set up schedules and resources, decide who may book what, require approval where you need it, and see everything on the dashboard and the schedule.
This guide covers the LibreBooking 7.2.0 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud documents, forms and scheduling listing on the AWS Marketplace, which you select as the software version when you subscribe and launch. Everything stays on your own instance in your own VPC.
A fresh upstream install starts with a web installer that anyone who reaches it can run, lets visitors register their own accounts, and leaves its REST API on. The SecureAnyCloud image changes all three.
What you get:
- HTTPS from the first boot. nginx serves LibreBooking on port 443 with a certificate generated on your instance's first boot. Port 80 redirects to HTTPS. The SHA-256 fingerprint of the certificate is written to the credentials file, so you can check it the first time you connect.
- One administrator, unique to your instance. First boot creates the database, its password and a single Application Administrator called
admin-<6 hex characters>with a random password, using the LibreBooking installer. There are no sample accounts and no web installer on the image. The account name and password are written to/root/librebooking-credentials.txt(root-only). - Closed by default. Self-registration, the anonymous schedule view, password reset by e-mail, all e-mail, the REST API, calendar subscriptions, reservation attachments and the in-browser settings page are off. You add people yourself, and you turn e-mail on when you have an SMTP relay (Step 9).
- Fail closed. nginx and PHP-FPM refuse to start until first boot has generated the certificate, the database and the administrator, so the application is never served half configured.
- Hardened. Requests for host names the instance does not serve are dropped. Sign-in attempts are rate-limited, and cross-site posts to sign-out are refused. The LibreBooking code is owned by root and read-only to PHP, and PHP never runs from the upload directory. MySQL listens on a Unix socket only, with no binary log. nginx, PHP-FPM and MySQL are blocked from the instance metadata service, the PHP user cannot reach private addresses in your VPC unless you allow them (Step 10), and the AMI requires IMDSv2.
- The official release, verified. The LibreBooking 7.2.0 release is checked against a pinned SHA-256 checksum and its PHP dependencies are installed from upstream's own
composer.lock, with one security update:symfony/html-sanitizeris raised from 7.4.13 to 7.4.23 to fix CVE-2026-118517, CVE-2026-121373 and CVE-2026-121949. The image is fully patched Ubuntu 24.04 LTS with unattended security upgrades on. - 24/7 SecureAnyCloud support
What is on the image: LibreBooking 7.2.0 in /var/www/librebooking, PHP 8.3 (PHP-FPM), MySQL 8.0 and nginx from the Ubuntu archive, Ubuntu 24.04 LTS, cloud-init and the AWS Systems Manager agent.
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), TCP 443 (LibreBooking) and TCP 80 (redirects to HTTPS). Open port 22 from your own networks only, and open ports 443 and 80 to the people who will book resources.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick LibreBooking 7.2.0 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.
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=librebooking}]'Connect to your instance
Version and SSH user:
LibreBooking 7.2.0 on Ubuntu 24.04 ubuntu
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot creates the database, the administrator and the certificate, and then nginx and PHP-FPM start. librebooking-firstboot runs once and then shows as inactive:
systemctl is-active nginx php8.3-fpm mysql librebooking-egress-guard librebooking-firstboot
sudo test -f /var/lib/sac/data/librebooking-firstboot.done && echo FIRSTBOOT_DONEactive active active active inactive FIRSTBOOT_DONEOnly SSH and nginx listen on the network. MySQL has no TCP listener at all, and PHP-FPM listens on a Unix socket:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | 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.53%lo:53 users:(("systemd-resolve",...)) 127.0.0.54:53 users:(("systemd-resolve",...)) [::]:22 users:(("sshd",...),("systemd",...)) [::]:443 users:(("nginx",...),("nginx",...),("nginx",...)) [::]:80 users:(("nginx",...),("nginx",...),("nginx",...))Get your URL and administrator password
Only root can read the credentials file. This command prints everything in it except the password line:
sudo grep -v '^LIBREBOOKING_ADMIN_PASSWORD=' /root/librebooking-credentials.txt# LibreBooking 7.2.0 - generated on first boot by librebooking-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. LIBREBOOKING_URL=<LIBREBOOKING_URL> LIBREBOOKING_ADMIN_USER=admin-<6hex> LIBREBOOKING_TLS_SHA256=<LIBREBOOKING_TLS_SHA256>
# Open LIBREBOOKING_URL in a browser ... ...Print the administrator password itself only when you are ready to sign in. Run sudo grep '^LIBREBOOKING_ADMIN_PASSWORD=' /root/librebooking-credentials.txt | cut -d= -f2-
<LIBREBOOKING_URL> is https://<the instance's public DNS name>/Web/, taken from EC2 instance metadata on first boot.
The rest of the file lists what is switched off, where the database password is kept and the helper commands used later in this guide. To serve LibreBooking under your own DNS name, see Step 11.
Check the certificate and sign in
The certificate is self-signed, so your browser asks you to confirm it the first time. Before you accept it, compare its SHA-256 fingerprint (in the certificate viewer of the browser) with <LIBREBOOKING_TLS_SHA256> from the credentials file. From your workstation, you can read the fingerprint with OpenSSL:
echo | openssl s_client -connect <public-ip>:443 2>/dev/null | openssl x509 -noout -fingerprint -sha256On the instance itself, the same check reads the fingerprint that nginx serves:
H=$(sudo sed -n 's#^LIBREBOOKING_URL=https://\([^/]*\)/.*#\1#p' /root/librebooking-credentials.txt)
echo | openssl s_client -connect 127.0.0.1:443 -servername "$H" 2>/dev/null | openssl x509 -noout -fingerprint -sha256 sudo grep '^LIBREBOOKING_TLS_SHA256=' /root/librebooking-credentials.txtThe two fingerprints match:
sha256 Fingerprint=<LIBREBOOKING_TLS_SHA256> LIBREBOOKING_TLS_SHA256=<LIBREBOOKING_TLS_SHA256>Open <LIBREBOOKING_URL> and sign in with LIBREBOOKING_ADMIN_USER (or its e-mail address, admin-<6hex>@example.com) and LIBREBOOKING_ADMIN_PASSWORD. There is no Register link, because self-registration is off.
Next, open My Account > Profile and enter your real e-mail address, name and organisation for the administrator. This makes the account recognisable in reservations and, once e-mail is on, lets it receive notifications.
Set up your resources
Under Application Management > Resources select Add Resource for each item people will book: rooms, desks, vehicles or equipment. Each resource belongs to a schedule (the image starts with the LibreBooking default schedule). A resource can have a location, a contact, a capacity, booking rules such as minimum and maximum length and notice, and an approval requirement.
Application Management > Schedules sets the opening hours and slot layout for each schedule. Application Management > Users is where you add people, because they cannot register themselves. Groups lets you give a team permission to book a resource or approve its reservations.
Book a resource
Schedule > Bookings shows the week for each schedule, with existing reservations in place. Select a free slot to book it.
In the reservation form, set the title, the resource, the start and end, any repeat, and participants and invitees, then select Create.
The Dashboard lists each person's upcoming reservations and announcements.
Check the security posture from the command line
Port 80 redirects to HTTPS, the site root redirects to the sign-in page, and the registration page, the web installer, the REST API and the configuration are not served. A request for a host name the instance does not serve is dropped without an answer:
H=$(sudo sed -n 's#^LIBREBOOKING_URL=https://\([^/]*\)/.*#\1#p' /root/librebooking-credentials.txt)
curl -s -o /dev/null -w 'http:// -> %{http_code} %{redirect_url}\n' --resolve "$H:80:127.0.0.1" "http://$H/"
curl -sk -o /dev/null -w 'https:// / -> %{http_code} %{redirect_url}\n' --resolve "$H:443:127.0.0.1" "https://$H/"
curl -sk -o /dev/null -w 'sign-in page -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/Web/"
curl -sk -o /dev/null -w 'register.php -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/Web/register.php"
curl -sk -o /dev/null -w 'web installer -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/Web/install/"
curl -sk -o /dev/null -w 'REST API -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/Web/Services/"
curl -sk -o /dev/null -w 'config.php -> %{http_code}\n' --resolve "$H:443:127.0.0.1" "https://$H/config/config.php"
curl -sk -o /dev/null -w 'unknown host -> %{http_code}\n' --resolve "evil.example:443:127.0.0.1" "https://evil.example/" || truehttp:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ https:// / -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/Web/ sign-in page -> 200 register.php -> 404 web installer -> 404 REST API -> 404 config.php -> 404 unknown host -> 000000 means nginx closed the connection without answering, which is how it treats any host name it does not serve.
The image ships a round-trip check that signs in through the LibreBooking sign-in form with the administrator's password. It also proves that a wrong password and the upstream sample accounts are refused, and it never prints the password:
sudo librebooking-cred-roundtripLIBREBOOKING_ROUNDTRIP_OK https 301 + / -> /Web/ + no code/config/installer/API/registration/upload PHP + health + administrator sign-in (LibreBooking's own sign-in form) + wrong password and sample accounts refusedUpload your logo and favicon under Application Management > Customization > Look and Feel. LibreBooking stores them in /var/lib/librebooking-public/images and serves them as images only. The code tree stays read-only to PHP, so a CSS file uploaded on that page is not applied.
The round-trip check can prove the page end to end. With --logo, it signs in once, uploads a 1x1 test logo through the form on the page, fetches it back and removes it again. It refuses to run while a logo of yours is uploaded, so it never replaces one:
sudo librebooking-cred-roundtrip --logoLIBREBOOKING_LOGO_OK administrator sign-in + Look and Feel page + logo upload (CSRF token) -> /var/lib/librebooking-public/images/custom-logo.png, served back byte for byte at /Web/uploads/images/ + Remove deleted itThe secrets live in root-only or group-restricted files. config.php holds the database password and is readable by the librebooking group (PHP-FPM) but writable by root only:
sudo stat -c '%a %U:%G %n' /root/librebooking-credentials.txt /etc/librebooking/config.php /etc/nginx/ssl/librebooking.key /etc/nginx/ssl/librebooking.crt600 root:root /root/librebooking-credentials.txt 640 root:librebooking /etc/librebooking/config.php 600 root:root /etc/nginx/ssl/librebooking.key 644 root:root /etc/nginx/ssl/librebooking.crtnginx, PHP-FPM and MySQL cannot reach the instance metadata service:
systemctl show nginx php8.3-fpm mysql -p Id -p IPAddressDenyIPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=nginx.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=php8.3-fpm.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=mysql.serviceThe closed defaults are in /etc/librebooking/config.php. The first three lines are self-registration, password reset (disabled) and the anonymous schedule view. The last two lines are e-mail and the REST API:
sudo grep -nE "'(allow.self.registration|disable.reset|view.schedules)' =>" /etc/librebooking/config.php
sudo awk "/^ 'email' =>/{f=1} f&&/'enabled'/{print; exit}" /etc/librebooking/config.php
sudo awk "/^ 'api' =>/{f=1} f&&/'enabled'/{print; exit}" /etc/librebooking/config.php141: 'allow.self.registration' => false, 179: 'disable.reset' => true, 187: 'view.schedules' => false, 'enabled' => false, 'enabled' => false,Turn on e-mail
E-mail is off because no SMTP relay is configured. While it is off, LibreBooking sends no reservation notices or reminders, and password reset by e-mail stays disabled. To turn it on, edit the configuration as root:
sudo nano /etc/librebooking/config.phpSet 'enabled' => true in the 'email' section with your sender address. Set 'admin.email' near the top of the file to the address that should receive administrator mail, and fill in the 'phpmailer' section for your relay.
The following example is for Amazon SES. Outbound port 25 is throttled on EC2, so use port 587 with STARTTLS:
'email' => array ( 'enabled' => true, 'enforce.custom.template' => false, 'default.from.address' => 'bookings@<your-domain>', 'default.from.name' => 'Room bookings', ), ... 'phpmailer' => array ( 'mailer' => 'smtp', 'smtp.host' => 'email-smtp.<region>.amazonaws.com', 'smtp.port' => 587, 'smtp.secure' => 'tls', 'smtp.autotls' => true, 'smtp.auth' => true, 'smtp.username' => '<smtp-username>', 'smtp.password' => '<smtp-password>', ... ),Then check the file and reload PHP-FPM:
sudo php -l /etc/librebooking/config.php && sudo systemctl reload php8.3-fpmTo let people reset forgotten passwords by e-mail, set 'disable.reset' => false in the 'password' section.
Self-registration stays off on this image whatever allow.self.registration says, because nginx refuses register.php. Add people under Application Management > Users.
The in-browser Application Configuration page is off on purpose. The configuration file is read-only to PHP, so you change every setting in config.php as described above.
Reach an SMTP relay, LDAP directory or SSO provider inside your VPC
LibreBooking runs as the OS user librebooking. A firewall service, librebooking-egress-guard, lets that user reach public internet addresses (such as the public SES endpoint above). It refuses the instance metadata service, link-local and loopback addresses, IPv6 and every address in your VPC's own CIDR blocks. This stops anyone who can type a URL into LibreBooking (an OAuth endpoint, a webhook, a mail host) from using it to probe your private network.
If your SMTP relay, LDAP or Active Directory server, OAuth provider or a VPC interface endpoint is on a private address in this VPC, add it to the allow list, one IPv4 address or CIDR per line, and restart the guard:
sudo nano /etc/sac/librebooking-egress-allow.conf
sudo systemctl restart librebooking-egress-guardEntries may not cover the metadata service, link-local, loopback or multicast ranges. The guard refuses to start if the file contains such a line.
The image ships with the LibreBooking LDAP, Active Directory, SAML, Shibboleth and other sign-in plugins, and its Google, Microsoft, Facebook, Keycloak and generic OAuth2 sign-in options (the 'authentication' section of config.php). All of them are off. The CAS plugin is not on the image.
Your own DNS name and certificate
Point a DNS record at the instance, then set the name that LibreBooking is served as. The command creates a new self-signed certificate for the name and updates nginx, the links LibreBooking puts in its pages and e-mails, and the URL and fingerprint in the credentials file. The name persists across reboots:
sudo librebooking-set-hostname <your-domain>To use a certificate from your own certificate authority instead, copy it over the generated pair and reload nginx. Running librebooking-set-hostname again replaces it with a self-signed certificate:
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/librebooking.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/librebooking.key
sudo nginx -t && sudo systemctl reload nginxChange the administrator password
You can change the password in the web interface under My Account > Change Password.
From the command line, librebooking-set-password generates a new random password, or takes yours on standard input (20 to 72 letters, digits and dashes, with an uppercase letter, a lowercase letter, a digit and a dash). It signs every session out and records the new password in /root/librebooking-credentials.txt. printf is a shell builtin, so the password never appears in the process list. Start the line with a space so that most shells keep it out of your history:
# a new random password
sudo librebooking-set-password
# or your own printf '%s\n' '<new-password>' | sudo librebooking-set-password --stdinLibreBooking 7.2.0 stores account passwords as salted SHA-1 hashes, which is the upstream design. Give every account a long, unique password. To enforce your own password policy, connect LibreBooking to your directory (Step 10).
Data, backups and server components
Check the versions on the image and the database. A new instance has one schema and one administrator account:
grep -o "VERSION = '[0-9.]*'" /var/www/librebooking/lib/Config/Configuration.php php -v | head -1 mysqld --version nginx -v 2>&1
sudo mysql -N -e "SELECT COUNT(*) FROM librebooking.users"
sudo mysql -N -e "SHOW VARIABLES WHERE Variable_name IN ('skip_networking','log_bin')"VERSION = '7.2.0' PHP 8.3.6 (cli) (built: ...) (NTS) /usr/sbin/mysqld Ver 8.0.46-0ubuntu0.24.04.4 for Linux on x86_64 ((Ubuntu)) nginx version: nginx/1.24.0 (Ubuntu) 1 log_bin OFF skip_networking ONTo back up LibreBooking, dump the database and copy the uploaded images, for example to S3, or take an EBS snapshot of the root volume:
sudo mysqldump --single-transaction librebooking | gzip > librebooking-$(date +%F).sql.gz
sudo tar -czf librebooking-uploads-$(date +%F).tar.gz -C /var/lib/librebooking-public imagesTo restore a dump into a new instance from this image, stop PHP-FPM, load it, and start PHP-FPM again:
sudo systemctl stop php8.3-fpm gunzip -c <backup-dir>/librebooking-<date>.sql.gz | sudo mysql librebooking
sudo systemctl start php8.3-fpmThe restored accounts keep their passwords, so you sign in with the administrator from the old instance, not the one in the new credentials file.
Component and path:
LibreBooking code (root owned, read only to PHP) /var/www/librebooking
Configuration /etc/librebooking/config.php (root:librebooking 0640)
Licence, source note and upstream composer.lock /usr/share/doc/librebooking/
Sessions, compiled templates, cache /var/lib/librebooking
Uploaded images (resource pictures, logo) /var/lib/librebooking-public/images
Application log /var/log/librebooking/app.log
Database MySQL 8.0, database and user librebooking, unix socket only
nginx site /etc/nginx/sites-available/sac-librebooking
Certificate and key /etc/nginx/ssl/
VPC allow list for LibreBooking /etc/sac/librebooking-egress-allow.conf
Helpers /usr/local/sbin/librebooking-set-password, librebooking-set-hostname, librebooking-cred-roundtrip
First boot script /usr/local/sbin/librebooking-firstboot.sh
Credentials /root/librebooking-credentials.txt (mode 0600)
Logs you may notice. LibreBooking writes each refused sign-in to /var/log/librebooking/app.log as Failed user authentication for <name>, with the name typed but never the password.
While the administrator is the only account, every sign-in also adds a PHP warning to /var/log/nginx/error.log that file_put_contents(.../config/config.php) was refused. Upstream tries to rewrite its configuration file after the first sign-in, and on this image that file is read-only to PHP, so nothing changes. The warning stops once you add a second account.
Security recommendations
- Allow port 22 in the security group from your own networks only, and ports 443 and 80 only to the people who book resources.
- Check the certificate fingerprint the first time you connect (Step 5), then use your own DNS name and a certificate your clients trust (Step 11).
- Change the administrator's e-mail address (Step 5), keep self-registration off, and add people yourself.
- Allow only the private hosts that LibreBooking needs (Step 10).
- Keep the operating system patched. Unattended security upgrades are on, and
sudo apt-get update && sudo apt-get upgradeapplies everything else.
Support and licensing
LibreBooking is open-source software under the GNU General Public License v3.0, and there is no per-user or per-CPU licence fee. The licence, a note on where the source comes from and the original upstream composer.lock are in /usr/share/doc/librebooking/.
SecureAnyCloud is not affiliated with or endorsed by the LibreBooking project. The AMI price covers the SecureAnyCloud 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 LibreBooking 7.2.0 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