DomainMOD 4.23.0
Overview
This guide covers launching and using the DomainMOD 4.23.0 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.
DomainMOD is an open source application for managing domains and other internet assets in one place. It records every domain you own with its registrar, expiry date, renewal fee, owner, category and DNS provider. It tracks SSL certificates, hosting accounts and IP addresses the same way, sends expiration e-mails, and reports renewal costs across currencies. It can also pull your domain list straight from supported registrar APIs through its domain queue.
What you get:
- No installation wizard and no default login. DomainMOD's own installer creates the
adminadministrator with the passwordadminand offers no way to choose another. This image runs the installer at build time, replaces that password at once, and proves that admin is refused. It then deletes theinstall/directory, and nginx returns 404 for/install/as well. - A password unique to your instance, and no database password at all. The DomainMOD
adminpassword is generated on first boot and written to/root/domainmod-credentials.txt(root-only). DomainMOD then asks you to choose your own password when you first sign in. DomainMOD reaches MariaDB as the system userwww-dataover the local socket, which MariaDB authenticates by the connecting process (unix_socket), so there is no database password to steal or rotate. The image ships with no DomainMOD database at all. First boot creates it, and nginx and PHP-FPM refuse to start until first boot has finished. - HTTPS from the first boot. nginx serves DomainMOD on port 443 with a certificate generated on your instance, and port 80 redirects to HTTPS. Requests for a host name the instance does not serve are dropped. DomainMOD's own HTTPS switch is on, so the session cookie is
Secure. - Only the application on the web. Upstream ships no web server rules at all. On this image, the configuration file, the class library, the vendored dependencies, the scheduler and upgrade entry points, and DomainMOD's
temp/directory all answer 404. The backup page writes a full database dump to that directory. - The scheduler on a timer, not a public URL. DomainMOD's task scheduler runs every ten minutes from a systemd timer, instead of from a
cron.phpweb request that anyone could trigger. - Hardened defaults. MariaDB listens on
127.0.0.1only, with its data on a dedicated 20 GiB EBS volume. nginx, PHP-FPM, MariaDB, the scheduler and the first-boot service are blocked from the instance metadata service, because DomainMOD calls registrar APIs and other remote services. The AMI requires IMDSv2. PHP is handed the configured host name and the real client address from the connection, never values that a client sends. Cross-site form posts are refused. - Bundled library fixes. DomainMOD 4.23.0 is the newest release, but three libraries it bundles have security fixes that it does not carry yet. The image updates them to the fixed upstream releases: the Carbon date library 2.72.6 (CVE-2025-22145), moment 2.29.4 (CVE-2022-24785 and CVE-2022-31129) and JSZip 3.10.1 (CVE-2022-48285).
- Fully patched Ubuntu 24.04 LTS at build time, with unattended security upgrades switched on.
- Components: DomainMOD 4.23.0 (the upstream v4.23.0 release, checksum verified), nginx, PHP 8.3 FPM with OPcache, MariaDB, 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 that you use for management).
- A security group that allows TCP 22 (SSH) from your admin network, and TCP 443 (DomainMOD) and TCP 80 (redirects to HTTPS) from the networks your users work from.
- Never open 3306. DomainMOD can hold registrar API credentials, so keep 80 and 443 as narrow as you can.
Launch the instance
In the AWS Marketplace listing, choose Continue to Subscribe, then Continue to Configuration. Pick DomainMOD 4.23.0 on Ubuntu 24.04 as the software version, choose your Region, then choose Launch through EC2.
Choose m5.large, your key pair and a security group as above. The AMI brings two volumes: the root volume and a 20 GiB data volume for the database.
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> \
--metadata-options HttpTokens=required,HttpEndpoint=enabled \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=domainmod}]'First boot takes well under a minute after the instance is running.
Connect to your instance
The SSH user for DomainMOD 4.23.0 on Ubuntu 24.04 is ubuntu.
ssh -i <your-key.pem> ubuntu@<public-ip>Check the services
First boot sets the passwords and the certificate, and then nginx and PHP-FPM start. Check the units and the first-boot marker:
systemctl is-active nginx php8.3-fpm mariadb domainmod-firstboot
sudo test -f /var/lib/sac/data/domainmod-firstboot.done && echo FIRSTBOOT_DONEAll four units are active and the first boot marker is present:
active active active active FIRSTBOOT_DONEOnly SSH and nginx listen on network ports. MariaDB 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' | sort0.0.0.0:22 users:(("sshd",...)) 0.0.0.0:443 users:(("nginx",...)) 0.0.0.0:80 users:(("nginx",...)) 127.0.0.1:3306 users:(("mariadbd",...)) [::]:22 users:(("sshd",...)) [::]:443 users:(("nginx",...)) [::]:80 users:(("nginx",...))Get your URL and password
sudo cat /root/domainmod-credentials.txtThe file is readable by root only:
# DomainMOD 4.23.0 - generated on first boot by domainmod-firstboot.service
# These credentials are unique to this instance; none was baked into the image. Keep this file secret. DOMAINMOD_URL=https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ DOMAINMOD_ADMIN_USER=admin DOMAINMOD_ADMIN_PASSWORD=<DOMAINMOD_ADMIN_PASSWORD>
# Database: MariaDB on this instance, database 'domainmod'. DomainMOD connects as the system user www-data
# over the local socket (MariaDB unix_socket authentication), so there is NO database password at all. MARIADB_DATABASE=domainmod MARIADB_USER=www-data
# DomainMOD asks you to choose your own password after you first sign in.
# The certificate is self signed (minted on this instance); port 80 redirects to https.
# Change the name DomainMOD is served as:
sudo domainmod-set-hostname <your-dns-name>
# MariaDB listens on 127.0.0.1 only; on-box maintenance:
sudo mariadb
# User guide: https://secureanycloud.com/stacks/domainmod-4-23-0/The URL uses the instance's public DNS name from the EC2 instance metadata. The certificate also names the public and private IP addresses, so https://<public-ip>/ works too.
If you stop and start the instance without an Elastic IP, the boot service picks up the new address and issues a new certificate for it. To serve DomainMOD under your own DNS name, see Step 9.
There is no database password. /var/www/domainmod/_includes/config.inc.php names the user www-data with an empty password, and MariaDB accepts that user only from processes running as www-data on this instance (PHP-FPM and the scheduler). For your own maintenance, sudo mariadb signs you in as the MariaDB root user, also by socket.
Sign in and choose your password
Open the DOMAINMOD_URL in your browser. The certificate is self-signed, so your browser asks you to confirm it the first time. You can install your own certificate instead (Step 9). Sign in as admin with the password from Step 4:
DomainMOD takes you straight to Change Password, because the first-boot password is only meant to get you in. Enter a password of your own twice and select Change Password.
Then delete or update DOMAINMOD_ADMIN_PASSWORD in /root/domainmod-credentials.txt, so that the file does not hold an old password. The Dashboard shows the system totals, with the full navigation on the left and the DomainMOD version in the footer.
You can also check the sign-in from the instance. This script signs in through the real login form over HTTPS with the instance's first-boot password. It then shows that upstream's default admin, a blank password and common weak passwords are refused.
Run it before you change the password. Afterwards it reports that the first-boot password no longer works, which is what you want:
sudo domainmod-cred-roundtrip.shOK per-instance admin signs in over HTTPS; upstream's admin/admin, blank and weak guesses refusedAdd your registrars and domains
DomainMOD organises domains under the registrar they are registered with, so a registrar and a registrar account come first. Open Domains, and DomainMOD tells you exactly that.
Select Click here to add a Domain Registrar, save it, then add a registrar account under it. After that, add domains one at a time, or import them in bulk with the CSV importer on the same page. For the registrars that DomainMOD supports, you can instead save the account's API credentials and let the Domain Queue pull your domain list and expiry dates from the registrar.
SSL Certificates does the same for your certificates, with their own providers, accounts and types. Assets holds the records that those point at (owners, categories, DNS profiles, IP addresses, web hosts).
Segments groups domains that you want to report on together. Reporting turns the fee data into renewal cost reports in your currency, and Bulk Updater changes many records at once.
Set up e-mail and check the installation URL
DomainMOD sends expiration e-mails and password reset links. Set your SMTP server under Administration, System Settings. Amazon SES works as the relay (port 587 with STARTTLS). Allow outbound 587 if you restrict egress.
Each user subscribes to expiration e-mails in their User Profile.
The links inside those e-mails start from DomainMOD's installation URL. On this image it is always the address that DomainMOD is served as (https://<host>). First boot and domainmod-set-hostname (Step 9) keep it in step, so you do not need to edit it by hand. Check it with:
sudo mariadb -N -B domainmod -e "SELECT full_url FROM settings;"https://ec2-<public-ip-dashed>.compute-1.amazonaws.comReview the task scheduler
DomainMOD's scheduler processes the domain queue, sends the expiration e-mails, updates currency conversion rates, cleans up, checks for a new DomainMOD release and builds the data warehouse.
Upstream asks you to call cron.php every ten minutes. On this image, a systemd timer runs it every ten minutes through the PHP command line as the web server user, and cron.php is not reachable over the web:
systemctl is-enabled domainmod-scheduler.timer
systemctl cat domainmod-scheduler.timer | grep -E '^On'enabled OnBootSec=5min OnUnitActiveSec=10minTurn individual jobs on or off, change their run times or run one now under Administration, Task Scheduler:
The Check For New Version job asks GitHub for the latest DomainMOD release.
DomainMOD also reports installs and upgrades to domainmod.org from your first sign-in after them. The record that the build created was removed, so nothing about the image build is sent from your instance.
Use your own DNS name and certificate
Point a DNS record at the instance (an Elastic IP keeps the address stable), then set the name that DomainMOD is served as. This mints a new self-signed certificate for the name, updates nginx, DomainMOD's installation URL and the URL in /root/domainmod-credentials.txt, and keeps the name across reboots:
sudo domainmod-set-hostname <your-domain>To use a certificate from a public or internal certificate authority instead, copy it over the generated pair and reload nginx. An example is a certificate issued by Let's Encrypt for <your-domain>. Running domainmod-set-hostname again replaces it with a self-signed one:
sudo install -m 0644 <your-domain>.crt /etc/ssl/domainmod/domainmod.crt
sudo install -m 0600 <your-domain>.key /etc/ssl/domainmod/domainmod.key
sudo nginx -t && sudo systemctl reload nginxSecurity checks
The installer is gone, and nginx serves only the application. The configuration file, the vendored code, temp/, the scheduler and the upgrade entry point answer 404. Plain HTTP redirects to HTTPS:
H=$(sudo grep '^DOMAINMOD_URL=' /root/domainmod-credentials.txt | cut -d= -f2- | sed -E 's#https://([^/]+)/#\1#') for p in /index.php /install/ /_includes/config.inc.php /vendor/autoload.php /temp/ /cron.php /update.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/" ls /var/www/domainmod/install 2>&1 | sed 's/^ls: //' [ "$(curl -sk -o /dev/null -w '%{http_code}' --resolve "$H:443:127.0.0.1" "https://$H/install/")" = "404" ]200 /index.php 404 /install/ 404 /_includes/config.inc.php 404 /vendor/autoload.php 404 /temp/ 404 /cron.php 404 /update.php http:// -> 301 https://ec2-<public-ip-dashed>.compute-1.amazonaws.com/ cannot access '/var/www/domainmod/install': No such file or directoryadmin is the only account, and upstream's admin / admin password hash is nowhere in the database:
sudo mariadb -N -B domainmod -e "SELECT CONCAT('accounts that can sign in: ', GROUP_CONCAT(username)) FROM users; SELECT CONCAT('upstream admin/admin hashes present: ', COUNT(*)) FROM users WHERE password = CONCAT('*', UPPER(SHA1(UNHEX(SHA1('admin')))));"accounts that can sign in: admin upstream admin/admin hashes present: 0DomainMOD's database account has no password. MariaDB accepts it only over the local socket from processes running as www-data, and nothing is reachable over TCP from other hosts:
sudo mariadb -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 = 'www-data';"
sudo -u www-data mariadb -N -B domainmod -e "SELECT CONCAT('signed in as ', CURRENT_USER());"www-data@localhost authenticates by unix_socket, password set: no signed in as www-data@localhostDomainMOD reports version 4.23.0 in its code and its database:
echo "$(cat /var/www/domainmod/version.txt)"
sudo mariadb -N -B domainmod -e "SELECT db_version FROM settings;"4.23.0 4.23.0The certificate was generated on this instance and names its own addresses:
H=$(sudo grep '^DOMAINMOD_URL=' /root/domainmod-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 registrar or data warehouse address that points at it gets nothing back:
systemctl show nginx php8.3-fpm mariadb domainmod-scheduler domainmod-firstboot -p Id -p IPAddressDenyIPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=nginx.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=php8.3-fpm.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=mariadb.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=domainmod-scheduler.service IPAddressDeny=fd00:ec2::254/128 169.254.169.254/32 168.63.129.16/32 Id=domainmod-firstboot.servicenginx hands PHP the configured host name and the client address from the connection, never values a client sends:
grep -E 'fastcgi_param (HTTP_HOST|HTTPS|HTTP_X_FORWARDED_FOR|HTTP_X_REAL_IP|HTTP_CLIENT_IP) ' /etc/nginx/sites-available/sac-domainmodfastcgi_param HTTP_HOST $domainmod_host; fastcgi_param HTTPS on; fastcgi_param HTTP_X_FORWARDED_FOR $remote_addr; fastcgi_param HTTP_X_REAL_IP $remote_addr; fastcgi_param HTTP_CLIENT_IP $remote_addr;nginx also refuses a form post whose Origin is another website (HTTP 403).
Back up and maintain the instance
Your whole estate lives in the MariaDB database domainmod. Its data directory is on the dedicated data volume: /data/mysql is mounted onto /var/lib/mysql.
findmnt -no SOURCE,TARGET,FSTYPE /data
findmnt -no SOURCE,TARGET /var/lib/mysql/dev/nvme1n1 /data ext4 /dev/nvme1n1[/mysql] /var/lib/mysqlThe device name can differ on your instance. The simplest backup is an EBS snapshot of the data volume. For a consistent dump while DomainMOD is running, use:
sudo mariadb-dump --single-transaction --routines domainmod | gzip > <backup-dir>/domainmod-$(date +%F).sql.gzDomainMOD's own Administration, Maintenance, Backup & Restore page also works on this image. It writes domainmod-backup.sql into /var/www/domainmod/temp/, which the web server never serves. You download the file through the signed-in page.
The dump holds every password hash and any registrar API keys you saved, so delete it when you have your copy:
sudo rm -f /var/www/domainmod/temp/domainmod-backup.sqlTo give the database more room, enlarge the data volume in the EC2 console (Volumes, Modify). Then grow the file system:
sudo resize2fs "$(findmnt -no SOURCE /data)"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 DomainMOD keeps all of its data.
Key locations on the instance:
- DomainMOD: /var/www/domainmod
- Configuration: /var/www/domainmod/_includes/config.inc.php (mode 0640)
- Database: MariaDB database domainmod (/var/lib/mysql, on the /data volume)
- nginx site: /etc/nginx/sites-available/sac-domainmod
- Certificate and key: /etc/ssl/domainmod/
- Boot service: /usr/local/sbin/domainmod-firstboot.sh
- Host name helper: /usr/local/sbin/domainmod-set-hostname
- Scheduler: domainmod-scheduler.timer (runs /var/www/domainmod/cron.php)
- Credentials: /root/domainmod-credentials.txt (mode 0600)
Security recommendations
- Allow port 22 from your admin network only, and ports 80 and 443 only from the networks your users work from. Never open 3306.
- Use your own DNS name and a certificate that your users' browsers trust (Step 9).
- Give each person their own DomainMOD user under Administration, Users. Change the
adminpassword if it may have been shared. DomainMOD has no lockout after wrong passwords, so keep the instance off the open internet where you can. - Save registrar API credentials only while you need them, as upstream recommends.
- Keep the operating system patched, and snapshot the data volume regularly.
- The offline DomainMOD user guide at
/docs/userguide/is a set of static pages that load jQuery 2.1.1. That version has cross-site scripting advisories (CVE-2015-9251, CVE-2019-11358, CVE-2020-11022, CVE-2020-11023) that are fixed only in jQuery 3. Those pages hold no forms or user data and never pass anything a visitor sends to jQuery, so the issues cannot be reached on this image. The DomainMOD application itself uses jQuery 3.6.0. A file scanner may still report the file.
Support and licensing
DomainMOD is open source under the GNU General Public License version 3 or later, created by Greg Chetcuti; there is no per-user or per-CPU licence fee. 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 DomainMOD 4.23.0 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