FreeScout 1.8.250
Overview
FreeScout is an open source help desk and shared inbox, a self-hosted alternative to Help Scout and Zendesk. Email sent to your support addresses becomes conversations in shared mailboxes. Agents assign, reply to and close those conversations, with saved replies, notes, tags, customer profiles, per-mailbox permissions and notifications.
This guide covers launching and using the FreeScout 1.8.250 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. It is one version of the SecureAnyCloud help desk, IT service and project management listing on AWS Marketplace. You pick it as the software version when you subscribe and launch.
What you get:
- No web installer and no default login. Upstream FreeScout is set up in a browser installer that creates the first administrator. This image does not ship the installer, and
/installanswers 404. First boot creates the database and one administrator,admin@sac.local, with a password unique to your instance. There are no other users. - Nothing baked into the image. The image ships an empty MariaDB data directory and no FreeScout settings file, so every instance creates its own database and its own Laravel application key (
APP_KEY, which signs cookies, attachment links and notification replies) on first boot. - No database password at all. FreeScout runs as its own system user,
freescout, and MariaDB accepts that user only over the local socket from processes running asfreescout(unix_socketauthentication). MariaDB has no network listener. - HTTPS from the first boot. nginx serves FreeScout 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 get no answer. The session cookie is
Secure,HttpOnlyandSameSite=Lax. - Only FreeScout's front controller runs PHP. Every request goes to FreeScout's router, and no other PHP file can be reached. Any path that starts with
/index.phpis refused, so no request can reach a page around the limits below. The settings file, logs, caches, sources and the web cron URL answer 404. - Read-only code and safe uploads. The FreeScout code is owned by root and read-only to PHP. nginx serves uploaded avatars and editor images as static files with a sandboxing content security policy, and never runs them as PHP. FreeScout alone sends attachments, through signed links.
- Abuse limits and cross-site protection. Sign-in, password reset and invitation requests are rate limited per client address. The links that change data with a plain GET (undo a reply, clone a ticket, disconnect a mailbox) refuse requests opened from other sites. FreeScout sees the real client address and the configured host name, never values a client sends in headers.
- Metadata access blocked. nginx, PHP-FPM, MariaDB, first boot and the FreeScout scheduler (with the mail fetch and queue workers it starts) are blocked from the instance metadata service. A mail server, webhook or image address pointed at it gets nothing back, and the AMI requires IMDSv2.
- Background work from a service. FreeScout's scheduler fetches mail, sends replies and notifications, and runs the queue. It runs every minute from
freescout-scheduler.serviceas thefreescoutuser. There is no crontab and no web cron. - Fully patched Ubuntu. Ubuntu 24.04 LTS was fully patched at build time, with unattended security upgrades switched on.
- What is on the image. FreeScout 1.8.250 is the official release from GitHub, checksum verified, with its bundled PHP libraries and no modules. The image also carries 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 (FreeScout) and TCP 80 (redirects to HTTPS) from the networks your agents work from. FreeScout holds your customers' email, so keep ports 80 and 443 as narrow as you can.
- A mailbox at your email provider for each support address (IMAP or POP3 to fetch, SMTP to send). FreeScout fetches mail. It does not receive mail on port 25.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick FreeScout 1.8.250 on Ubuntu 24.04 as the software version, pick your Region, and choose Launch through EC2.
Choose m5.large (or larger for many agents or a busy mailbox), your key pair and a security group as above.
Alternatively, launch 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=freescout}]'First boot builds the database and takes about two minutes after the instance is running.
Connect to your instance
Connect over SSH. On FreeScout 1.8.250 on Ubuntu 24.04, the SSH user is ubuntu:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot creates the database, the settings file and the administrator, and mints the certificate. nginx and the scheduler start only after first boot has finished:
systemctl is-active nginx php8.3-fpm mariadb freescout-scheduler freescout-firstboot
sudo test -f /var/lib/sac/data/freescout-firstboot.done && echo FIRSTBOOT_DONEAll five units are active and the first boot marker is present:
active active active active active FIRSTBOOT_DONEOnly SSH and nginx listen on network ports. MariaDB has no network listener, 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]}' | sort0.0.0.0:22 sshd 0.0.0.0:443 nginx 0.0.0.0:80 nginx [::]:22 sshd [::]:443 nginx [::]:80 nginxGet your URL and password
sudo cat /root/freescout-credentials.txtThe file is readable by root only:
# FreeScout 1.8.250 - generated on first boot by freescout-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. FREESCOUT_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ FREESCOUT_ADMIN_EMAIL=admin@sac.local FREESCOUT_ADMIN_PASSWORD=<FREESCOUT_ADMIN_PASSWORD>
#
# Open FREESCOUT_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 and password above. Then set your own e-mail in Your Profile and add a mailbox. # MariaDB: unix socket only (no TCP listener, no database password: FreeScout runs as the OS user freescout); # sudo mysql freescout (root signs in over the socket) # Settings: /etc/freescout/freescout.env (owned by freescout; then:
sudo freescout-artisan freescout:clear-cache)
# Artisan:
sudo freescout-artisan <command> Scheduler: systemctl status freescout-scheduler
# Change the password:
sudo freescout-set-password
# Change the name it serves as:
sudo freescout-set-hostname <your-dns-name>
# User guide: https://secureanycloud.com/stacks/freescout-1-8-250/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. If you stop and start the instance without an Elastic IP and its public address changes, run sudo freescout-set-hostname with the new name (Step 9). A better option is to give the instance an Elastic IP or your own DNS name.
To check sign-in end to end from the instance itself, run the following. It covers the HTTPS redirect, refused paths, the administrator password through the real sign-in form, and a wrong password being refused:
sudo freescout-cred-roundtripOK https 301 + no installer/tools/web cron/.env/sources + administrator sign-in + wrong password refusedSign in
Open the FREESCOUT_URL in your browser. The certificate is self-signed, so your browser asks you to confirm it the first time. Alternatively, install your own certificate (Step 9). Sign in with the email address admin@sac.local and the password from Step 4:
A new FreeScout has no mailboxes, so the dashboard offers Manage Mailboxes. Once you add a mailbox (Step 6), the dashboard shows a card for each one. The card lists its open conversations, or a reminder to configure its connection settings:
Make the account yours. Open the user menu (top right), choose Your Profile, and set your name and your own email address. FreeScout signs in by email address and sends password resets there.
Then update FREESCOUT_ADMIN_EMAIL in /root/freescout-credentials.txt to match, because freescout-set-password looks the administrator up by that address. To choose your own password, use Change your password on the profile page. Then delete FREESCOUT_ADMIN_PASSWORD from the credentials file so it does not hold an old password.
If you lose the administrator password, set a new one from the instance. Without an option, the command generates a random password and writes it to the credentials file. With --stdin, it reads the password you type (24 to 72 letters and digits). Either way, it clears the remember-me token and signs every session out:
sudo freescout-set-password
sudo freescout-set-password --stdinMailboxes and conversations
Create a mailbox. Choose Manage, Mailboxes, New Mailbox, enter the support address customers write to and a name, and choose which users work in it:
Connect it to your mail provider. Open the mailbox's Connection Settings. Under Fetching Emails, enter the IMAP (or POP3) server, port, user name and password of the support address. Keep Validate Certificate on. Select Save Settings, then Check Connection.
Under Sending Emails, choose SMTP and enter your SMTP server. Amazon SES works as the relay (port 587 with STARTTLS). The image has no local mail server, so PHP's mail() function and Sendmail cannot send:
Work the queue. New mail arrives as conversations in Unassigned. Assign a conversation to an agent, reply, add a private note, tag it and close it. Mine, Assigned and Closed follow its progress, and the envelope button starts a new conversation yourself:
Users. Add each agent under Manage, Users, New User, as a User (works in the mailboxes you grant) or an Administrator. FreeScout emails each new user an invitation link to set their password, so set up the system email below first.
Mail settings and the scheduler
System email. Invitations and alerts to administrators use the system email settings under Manage, Settings, Mail Settings. Set Mail From to an address at your domain. Set Send Method to SMTP with the same server as your mailboxes. The default, PHP's mail() function, has no mail server to use on this image. Fetching Interval sets how often every mailbox is checked:
The scheduler and its workers. freescout-scheduler.service runs FreeScout's schedule:run once a minute as the freescout user. It fetches mail and starts the queue worker that sends replies and notifications. Every one of those processes stays inside the service, under the same metadata block:
systemctl show freescout-scheduler -p User -p IPAddressDeny for p in $(pgrep -f '[a]rtisan queue:work'); do echo "$(ps -o user= -p "$p") $(cut -d: -f3 "/proc/$p/cgroup")"; doneIPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 User=freescout freescout /system.slice/freescout-scheduler.serviceThe FreeScout console. FreeScout's artisan command line runs as the freescout user in a short-lived systemd unit with the same metadata block as the services. Use it for maintenance such as clearing the cache after you edit the settings file:
sudo freescout-artisan freescout:clear-cache grep -F "'version'" /var/www/freescout/config/app.php | head -1The System Status page. Manage, System, Status shows the version, PHP and the background jobs. Two of its permission checks are expected to show a warning on this image: Modules/ is "Not writable" and public/storage (symlink) is "Not found". Both are deliberate, because the code is read-only to PHP and nginx serves uploads itself.
Do not run the chown command the page suggests, because it would let PHP change its own code. For the same reason, the Modules page is not available. The web cron URL the page shows answers 404, because the scheduler service does that work.
What the server contacts. FreeScout connects only to the mail servers and other services an administrator configures. None of the services can reach the instance metadata service (Step 10). To limit these connections further, restrict the instance's outbound traffic to your mail servers with its security group or a network ACL.
Settings that stay off
FreeScout's settings file is /etc/freescout/freescout.env, owned by freescout with mode 0600. Debug output is off, and sessions are files on the instance. The session cookie is Secure and SameSite=Lax, no proxy is trusted for client addresses, and there is no database password:
sudo grep -E '^(APP_DEBUG|APP_TRUSTED_PROXIES|SESSION_DRIVER|SESSION_SECURE_COOKIE|SESSION_SAME_SITE|DB_PASSWORD)=' /etc/freescout/freescout.envAPP_DEBUG=false APP_TRUSTED_PROXIES= SESSION_DRIVER=file SESSION_SECURE_COOKIE=true SESSION_SAME_SITE=lax DB_PASSWORD=If you put a load balancer in front of the instance, set APP_TRUSTED_PROXIES to its addresses only, then run sudo freescout-artisan freescout:clear-cache.
Your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name FreeScout is served as. The command mints a new self-signed certificate for the name and points nginx and FreeScout's APP_URL at it. It also updates the URL in /root/freescout-credentials.txt and keeps the name across reboots:
sudo freescout-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 freescout-set-hostname again replaces it with a self-signed certificate:
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/freescout.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/freescout.key
sudo nginx -t && sudo systemctl reload nginxFreeScout sends its own Strict-Transport-Security header. Browsers ignore it over the self-signed certificate and honor it once your users' browsers trust the certificate.
Security checks
nginx serves only the application. The installer, any path under /index.php, the settings file, logs, a PHP file under the uploads, the web cron, the Modules page and the vendored sources 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 '^FREESCOUT_URL=' /root/freescout-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#') for p in / /login /index.php /index.php/login /install /.env /storage/logs/laravel.log /storage/x.php /system/cron/x /modules/list /vendor/autoload.php; 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/" || true302 / 200 /login 404 /index.php 404 /index.php/login 404 /install 404 /.env 404 /storage/logs/laravel.log 404 /storage/x.php 404 /system/cron/x 404 /modules/list 404 /vendor/autoload.php http:// -> 301 unknown host name -> 000The links that change data with a plain GET are refused when the request comes from another site, so a link or image on another page cannot undo a reply, clone a ticket or disconnect a mailbox on your agents' behalf:
H=$(sudo grep '^FREESCOUT_URL=' /root/freescout-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#')
curl -sk -o /dev/null -w 'cross-site undo reply -> %{http_code}\n' -H 'Sec-Fetch-Site: cross-site' --resolve "$H:443:127.0.0.1" "https://$H/conversation/undo-reply/1/1"cross-site undo reply -> 403FreeScout's database account has no password. MariaDB accepts it only over the local socket from processes running as freescout, and MariaDB does not listen on the network:
sudo mysql -N -B -e "SELECT CONCAT(User, '@', Host, ' authenticates by ', JSON_VALUE(Priv, '$.plugin'), ', password set: ', IF(IFNULL(JSON_VALUE(Priv, '$.authentication_string'), '') = '', 'no', 'yes')) FROM mysql.global_priv WHERE User = 'freescout'; SELECT CONCAT('skip_networking: ', @@skip_networking);"freescout@localhost authenticates by unix_socket, password set: no skip_networking: ONThe certificate was generated on this instance and names its own addresses:
H=$(sudo grep '^FREESCOUT_URL=' /root/freescout-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 = ec2-<public-ip-dashed>.compute-1.amazonaws.com, O = sac X509v3 Subject Alternative Name: DNS:ec2-<public-ip-dashed>.compute-1.amazonaws.com, IP Address:<public-ip>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhostNone of the services can reach the instance metadata service, so a mail server, webhook or image address pointed at it gets nothing back:
systemctl show nginx php8.3-fpm mariadb freescout-scheduler freescout-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=mariadb.service IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=freescout-scheduler.service IPAddressDeny=168.63.129.16/32 169.254.169.254/32 fd00:ec2::254/128 Id=freescout-firstboot.servicesudo freescout-artisan <command> runs FreeScout's console with the same block.
Backup, storage and maintenance
Everything you enter is in the MariaDB database freescout (/var/lib/mysql). Attachments, uploads, sessions, caches and FreeScout's logs are under /var/lib/freescout. The settings file with the application key is /etc/freescout/freescout.env.
All three are on the root volume, so the simplest backup is an EBS snapshot of it. For a consistent copy while FreeScout is running:
sudo mariadb-dump --single-transaction --routines freescout | gzip > <backup-dir>/freescout-$(date +%F).sql.gz
sudo tar -C / -czf <backup-dir>/freescout-files-$(date +%F).tar.gz var/lib/freescout/storage/app etc/freescoutKeep /etc/freescout/freescout.env with the dump. Its APP_KEY encrypts the mailbox passwords FreeScout stores, and a restored database cannot use them without it. The dump and the settings file hold every password hash and secret, so store them as carefully as the instance.
To give attachments and the database more room, enlarge the root volume in the EC2 console (Volumes, Modify). Ubuntu grows the file system on the next boot.
To keep FreeScout's data on its own EBS volume instead, attach a volume and stop FreeScout. Copy /var/lib/mysql and /var/lib/freescout onto the volume, 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.
FreeScout's web updater and module installer cannot change the code on this image, because the code is read-only to PHP. New FreeScout releases arrive as new versions of this listing, and support can help you move your data to one.
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 FreeScout keeps all of its data.
- FreeScout: /var/www/freescout (owned by root, read-only to PHP; nginx serves public/)
- Settings and application key: /etc/freescout/freescout.env (owned by freescout, mode 0600)
- Database: MariaDB database freescout (/var/lib/mysql)
- Attachments, uploads, sessions, caches and logs: /var/lib/freescout
- nginx site: /etc/nginx/sites-available/sac-freescout
- Certificate and key: /etc/nginx/ssl/freescout.crt, /etc/nginx/ssl/freescout.key
- Scheduler: freescout-scheduler.service
- Helpers: /usr/local/sbin/freescout-set-password, freescout-set-hostname, freescout-artisan, freescout-cred-roundtrip
- Credentials: /root/freescout-credentials.txt (mode 0600)
- Source and changes: /usr/share/doc/freescout/SOURCE.txt
Security recommendations
- Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your agents work from.
- Use your own DNS name and a certificate your users' browsers trust (Step 9).
- Set your own email address on the administrator and change its password (Step 5). Give each agent their own user with access only to the mailboxes they work in.
- Use dedicated support mailboxes with their own passwords (or app passwords) for fetching and sending, and keep Validate Certificate on.
- Keep the operating system patched, and snapshot the root volume regularly.
Support and licensing
FreeScout is open source under the GNU Affero General Public License version 3, by the FreeScout project and its contributors. There is no per-agent or per-mailbox license fee.
The image ships FreeScout exactly as released, with its bundled PHP libraries and no modules. /usr/share/doc/freescout/SOURCE.txt names the release it came from and lists every file the image leaves out or adds. No source file is modified. The AMI price covers SecureAnyCloud's hardening, first boot setup and support.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- 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.
Deploy on AWS
Launch FreeScout 1.8.250 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