ITFlow 26.11.3 on AWS User Guide
Overview
This guide covers launching and using the ITFlow 26.11.3 on Ubuntu 24.04 AMI from cloudimg on Amazon EC2. It is one version of the cloudimg help desk, IT service and project management listing on AWS Marketplace; you pick it as the software version when you subscribe and launch.
ITFlow is an open source platform for managed service providers and IT teams. One web application keeps each client's documentation (contacts, locations, assets, networks, software and licences, domains, certificates, documents and a credential vault), runs the service desk (tickets, recurring tickets, time tracking and SLAs), handles the money side (quotes, invoices, recurring invoices, payments and expenses) and gives your clients a portal where they raise and follow their own requests.
What the cloudimg image adds:
- No setup wizard and no default login. Upstream ITFlow is set up in a browser wizard that asks for database details and creates the first user. On this image the wizard is never reachable (
/setup/answers 404). First boot runs ITFlow's own setup code once, creates the database, the first company and an administrator with a password unique to your instance, and closes setup. - Nothing baked into the image. The image ships an empty MariaDB data directory, no
config.phpand an empty/var/lib/itflow, so every instance creates its own database, its own installation id, its own backup encryption key and its own vault key on first boot. - No database password at all. ITFlow runs as its own system user,
itflow, and MariaDB accepts that user only over the local socket from processes running asitflow(unix_socketauthentication). MariaDB has no network listener. - HTTPS from the first boot. nginx serves ITFlow on port 443 with a certificate generated on your instance, port 80 redirects to HTTPS, requests for a host name the instance does not serve get no answer, and ITFlow's HTTPS only mode is on, so its session cookies are
SecureandHttpOnly. - Only ITFlow's pages run PHP. nginx runs a PHP file only when the address names a real ITFlow page. The configuration, setup, the cron script, the function and include files, the bundled libraries, the form handler fragments and any trick address (
/login.php/x, doubled or encoded slashes) answer 404. - Read only code. The ITFlow code is owned by root and read only to PHP, and
config.phpis owned by root and only readable by ITFlow, so nothing on the web can change the application or its settings file. - Uploaded files are never run. Files you and your clients upload are served with a sandboxing content security policy and
nosniff, never as PHP, and backups and temporary files are never served at all. - Abuse limits and cross site protection. Sign in requests are rate limited per client address on top of ITFlow's own lockout, ITFlow's form and ajax handlers and sign out refuse requests opened from other sites, and ITFlow sees the real client address and the configured host name, never values a client sends in headers.
- Metadata access blocked. nginx, PHP-FPM, MariaDB, ITFlow's cron and first boot are blocked from the instance metadata service, so a mail server, webhook or integration address pointed at it gets nothing back, and the AMI requires IMDSv2.
- Cron as a service. ITFlow's scheduled jobs (mail, recurring tickets and invoices, reminders, clean up) run every minute from
itflow-cron.serviceas theitflowuser, with no crontab. - Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: ITFlow 26.11.3 (the upstream source of commit e07fbf6d1fef, checksum verified), nginx, PHP 8.3 FPM, MariaDB 10.11, 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) from your admin network, and TCP 443 (ITFlow) and TCP 80 (redirects to HTTPS) from the networks your technicians and clients work from. ITFlow holds your clients' documentation and credentials, so keep 80 and 443 as narrow as you can.
Step 1: Launch the instance
In the AWS Marketplace listing choose Continue to Subscribe, then Continue to Configuration, pick ITFlow 26.11.3 on Ubuntu 24.04 as the software version and your Region, then Launch through EC2. Choose m5.large (or larger for many technicians), your key pair and a security group as above.
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=itflow}]'
First boot builds the database and takes about two minutes after the instance is running.
Step 2: Connect to your instance
| Version | SSH user |
|---|---|
| ITFlow 26.11.3 on Ubuntu 24.04 | ubuntu |
ssh -i <your-key.pem> ubuntu@<public-ip>
Step 3: Check the services
First boot creates the database, sets the password and mints the certificate; nginx and ITFlow's cron start only after it has finished:
systemctl is-active nginx php8.3-fpm mariadb itflow-cron
sudo test -f /var/lib/cloudimg/itflow-firstboot.done && echo FIRSTBOOT_DONE
All four services are active and the first boot marker is present:
active
active
active
active
FIRSTBOOT_DONE
Only SSH and nginx listen on network ports. MariaDB has no network listener at all and PHP-FPM uses a local socket:
sudo ss -lntp | awk 'NR>1 && $4 !~ /^127\.0\.0\.5[34]/ {split($6, p, "\""); print $4, p[2]}' | sort
0.0.0.0:22 sshd
0.0.0.0:443 nginx
0.0.0.0:80 nginx
[::]:22 sshd
[::]:443 nginx
[::]:80 nginx
Step 4: Get your URL and password
sudo cat /root/itflow-credentials.txt
The file is readable by root only:
# ITFlow 26.11.3 - generated on first boot by itflow-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret.
ITFLOW_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/
ITFLOW_ADMIN_EMAIL=admin@localhost.localdomain
ITFLOW_ADMIN_PASSWORD=<ITFLOW_ADMIN_PASSWORD>
#
# Open ITFLOW_URL in a browser (self-signed certificate minted on this instance's first boot; port 80 redirects to
# https) and sign in with the e-mail address and password above; ITFlow's Get started page opens. Then, under your
# name (top right > Account), set your own e-mail address (Profile) and change the password (Security; this re-wraps
# ITFlow's vault key). Backup encryption key: Administration > Maintenance > Backup shows it (also in
# /etc/itflow/config.php) - keep a copy away from
# this server; a backup cannot be restored without it.
# MariaDB: unix socket only (no TCP listener); ITFlow signs in as the OS user itflow (no database password).
# root signs in over the socket: sudo mysql itflow
# Configuration: /etc/itflow/config.php (root-owned, read-only to ITFlow). Files: /var/lib/itflow/uploads
# Cron: systemctl status itflow-cron (runs cron/cron.php every minute as itflow; Administration > Maintenance > Cron)
# Change the name it serves as: sudo itflow-set-hostname <your-dns-name>
# User guide: https://www.cloudimg.co.uk/guides/itflow-26-11-3-on-ubuntu-24-04-aws/
The URL uses the instance's public DNS name from the EC2 instance metadata, and the certificate also names the public and private IP addresses. nginx answers only to the names in the certificate. The name is fixed at first boot, so if you stop and start the instance without an Elastic IP and its public address changes, run sudo itflow-set-hostname with the new name (Step 8), or better, give the instance an Elastic IP or your own DNS name.
Step 5: Sign in and make the account yours
Open the ITFLOW_URL in your browser. The certificate is self signed, so your browser asks you to confirm it the first time (or install your own, Step 8). Sign in with the e-mail address admin@localhost.localdomain and the password from Step 4.

The first time the administrator signs in, ITFlow opens its Get started page: eight steps (Cron, Email, Backups, Billing, Support, Team, Content and First client), each of which you can do now, skip, or leave for later. Cron is already ticked, because the image runs ITFlow's cron for you.

Then open your account (your name at the top right, then Account) and:
- On Profile, change the e-mail address to your own. ITFlow signs you in with it and sends notifications to it.
- On Security, change the password. Do it there, inside ITFlow, rather than in the database: ITFlow encrypts the credential vault with a key wrapped by your password, and changing the password re-wraps that key. ITFlow then signs you out so you sign in again with the new password.
- On Security, turn on multi factor authentication.

Until every Get started step is done or skipped, the dashboard shows a Finish setting up bar to carry on from. Add a separate ITFlow user for each technician (Administration, Users) instead of sharing the administrator account.

Tickets, clients, assets, documentation, invoices and the rest live in the menu on the left.

Step 6: Mail, cron and outbound connections
ITFlow sends ticket and invoice e-mail and can turn incoming e-mail into tickets. Set your SMTP and IMAP servers in the Get started Email step, or in Administration, Mail. Until you do, ITFlow sends no mail.

ITFlow's scheduled jobs run from itflow-cron.service, which runs ITFlow's cron dispatcher every minute as the itflow user. ITFlow shows each job's last run and result under Administration, Maintenance, Cron:
systemctl status itflow-cron --no-pager | head -5
ITFlow connects out only to servers an administrator configures: your mail servers, Stripe if you take card payments, an AI provider if you turn one on, and your identity provider if you set up single sign on. Nothing is contacted on its own. ITFlow's one click updater runs git from inside PHP, and this image does not let PHP start programs; new ITFlow releases arrive as new versions of this listing.
ITFlow keeps an encryption key for the credential vault in a cookie named user_encryption_session_key. ITFlow sets it Secure and HttpOnly with SameSite=None; the session cookie PHPSESSID is Secure, HttpOnly and SameSite=Lax. Cross site requests to ITFlow's form handlers are refused by nginx regardless.
Step 7: Backups and the backup encryption key
ITFlow generates a backup encryption key for your instance on first boot. It protects the backups ITFlow makes from Administration, Maintenance, Backup, and a backup cannot be restored without it. Copy the key from that page into your password manager, away from this server.
Everything you enter is in the MariaDB database itflow (/var/lib/mysql), uploaded files are under /var/lib/itflow/uploads, and the configuration (database name, base URL, installation id and backup key) is /etc/itflow/config.php. All three are on the root volume, so the simplest backup is an EBS snapshot of it. For a consistent copy while ITFlow is running:
sudo mariadb-dump --single-transaction --routines itflow | gzip > <backup-dir>/itflow-$(date +%F).sql.gz
sudo tar -C / -czf <backup-dir>/itflow-files-$(date +%F).tar.gz var/lib/itflow/uploads etc/itflow
The dump holds every password hash and the encrypted vault, so store it as carefully as the instance.
To give ITFlow more room, enlarge the root volume in the EC2 console (Volumes, Modify); Ubuntu grows the file system on the next boot. If you would rather keep ITFlow's data on its own EBS volume, attach a volume, stop ITFlow, copy /var/lib/mysql and /var/lib/itflow onto it, and mount it back over the same paths with bind mounts in /etc/fstab before you start the services again; contact support if you would like help with the move.
Step 8: Your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name ITFlow is served as. This mints a new self signed certificate for the name, points nginx and ITFlow's base URL (used in every e-mailed link) at it, updates the URL in /root/itflow-credentials.txt, and keeps the name across reboots:
sudo itflow-set-hostname <your-domain>
To use a certificate from a public or internal certificate authority instead (for example one issued by Let's Encrypt for <your-domain>), copy it over the generated pair and reload nginx (running itflow-set-hostname again replaces it with a self signed one):
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/itflow.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/itflow.key
sudo nginx -t && sudo systemctl reload nginx
Step 9: Security checks
nginx serves only ITFlow's pages and static files. Setup, the configuration, the cron script, the function files, the bundled libraries and trick addresses answer 404, plain HTTP redirects to HTTPS, and a request for a name the instance does not serve gets no answer at all:
H=$(sudo grep '^ITFLOW_URL=' /root/itflow-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
for p in /login.php /config.php /setup/ /cron/cron.php /functions.php /includes/check_login.php /login.php/x //config.php /libs/vendor/autoload.php /.git/config; 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/"
curl -sk -o /dev/null -w 'unknown host name -> %{http_code}\n' --resolve "other.example:443:127.0.0.1" "https://other.example/" || true
200 /login.php
404 /config.php
404 /setup/
404 /cron/cron.php
404 /functions.php
404 /includes/check_login.php
404 /login.php/x
404 //config.php
404 /libs/vendor/autoload.php
404 /.git/config
http:// -> 301
unknown host name -> 000
Every service runs with the instance metadata service blocked:
for u in nginx php8.3-fpm mariadb itflow-cron; do echo "$u $(systemctl show -p IPAddressDeny --value $u)"; done
nginx 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
php8.3-fpm 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
mariadb 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
itflow-cron 168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32
The code is owned by root, and PHP runs as itflow:
stat -c '%U:%G %a %n' /var/www/itflow /var/www/itflow/login.php /etc/itflow
sudo stat -c '%U:%G %a %n' /etc/itflow/config.php
root:root 755 /var/www/itflow
root:root 644 /var/www/itflow/login.php
root:itflow 750 /etc/itflow
root:itflow 640 /etc/itflow/config.php
Step 10: Maintenance
Operating system security updates install automatically; run sudo apt-get update && sudo apt-get upgrade to apply everything else. nginx, PHP-FPM and MariaDB restart cleanly and ITFlow keeps all of its data. New ITFlow releases arrive as new versions of this listing, and support can help you move your data to one.
| Component | Path |
|---|---|
| ITFlow | /var/www/itflow (owned by root, read only to PHP) |
| Configuration | /etc/itflow/config.php (root:itflow, mode 0640) |
| Database | MariaDB database itflow (/var/lib/mysql) |
| Uploaded files, sessions and backups | /var/lib/itflow |
| nginx site | /etc/nginx/sites-available/cloudimg-itflow |
| Certificate and key | /etc/nginx/ssl/itflow.crt, /etc/nginx/ssl/itflow.key |
| Cron | itflow-cron.service |
| Helper | /usr/local/sbin/itflow-set-hostname |
| Credentials | /root/itflow-credentials.txt (mode 0600) |
| Source and changes | /usr/share/doc/itflow/SOURCE.txt |
Step 11: Security recommendations
- Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your technicians and clients work from.
- Use your own DNS name and a certificate your users' browsers trust (Step 8).
- Change the administrator e-mail address and password as soon as you sign in, turn on multi factor authentication, and give each technician their own user (Step 5).
- Keep a copy of the backup encryption key away from the server (Step 7).
- Keep the operating system patched, and snapshot the root volume regularly.
Support and licensing
ITFlow is open source under the GNU Affero General Public License version 3, by the ITFlow project and its contributors; there is no per user or per client licence fee. The image ships ITFlow exactly as released, with its bundled PHP and JavaScript libraries: /usr/share/doc/itflow/SOURCE.txt names the commit it came from and lists every file the image leaves out or adds, and no source file is modified. The AMI price covers cloudimg's hardening, first boot setup and support.
- Email: support@cloudimg.co.uk
- Website: https://www.cloudimg.co.uk
- Support: 24/7, with a 24 hour response SLA
All product and company names are trademarks or registered trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.