FreeScout on Ubuntu 24.04 on Azure User Guide
Overview
FreeScout is a free, open source, self-hosted help desk and shared mailbox — a lightweight alternative to Zendesk and Help Scout. It turns incoming email into a shared inbox of conversations that your team can assign, reply to and collaborate on with internal notes, saved replies and tags, and it can be extended with modules. The cloudimg image delivers FreeScout fully installed and configured on Ubuntu 24.04 — a Laravel application on PHP 8.3 with OPcache, served by nginx over HTTPS with php-fpm, backed by MariaDB. The database schema is already migrated and the admin account is already created, so you land directly on the sign-in page with nothing to configure. Backed by 24/7 cloudimg support.
FreeScout is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), and the complete, unmodified upstream source is shipped on the image under /var/www/freescout. cloudimg is not affiliated with, endorsed by, or sponsored by the FreeScout project; "FreeScout" is a trademark of its respective owner. This image repackages the upstream open source release with cloudimg's provisioning and support.
What is included:
- FreeScout 1.8.230 (AGPL-3.0), served from
/var/www/freescout/public - nginx (TLS on :443, with :80 redirected to HTTPS and a plain
/healthzliveness endpoint) + PHP 8.3 (php8.3-fpm with OPcache, including theimapextension for mailbox fetching) + MariaDB, all from Ubuntu 24.04 main/universe - A per-VM self-signed TLS certificate generated on first boot, so the interface loads over a secure context
- Per-VM administrator password, MariaDB password and Laravel
APP_KEY, all generated at first boot and written to a root-only file — no default or shared login ships in the image - The Laravel scheduler running every minute via a systemd timer (required for background jobs and email fetching)
nginx.service,php8.3-fpm.serviceandmariadb.serviceas systemd units, enabled and active- 24/7 cloudimg support

Prerequisites
An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a good starting point; scale up for larger teams or heavier mail volume. NSG inbound: allow 22/tcp from your management network and 443/tcp (HTTPS) plus 80/tcp (which redirects to HTTPS) from your users.
Step 1 — Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for FreeScout by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTPS (443). Then Review + create and Create.
Step 2 — Deploy from the Azure CLI
az vm create \
--resource-group <your-rg> \
--name freescout \
--image <marketplace-image-urn> \
--size Standard_B2s \
--admin-username azureuser \
--generate-ssh-keys \
--public-ip-sku Standard
Open HTTPS (and HTTP, which redirects) to reach the web interface:
az vm open-port --resource-group <your-rg> --name freescout --port 443 --priority 900
az vm open-port --resource-group <your-rg> --name freescout --port 80 --priority 910
Step 3 — Connect to your VM
ssh azureuser@<vm-public-ip>
Step 4 — Confirm the services are running
The three services that back FreeScout should all report active. The plain HTTP port answers a lightweight /healthz liveness check and redirects everything else to HTTPS, and the interface answers over TLS:
systemctl is-active nginx php8.3-fpm mariadb
curl -s -o /dev/null -w 'healthz -> %{http_code}\n' http://127.0.0.1/healthz
curl -s -o /dev/null -w 'http redirect -> %{http_code}\n' http://127.0.0.1/
curl -ks -o /dev/null -w 'https app -> %{http_code}\n' https://127.0.0.1/login
Expected: three lines of active, then healthz -> 200, http redirect -> 301 and https app -> 200 (the FreeScout sign-in page over TLS).

Step 5 — Retrieve your administrator password
On the first boot of every VM, a one-shot service (freescout-firstboot.service) generates credentials that are unique to that VM: a fresh Laravel application key, a fresh MariaDB password, and a fresh administrator password. It also generates a per-VM self-signed TLS certificate and sets the VM's own address as the application URL. No shared or default credentials ship in the image.
sudo cat /root/freescout-credentials.txt
The file (mode 0600, root only) contains the administrator email (freescout.admin.user, which is admin@cloudimg.local), the administrator password (freescout.admin.pass), the sign-in URL, and the database credentials. FreeScout signs in by email address. Change the admin email to your own from Manage → Users after signing in.

You can prove the login round-trip from the VM's own shell — this reads the per-VM credentials, fetches a CSRF token and posts a real sign-in (a successful FreeScout login answers HTTP 302 away from the login page), and confirms a wrong password is rejected back to the login page:
USER=$(sudo grep '^freescout.admin.user=' /root/freescout-credentials.txt | cut -d= -f2-)
PASS=$(sudo grep '^freescout.admin.pass=' /root/freescout-credentials.txt | cut -d= -f2-)
CJ=$(mktemp)
TOK=$(curl -ks -c "$CJ" https://127.0.0.1/login | grep -oE 'name="_token" value="[^"]+"' | head -1 | sed 's/.*value="//;s/"//')
curl -ks -o /dev/null -w 'good login -> %{redirect_url}\n' -b "$CJ" -c "$CJ" \
-d "_token=$TOK" --data-urlencode "email=$USER" --data-urlencode "password=$PASS" https://127.0.0.1/login
BAD=$(mktemp)
BTOK=$(curl -ks -c "$BAD" https://127.0.0.1/login | grep -oE 'name="_token" value="[^"]+"' | head -1 | sed 's/.*value="//;s/"//')
curl -ks -o /dev/null -w 'wrong pass -> %{redirect_url}\n' -b "$BAD" -c "$BAD" \
-d "_token=$BTOK" --data-urlencode "email=$USER" --data-urlencode "password=wrong-99" https://127.0.0.1/login
rm -f "$CJ" "$BAD"
Expected: good login -> https://127.0.0.1/home (signed in) and wrong pass -> https://127.0.0.1/login (bounced back, rejected).
Step 6 — Sign in
Browse to https://<vm-public-ip>/ and sign in with the email admin@cloudimg.local and the password from the credentials file. Because the image ships a per-VM self-signed certificate, your browser shows a one-time certificate warning on first visit — click through it, or install your own domain certificate into /etc/nginx/ssl/freescout.crt and /etc/nginx/ssl/freescout.key.
After signing in you land on the FreeScout dashboard, which lists your mailboxes and the conversations waiting in them.

Step 7 — Create a mailbox and work conversations
A mailbox is a shared inbox your whole team works from. Choose Manage → Mailboxes → Create Mailbox (or open the pre-created Support mailbox that ships with the image), give it a name and the email address that will receive customer mail, then add the Connection Settings (IMAP to fetch incoming mail and SMTP to send replies) for your mail provider.

Inside a mailbox, every email becomes a conversation you can assign to an agent, reply to, tag, add private internal notes to, or resolve. Use New Conversation to start one yourself — pick the customer, add a subject and body, and send. This is the core FreeScout workflow: a shared, collaborative inbox where nothing falls through the cracks.

Step 8 — Confirm the version and the stack
grep "'version'" /var/www/freescout/config/app.php | head -1
php -v | head -1
df -h /
Expected: 'version' => '1.8.230', PHP 8.3, and the OS disk that holds the application tree (/var/www/freescout) and the MariaDB datadir (/var/lib/mysql). Resize the OS disk from the Azure portal if you need more room for attachments or the database.

First-boot service and security model
A one-shot freescout-firstboot.service runs After=mariadb.service and Before=nginx.service, so the per-VM credentials and TLS certificate are in place before the first page is ever served. It rotates the MariaDB password (editing .env in lock-step so the application never loses its database connection), regenerates the Laravel APP_KEY, sets a per-VM administrator password, writes the credentials file at mode 0600 (root only) and drops a sentinel so it runs exactly once.
systemctl status freescout-firstboot.service --no-pager | head -6
sudo stat -c '%a %U:%G %n' /root/freescout-credentials.txt

Administration from the CLI
Admin tasks use Laravel's artisan as the www-data user. For example, list the available commands or fetch new mail on demand:
sudo -u www-data php /var/www/freescout/artisan list | grep freescout
sudo -u www-data php /var/www/freescout/artisan freescout:clear-cache
The Laravel scheduler (background jobs such as fetching new email and sending notifications) runs every minute through the freescout-scheduler.timer systemd timer — no crontab entry to add.
Serving FreeScout on your own domain
FreeScout protects against host-header attacks: it only answers requests whose host matches APP_URL or is listed in APP_TRUSTED_HOSTS. The image pre-trusts the loopback address and the VM's own IP addresses. To serve FreeScout on your own domain, point a DNS record at the VM, then set both values in /var/www/freescout/.env and clear the cache:
APP_URL=https://help.example.com
APP_TRUSTED_HOSTS=127.0.0.1,localhost,help.example.com
sudo -u www-data php /var/www/freescout/artisan freescout:clear-cache
For a browser-trusted certificate, install one from your CA (for example Let's Encrypt) over the shipped self-signed pair:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d help.example.com
Backup and maintenance
FreeScout's data lives in the MariaDB database and the uploaded files under /var/www/freescout/storage. Back the database up with mariadb-dump, and snapshot the OS disk from the Azure portal for a full point-in-time copy:
sudo mariadb-dump --single-transaction freescout | gzip > /var/backups/freescout-$(date +%F).sql.gz
Keep the OS current with sudo apt-get update && sudo apt-get upgrade; the image ships with unattended security updates enabled. Review FreeScout's own update notes before moving between versions.
Support
This image is backed by 24/7 cloudimg support for deployment, upgrades, mailbox and IMAP/SMTP configuration, module installation, LDAP and SAML single sign-on, performance tuning and database administration. Email support@cloudimg.co.uk or use the live chat in the support portal; critical issues receive a one-hour average response.