EspoCRM 10.0.3
Overview
EspoCRM is an open-source customer relationship management application. It brings accounts, contacts, leads, opportunities, cases, emails, meetings, calls, tasks, a calendar, documents, a knowledge base and an activity stream together in one web application. It also provides role-based access control, customer portals, import and export, workflows through scheduled jobs and a full REST API.
This guide covers launching and using the EspoCRM 10.0.3 on Ubuntu 24.04 AMI from SecureAnyCloud on Amazon EC2. The image is one version of the SecureAnyCloud ERP and CRM listing on AWS Marketplace, and you choose it as the software version when you subscribe and launch.
What you get:
- No default login. The administrator password and EspoCRM's application keys (
cryptKey,hashSecretKey) are generated on your instance's first boot, and the password is written to/root/espocrm-credentials.txt(root only). The image ships no known password, and EspoCRM refuses blank and common passwords such asadminandpassword. - No database password. EspoCRM signs in to MySQL as the MySQL user
www-dataover the local unix socket, authenticated by the operating system (auth_socket). Only processes running as thewww-datauser get in, so there is no database password to store, leak or rotate. - No install wizard. EspoCRM is installed and its database is built from the command line. The web install wizard is deleted from disk and its URL answers 404, so nobody who reaches the instance first can take it over.
- HTTPS from the first boot. nginx serves EspoCRM on port 443 with a certificate generated on your instance. Port 80 redirects to HTTPS, and requests for a host name that the instance does not serve are dropped.
- Fail-closed start. nginx, PHP-FPM and the scheduled jobs start only after first boot has finished. If first boot cannot finish, nothing is served.
- A hardened MySQL. MySQL 8.0 listens on
127.0.0.1only, with the X protocol,LOAD DATA LOCAL, the binary log and the general query log switched off. MySQL'srootaccount works only from the instance itself (sudo mysql), and no MySQL account has a password. - Hardened defaults. nginx, PHP-FPM, MySQL, the scheduled jobs and the first-boot service are blocked from the instance metadata service, and the AMI requires IMDSv2. EspoCRM is handed the configured host name and the real client address from the connection, never values that a client sends.
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
What is on the image: EspoCRM 10.0.3 (the upstream release, checksum verified), nginx 1.24, PHP 8.3 FPM with OPcache, MySQL 8.0 (all from Ubuntu 24.04), 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 that you use for management).
- A security group that allows TCP 22 (SSH) from your admin network, and TCP 443 (EspoCRM) and TCP 80 (redirects to HTTPS) from the networks your users work from. Never open 3306, because MySQL listens on the loopback address only.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Select EspoCRM 10.0.3 on Ubuntu 24.04 as the software version, select your Region, and choose Launch through EC2. Pick m5.large, your key pair and a security group as described above.
The root volume holds the database and uploaded files, so give it room to grow (for example 30 GiB or more for a busy CRM).
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> \
--block-device-mappings 'DeviceName=/dev/sda1,Ebs={VolumeSize=30,VolumeType=gp3}' \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=espocrm}]'First boot takes well under a minute after the instance is running.
Connect to your instance
Connect to EspoCRM 10.0.3 on Ubuntu 24.04 as the SSH user ubuntu, with the key pair you chose at launch:
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot sets the passwords, keys and certificate, and then nginx, PHP-FPM and the scheduled jobs start:
systemctl is-active nginx php8.3-fpm mysql espocrm-cron.timer espocrm-firstboot
sudo test -f /var/lib/sac/data/espocrm-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. MySQL listens on the loopback address, and PHP-FPM uses a local socket:
sudo ss -lntp | awk 'NR>1 {print $4, $6}' | grep -v '127.0.0.5' | 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.1:3306 users:(("mysqld")) [::]:22 users:(("sshd"),("systemd")) [::]:443 users:(("nginx"),("nginx"),("nginx")) [::]:80 users:(("nginx"),("nginx"),("nginx"))Get your URL and password
sudo cat /root/espocrm-credentials.txtOnly root can read this file:
# EspoCRM 10.0.3 - generated on first boot by espocrm-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. espocrm.url=https://<public-ip>/ espocrm.admin.user=admin espocrm.admin.pass=<ESPOCRM_ADMIN_PASSWORD> espocrm.db.name=espocrm espocrm.db.user=www-data
# EspoCRM signs in to MySQL as www-data over the unix socket (auth_socket): no database password exists.
# The certificate is self signed (minted on this instance): accept the browser warning once, or install
# your own. Port 80 redirects to https. Change the name EspoCRM is served as (also its siteUrl):
#
sudo espocrm-set-hostname <your-dns-name>
# MySQL listens on 127.0.0.1:3306 only; on the instance 'sudo mysql' is root over the unix socket, and
# 'sudo -u www-data mysql -u www-data espocrm' opens EspoCRM's database as the application user. # EspoCRM CLI:
sudo -u www-data php /var/www/espocrm/command.php <command>
# User guide: https://secureanycloud.com/stacks/espocrm-10-0-3/The URL uses the instance's public IP address from the EC2 instance metadata. The certificate also names the public DNS name and the private IP address, so https://<public-dns-name>/ works too. If you stop and start the instance without an Elastic IP, the boot service picks up the new address, issues a new certificate for it and updates EspoCRM's site URL. To serve EspoCRM under your own DNS name, see Step 7.
Sign in
Browse to the URL from the credentials file. Your browser warns once about the self-signed certificate. Accept it, or install your own certificate (Step 7). Sign in as admin with the password from the credentials file.
After you sign in, you land on the home dashboard, with the navigation for accounts, contacts, leads, opportunities, activities and support on the left. Add your own users under Administration > Users and sign in as them for day-to-day work.
Work with your customer records
Choose Leads > Create Lead, fill in the name, account, status and source, and save. Every list supports search, filters, mass actions and export. A lead converts into an account, a contact and an opportunity in one action.
Use Administration to configure the system settings, outbound email (SMTP), authentication options, roles and teams, scheduled jobs, currencies and extensions. Set up outbound email first so that password recovery and notifications can reach your users.
The scheduled jobs (email sending and fetching, reminders, cleanup) run every minute from espocrm-cron.timer as the www-data user, so leave that timer enabled.
Your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), and then set the name that EspoCRM is served as. This creates a new self-signed certificate for the name, updates nginx, EspoCRM's site URL (used in the links in emails) and the URL in /root/espocrm-credentials.txt, and keeps the name across reboots:
sudo espocrm-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 espocrm-set-hostname again replaces it with a self-signed one:
sudo install -m 0644 <your-domain>.crt /etc/nginx/ssl/espocrm.crt
sudo install -m 0600 <your-domain>.key /etc/nginx/ssl/espocrm.key
sudo nginx -t && sudo systemctl reload nginxSecurity checks
The shipped round trip signs in as the admin administrator with this instance's password. It confirms that a wrong password, a blank password and the common passwords admin and password are refused, and it creates, reads and deletes a lead. It also checks that MySQL lets the www-data user into EspoCRM's database over the socket, while refusing the same account from any other user and refusing any password login over TCP. Credentials are handed to curl and mysql in root-only temporary files, never on a command line:
sudo bash /usr/local/sbin/espocrm-cred-roundtrip.shOK per-instance admin signs in over HTTPS (200); wrong, blank, 'admin' and 'password' refused (401); Lead create/read/delete; MySQL app user www-data: socket login as www-data only, other OS users and TCP passwords refusedThe install wizard is not on disk and its URL answers 404, the API refuses requests without a login, plain HTTP redirects to HTTPS on the configured name, and a host name the instance does not serve gets no answer at all:
H=$(sudo grep '^espocrm.url=' /root/espocrm-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#') for p in / /api/v1/App/user /install/ /install/index.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} %{redirect_url}\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 test -e /var/www/espocrm/install || echo "install wizard: not on disk"200 / 401 /api/v1/App/user 404 /install/ 404 /install/index.php http:// -> 301 https://<public-ip>/ unknown host name -> 000 install wizard: not on diskThe certificate was generated on this instance and names its own addresses:
H=$(sudo grep '^espocrm.url=' /root/espocrm-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 = <public-ip>, O = sac X509v3 Subject Alternative Name: IP Address:<public-ip>, DNS:<public-dns-name>, IP Address:<private-ip>, IP Address:127.0.0.1, DNS:localhostNone of the services can reach the instance metadata service:
systemctl show nginx php8.3-fpm mysql espocrm-cron espocrm-firstboot -p Id -p IPAddressDenyIPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 Id=nginx.service IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 Id=php8.3-fpm.service IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 Id=mysql.service IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 Id=espocrm-cron.service IPAddressDeny=168.63.129.16/32 fd00:ec2::254/128 169.254.169.254/32 Id=espocrm-firstboot.servicenginx hands PHP the configured host name and the client address from the connection, never values that a client sends, so EspoCRM's login history records the real address of every sign-in:
grep -E 'fastcgi_param (HTTP_HOST|HTTPS|HTTP_X_FORWARDED_FOR|HTTP_X_REAL_IP|HTTP_FORWARDED) ' /etc/nginx/sac-espocrm-fastcgi.conffastcgi_param HTTP_HOST $espo_host; fastcgi_param HTTPS on; fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr; fastcgi_param HTTP_X_REAL_IP $remote_addr; fastcgi_param HTTP_FORWARDED "";MySQL runs with the SecureAnyCloud settings, and its only accounts are the application user www-data and root, both reached over the unix socket with no password:
sudo mysql -e "SELECT @@bind_address, @@local_infile, @@log_bin, @@general_log; SELECT user, host, plugin FROM mysql.user WHERE user NOT LIKE 'mysql.%' ORDER BY user, host;" cat /etc/sac/espocrm-release.txt@@bind_address @@local_infile @@log_bin @@general_log 127.0.0.1 0 0 0 user host plugin root localhost auth_socket www-data localhost auth_socket sac: EspoCRM 10.0.3 (AGPL-3.0-or-later) from github.com/espocrm/espocrm releases, sha256 73369bb3e319846c99f1b6d0254fac9339bbfe46705d6dd882eaf648f85b87b1; install wizard removed.Versions and the command line
sudo -u www-data php /var/www/espocrm/command.php version php -r 'echo PHP_VERSION."\n";' mysqld --version nginx -v10.0.3 8.3.6 /usr/sbin/mysqld Ver 8.0.46-0ubuntu0.24.04.4 for Linux on x86_64 ((Ubuntu)) nginx version: nginx/1.24.0 (Ubuntu)EspoCRM's console runs as the www-data user, for example sudo -u www-data php /var/www/espocrm/command.php clear-cache, rebuild after a configuration change, or app-check for a health check.
Changing passwords
- EspoCRM
admin: in EspoCRM, open your own user record (your name in the top-right menu) and choose Change Password from its menu. Alternatively, run the command below on the instance. It asks for the new password at a prompt, so the password never appears on a command line. Then update or deleteespocrm.admin.passin/root/espocrm-credentials.txt:
sudo -u www-data php /var/www/espocrm/command.php set-password admin- Other users can reset their own password from the sign-in page once outbound email is set up (Administration > Outbound Emails). Password recovery links always point at the configured site URL, never at a host name taken from the request.
Backup and maintenance
The database lives in MySQL (/var/lib/mysql) and uploaded files under /var/www/espocrm/data/upload. The simplest backup is an EBS snapshot of the root volume. For a logical backup of the database while EspoCRM is running:
sudo mysqldump --single-transaction --routines --triggers espocrm | gzip > <backup-dir>/espocrm-$(date +%F).sql.gz
sudo tar -czf <backup-dir>/espocrm-files-$(date +%F).tar.gz -C /var/www/espocrm data/upload customOperating system, nginx, PHP and MySQL security updates install automatically from Ubuntu. Run sudo apt-get update && sudo apt-get upgrade to apply everything else. To upgrade EspoCRM itself, use Administration > Upgrade or run sudo -u www-data php /var/www/espocrm/command.php upgrade, and take a snapshot first.
Components and paths:
EspoCRM /var/www/espocrm (web root /var/www/espocrm/public)
EspoCRM configuration /var/www/espocrm/data/config.php, config-internal.php (www-data only)
MySQL settings /etc/mysql/mysql.conf.d/99-sac-espocrm.cnf
nginx site /etc/nginx/sites-available/sac-espocrm
Certificate and key /etc/nginx/ssl/
Scheduled jobs espocrm-cron.timer / espocrm-cron.service
Boot service /usr/local/sbin/espocrm-firstboot.sh
Host name helper /usr/local/sbin/espocrm-set-hostname
Credentials /root/espocrm-credentials.txt (mode 0600)
Security recommendations
- Allow port 22 from your admin network only, and allow ports 80 and 443 only from the networks your users work from. Never open 3306 to the internet.
- Use your own DNS name and a certificate that your browsers trust (Step 7).
- Create a named user for each person, with a role that limits what that person can see, and keep
adminfor administration. - Turn on two-factor authentication under Administration > Authentication, change the admin password if it may have been shared (Step 10), keep the operating system patched, and snapshot the volume regularly.
Support and licensing
EspoCRM is open-source software licensed under the GNU Affero General Public License version 3 or later, with the additional term that its user interface keeps showing the "EspoCRM" name. SecureAnyCloud ships it unmodified. There is no per-user licence fee. The AMI price covers SecureAnyCloud's hardening, first-boot setup and support. EspoCRM is a trademark of its owner, and SecureAnyCloud is not affiliated with or endorsed by EspoCRM, Inc.
- Email: sales@secureanycloud.com
- Website: https://secureanycloud.com
- Support: 24/7, with a 24-hour response SLA
Deploy on AWS
Launch EspoCRM 10.0.3 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