FreeScout on AWS User Guide
Overview
This image runs FreeScout 1.8.231, a free open source self-hosted help desk and shared inbox, installed from the project's official release tag. FreeScout turns inbound email into a shared mailbox of conversations that your team assigns, tags, replies to and closes, with internal notes that customers never see and a full history per contact. It is a Laravel PHP application, and this image serves it behind nginx with php-fpm 8.3 and OPcache, backed by MariaDB on the same instance bound to the loopback interface only. The imap, mysql, mbstring, gd, intl, bcmath and zip PHP extensions FreeScout needs are installed, all from the operating system archive with no third party package repository added.
FreeScout's web install wizard has already been completed at build time — the schema is migrated and an administrator account exists — so the first request lands directly on the sign-in page. FreeScout skips the wizard whenever the application's .env file is present, which it is in this image.
No credential is baked into the image. On the first boot of every deployed instance a one-shot service mints, uniquely for that instance: the administrator password, the MariaDB application password, the MariaDB maintenance credential in /etc/mysql/debian.cnf, the Laravel APP_KEY that signs sessions and encrypts stored data, and the TLS certificate. Two instances launched from the same Amazon Machine Image never share any secret. The administrator sign-in details are written to /root/freescout-credentials.txt with mode 0600, readable only by root.
The instance serves FreeScout over HTTPS on port 443 with that per-instance self signed certificate, so the application runs in a secure browser context from the first request. Port 80 answers a plain HTTP liveness check at /healthz and 301-redirects everything else to port 443. Because the certificate is self signed your browser will warn you on the first visit, until you replace it with a certificate for your own domain (see the Let's Encrypt step below).
No mail transfer agent is installed. FreeScout receives mail by fetching from an IMAP mailbox you connect and sends through an outbound SMTP server you nominate — this image is not, and cannot act as, a mail server of its own. See the two mail steps below for what that means in practice on EC2.
The FreeScout code tree and Laravel storage (conversation attachments, uploads, sessions and logs) live under /var/www on a dedicated EBS volume, and the MariaDB data directory sits on its own EBS volume at /var/lib/mysql. Both are separate from the operating system disk and each can be resized independently.
Prerequisites
Before you deploy this image you need:
- An Amazon Web Services account where you can launch EC2 instances
- IAM permissions to launch instances, create security groups, and subscribe to AWS Marketplace products
- An EC2 key pair in the target Region for SSH access to the instance
- A VPC and subnet in the target Region, with a security group allowing inbound port 22 from your management network and inbound port 443 from the networks your agents will reach FreeScout on
- The AWS CLI (version 2) installed locally if you plan to deploy from the command line
- An IMAP mailbox for the support address you want to receive on, and an authenticated SMTP relay (for example Amazon SES) to send from
Step 1: Launch the Instance from the AWS Marketplace
Sign in to the AWS Management Console, open the EC2 service, and select Launch instance. Under Application and OS Images choose AWS Marketplace AMIs and search for FreeScout. Select the cloudimg listing and choose Select, then Continue on the subscription summary.
Pick an instance type of m5.large or larger — the workload is PHP and MariaDB, and search and attachment handling benefit from memory. Choose your EC2 key pair under Key pair (login). Under Network settings select your VPC and subnet, and either create or select a security group that allows inbound port 22 from your management network and inbound port 443 from the networks your agents use. Leave the root volume at the default size or larger.
Select Launch instance. First boot initialisation takes a few seconds once the instance state becomes Running and the status checks pass.
Step 2: Launch the Instance from the AWS CLI
The following block launches an instance from the cloudimg FreeScout Marketplace AMI into an existing subnet and security group. Replace <ami-id> with the AMI ID shown on the Marketplace listing, <key-name> with your EC2 key pair name, <subnet-id> with your subnet ID, and <security-group-id> with a security group that opens ports 22 and 443 as described above.
aws ec2 run-instances \
--image-id <ami-id> \
--instance-type m5.large \
--key-name <key-name> \
--subnet-id <subnet-id> \
--security-group-ids <security-group-id> \
--block-device-mappings '[{"DeviceName":"/dev/sda1","Ebs":{"VolumeSize":30,"VolumeType":"gp3"}}]' \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=freescout-01}]'
The command prints a JSON document on success. Note the instance ID, then retrieve its public address once it is running with aws ec2 describe-instances --instance-ids <instance-id> --query "Reservations[].Instances[].PublicIpAddress" --output text.
Step 3: Connecting to your instance
Connect over SSH with the key pair you selected and the public IP address from step 2. The SSH login user depends on the operating system of the AMI variant you launched:
| AMI variant | SSH login user | Connect with |
|---|---|---|
| FreeScout on Ubuntu 24.04 | ubuntu |
ssh -i <path-to-key.pem> ubuntu@<public-ip> |
Substitute your own key path and the instance's public IP address.
Step 4: Retrieve the Per Instance Administrator Credentials
The administrator sign-in details, the database credentials and the instance URL are written to a root only file on first boot. List the entries it holds:
sudo grep -oE '^[a-z.]+=' /root/freescout-credentials.txt
Read the values with sudo cat /root/freescout-credentials.txt. That file contains live secrets, so treat it as sensitive: copy the administrator email and password into your password manager, and do not paste its contents anywhere shared. Confirm it is readable only by root:
sudo stat -c '%n mode %a owner %U' /root/freescout-credentials.txt
Step 5: Verify the Stack is Running
FreeScout is served by three systemd units. Confirm they are active:
systemctl is-active nginx php8.3-fpm mariadb
Each line returns active. Port 80 answers a plain HTTP liveness check that touches neither the application nor the database, which makes it a good target for a load balancer health check:
curl -s -m 15 -o /dev/null -w 'healthz HTTP %{http_code}\n' http://127.0.0.1/healthz
Confirm FreeScout itself answers on HTTPS (the -k flag accepts the per-instance self signed certificate):
curl -sk -m 15 -o /dev/null -w 'sign-in page HTTP %{http_code}\n' https://127.0.0.1/login
Confirm the shipped FreeScout release:
sed -n "s/.*'version'[[:space:]]*=>[[:space:]]*'\([0-9][^']*\)'.*/FreeScout \1/p" /var/www/freescout/config/app.php | sed -n '1p'
The Laravel scheduler, which runs FreeScout's background jobs and polls your mailboxes for new mail, runs every minute through a systemd timer:
systemctl is-active freescout-scheduler.timer
Step 6: Confirm the Network Surface
Only ports 22, 80 and 443 are reachable from outside. MariaDB is bound to the loopback interface, and no mail service listens at all:
ss -tlnH | awk '{print $4}' | sort -u
The database appears as 127.0.0.1:3306 and never on a routable address. No mail transfer agent is installed on this image, which is why nothing listens on ports 25, 465, 587, 143 or 993:
for p in postfix exim4 sendmail dovecot-core opensmtpd; do
dpkg-query -W -f='${Package} ${Status}\n' "$p" 2>/dev/null || echo "$p: not installed"
done
Step 7: First Sign In
Browse to https://<public-ip>/. Because the image ships a self signed certificate, your browser warns you on the first visit — accept the warning to proceed (you replace the certificate in step 13). You land on the FreeScout sign-in page.

Sign in with the administrator email address and password from /root/freescout-credentials.txt. FreeScout signs in by email address, not by username. After signing in you land on the FreeScout dashboard, which prompts you to create your first mailbox.
Step 8: Change the Administrator Email and Password
The first-boot password is unique to your instance, but you should still set your own. Open the user menu at the top right and choose Your Profile. Set your real name and change the email address to your own — that address becomes your sign-in identity and where your notifications go. Then use Password in the same area to set a password you control. FreeScout stores agent passwords as bcrypt hashes.
Step 9: Create Your First Mailbox
A mailbox in FreeScout is a support address plus the conversations that arrive at it. Open Manage → Mailboxes → New Mailbox, enter the support address customers will email (for example support@example.com) and a display name, choose which agents may use it, and save. FreeScout creates the Unassigned, Mine, Starred, Assigned, Closed and Spam folders for it.
The mailbox settings page controls the reply behaviour for that address — the outbound display name, the status a conversation moves to after you reply, the default assignee, and the email signature appended to replies:

Step 10: Receiving Mail — Connect an IMAP Mailbox
FreeScout does not run a mail server. It fetches mail from a mailbox you already have, which is what turns inbound email into conversations. Open Manage → Mailboxes → your mailbox → Connection Settings → Fetching Emails (the page shown above), then:
- Set Protocol to
IMAPand enter the Server, Port and Encryption your provider documents (commonly993with SSL, or143with StartTLS). - Enter the mailbox Username and Password. For Google Workspace or Microsoft 365 use an app password or OAuth as your provider requires — both are linked from that page.
- Leave IMAP Folders as
INBOXunless you sort inbound mail into another folder. - Save the settings, then use Check Connection to confirm FreeScout can log in.
The php8.3-imap extension this image ships is what makes fetching work, and the scheduler timer already running on the instance polls the mailbox every minute. New mail then appears in the mailbox's Unassigned folder.
Step 11: Sending Mail — Use Amazon SES or Another Authenticated Relay
Read this before you rely on outbound replies. A new EC2 instance cannot send email directly. AWS throttles outbound port 25 on new accounts and instances by default, and a fresh instance has no reverse DNS record and no sending reputation, so mail it emits directly is very likely to be rejected or filed as spam. This image therefore ships no mail transfer agent and makes no attempt to deliver mail itself.
Configure an authenticated relay instead. Open Manage → Mailboxes → your mailbox → Connection Settings → Sending Emails:

Choose SMTP as the method, then enter the host, port (587 with StartTLS, or 465 with SSL), username and password of your relay. Amazon SES is the natural choice on AWS: verify your sending domain in SES, create SMTP credentials, and enter the regional SES SMTP endpoint here. Any authenticated provider works equally well. Note that the PHP mail() and Sendmail methods offered on that page require a local mail transfer agent, which this image deliberately does not install — leave them unselected. Save the settings and use Send Test to confirm delivery before you go live.
Step 12: Work a Conversation
The mailbox view is the shared inbox: each row is a conversation, showing the customer, the subject and preview, the conversation number and how long it has been waiting. The folder list on the left separates what nobody has picked up (Unassigned) from what is yours (Mine), starred, assigned, closed and spam.

Open a conversation to work it. You get the customer's message thread, the assignee and status controls at the top, and the customer's profile on the right:

Use Reply to answer the customer, Note for a comment only your team sees, the person control to assign it to an agent, and the status control to move it between Active, Pending and Closed. Saved replies, tags and custom folders are all available from the same view once you configure them.
Step 13: Add Agents
Add the rest of your team under Manage → Users → New User. Give each person their own account with the User role for agents or Admin for administrators, then grant them access to the mailboxes they should see from the mailbox's Permissions page. Each agent signs in with their own email address and password.

The Manage → Settings area sets the instance-wide behaviour: company name, conversation numbering, which actions non-admin users may perform, default language, timezone, and what customers see in outbound email.
Step 14: Point FreeScout at Your Own Domain
FreeScout builds links and assets from APP_URL, and its trusted-hosts protection rejects any request whose Host header it does not recognise. On first boot both are set to the instance's own address, so browsing by IP works out of the box. To serve FreeScout on your own name instead, point a DNS record at the instance, then edit /var/www/freescout/.env as root: set APP_URL to https://support.your-domain.com and add that hostname to the comma separated APP_TRUSTED_HOSTS list. Apply the change with sudo -u www-data php /var/www/freescout/artisan freescout:clear-cache. Skipping the trusted-hosts entry is the usual cause of a 403 Untrusted Host response after a domain change.
Step 15: Replace the Self Signed Certificate with Let's Encrypt
The image serves HTTPS with a per-instance self signed certificate so traffic is encrypted out of the box. For production, replace it with a trusted certificate for your own domain. Complete step 14 first so DNS resolves to the instance. The commands below are illustrative — they involve a domain you own and interactive prompts, so run them yourself and substitute your own hostname.
Install Certbot and the nginx plugin, then request a certificate. Certbot edits the nginx site in place and reloads nginx:
sudo apt-get update && sudo apt-get install -y certbot python3-certbot-nginx
sudo certbot --nginx -d support.your-domain.com
Certbot installs a renewal timer, so the certificate renews automatically. If you would rather keep the shipped nginx site as it is, drop your own certificate and key at /etc/nginx/ssl/freescout.crt and /etc/nginx/ssl/freescout.key (key mode 0600) and reload nginx.
Step 16: Storage Layout
The application and database tiers are on dedicated EBS volumes, each independently resizable:
df -h /var/lib/mysql /var/www
/var/lib/mysql holds the MariaDB data directory and /var/www holds the FreeScout code tree, Laravel storage and conversation attachments. Both are recorded in /etc/fstab by filesystem UUID, so the layout reproduces on every instance launched from this image:
grep -E ' /var/(www|lib/mysql) ' /etc/fstab
To grow a tier, modify the EBS volume in the EC2 console and then extend the filesystem with sudo resize2fs <device>.
Step 17: Backups and Maintenance
Back up both tiers: the FreeScout database in MariaDB and the application storage tree that holds conversation attachments. A consistent database dump, taken as root over the local socket:
sudo mysqldump --single-transaction --quick freescout | gzip > /tmp/freescout-db-$(date +%F).sql.gz && ls -la /tmp/freescout-db-*.sql.gz
Take EBS snapshots of both data volumes for point-in-time recovery, and snapshot before any FreeScout version upgrade. Keep the operating system patched with sudo apt-get update && sudo apt-get -y upgrade.
FreeScout writes its application log inside the storage tree, which is the first place to look if a background job or a mailbox fetch misbehaves:
sudo ls -1 /var/www/freescout/storage/logs/ 2>/dev/null; echo '(FreeScout log directory listed)'
Licensing
FreeScout core is licensed under the GNU Affero General Public License v3.0, and the complete corresponding source is shipped unmodified on the instance under /var/www/freescout with the licence text at /var/www/freescout/LICENSE:
sed -n '1,3p' /var/www/freescout/LICENSE
Only FreeScout core is installed. The project's paid modules are separate commercial products, are not bundled with this image, and are not covered by the cloudimg support subscription — buy and install them from the FreeScout project directly if you want them.
cloudimg is not affiliated with, endorsed by, or sponsored by the FreeScout project. All product and company names are trademarks or registered trademarks of their respective holders.
Support
This image is backed by 24/7 technical support from cloudimg, covering deployment, upgrades, TLS certificates, mailbox and SMTP configuration, workflows and saved replies, modules, and database administration. Contact support through the channel listed on the AWS Marketplace listing.