Running MODX on Linode means building a LEMP stack on an Ubuntu instance, dropping the MODX Revolution 3 package into the web root, running the browser setup wizard, and then moving the core directory somewhere the public cannot reach it. The whole process takes under an hour and MODX 3 is light enough that a 1 GB Nanode handles a small site comfortably. The parts worth slowing down for are the core relocation and the cron entry for the scheduler.
/var/www/modx, run /setup/ in a browser, then move core/ above the web root, delete setup/, issue a Let’s Encrypt certificate and add a cron job that hits the scheduler.MODX Revolution 3.2.4 is the current release line, and MODX 3.x raised its floor to PHP 8.1 and recommends 8.2 or higher, which is why building on a current Ubuntu LTS is the path of least resistance. The official server requirements page also lists the extensions MODX needs, and every one of them ships in the standard Ubuntu PHP packages. Nothing exotic is involved.
Deploy and prepare the Linode
In the Linode Cloud Manager, create a Linode with the latest Ubuntu LTS image in a region near your visitors. A Nanode with 1 GB of memory is enough for a brochure site. Pick 2 GB if you plan to run image heavy pages or the ImageMagick extension.
ssh root@YOUR_LINODE_IP
hostnamectl set-hostname modx-web
adduser deploy
usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy/
apt update && apt upgrade -y
apt install -y ufw
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw --force enable
timedatectl set-timezone America/New_YorkPoint an A record at the Linode IP now. Certificate issuance later depends on DNS already resolving, and propagation is the one part of this you cannot speed up.
Install the LEMP stack
MODX works on Apache or Nginx. Nginx uses less memory, which matters on a small instance, and the config below covers everything MODX needs including friendly URLs.
apt install -y nginx mariadb-server \
php-fpm php-mysql php-curl php-dom php-fileinfo php-gd php-json \
php-simplexml php-xml php-xmlwriter php-zip php-mbstring php-iconv php-intl
php -v
mysql_secure_installationThe extension list is not padded. MODX requires curl, dom, fileinfo, gd, json, pdo, simplexml, xml, xmlwriter, zip and zlib, and recommends mbstring, iconv and intl on top. Missing one produces a setup wizard that fails a check with a message you will not enjoy tracing.
Raise the PHP limits next. Edit the FPM ini file for your PHP version, then restart the pool.
# /etc/php/8.3/fpm/php.ini
memory_limit = 256M
max_execution_time = 120
upload_max_filesize = 64M
post_max_size = 64M
systemctl restart php8.3-fpmCreate the database
mysql -u root -p
CREATE DATABASE modx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'modxuser'@'localhost' IDENTIFIED BY 'a_long_random_password';
GRANT ALL PRIVILEGES ON modx.* TO 'modxuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;Use utf8mb4, not utf8. MODX supports both, but the older three byte character set cannot store emoji or a lot of non Latin content and the failure is a silent truncation rather than an error.
Download MODX and run setup
Grab the Advanced distribution rather than the Traditional one. Advanced is what lets you relocate the core directory during setup instead of moving it afterward and repairing paths by hand.
mkdir -p /var/www/modx
cd /tmp
# Check modx.com/download for the current release first
wget https://modx.s3.amazonaws.com/releases/3.2.4-pl/modx-3.2.4-pl-advanced.zip
apt install -y unzip
unzip modx-3.2.4-pl-advanced.zip
mv modx-3.2.4-pl-advanced/* /var/www/modx/
chown -R www-data:www-data /var/www/modx
find /var/www/modx -type d -exec chmod 755 {} \;
find /var/www/modx -type f -exec chmod 644 {} \;Now the Nginx server block. Save it as /etc/nginx/sites-available/modx.
server {
listen 80;
server_name example.com www.example.com;
root /var/www/modx;
index index.php;
location / {
try_files $uri $uri/ @modx;
}
location @modx {
rewrite ^/(.*)$ /index.php?q=$1;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~* /(core|\.git)/ { deny all; return 404; }
location ~ /\.ht { deny all; }
client_max_body_size 64M;
}ln -s /etc/nginx/sites-available/modx /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginxVisit http://example.com/setup/. Choose New Installation, enter the database name, user and password with localhost as the host, and when the Advanced distribution asks where the core should live, give it a path outside the web root such as /var/www/modx-core/. Create the admin account and let it finish.
Move the core and lock down
If you used the Traditional distribution, or you skipped the core path prompt, relocate it now. This is the difference between a MODX install that leaks its configuration and one that does not.
mv /var/www/modx/core /var/www/modx-core
chown -R www-data:www-data /var/www/modx-coreThen update the four config files that reference the core path: config.core.php in the web root, plus the copies inside manager/, connectors/ and the core itself. Each holds a single MODX_CORE_PATH definition.
<?php
define('MODX_CORE_PATH', '/var/www/modx-core/');
define('MODX_CONFIG_KEY', 'config');Delete the setup directory, rename the manager to something less guessable if you want, and issue a certificate.
rm -rf /var/www/modx/setup
apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com
systemctl status certbot.timersite_url and server_protocol system settings inside the MODX manager to the https address. Leaving them on http produces mixed content warnings that are tedious to hunt down in templates.Cron for the scheduler and caching
MODX does not run scheduled work on its own. If you use Extras that publish content on a date, send digests, or rebuild sitemaps, they need a cron entry. Add one as the web user.
crontab -u www-data -e
# Every 15 minutes, publish scheduled resources and run Extras schedulers
*/15 * * * * /usr/bin/php /var/www/modx-core/cron.php >/dev/null 2>&1
# Nightly cache clear, optional but keeps long running sites tidy
30 3 * * * /usr/bin/find /var/www/modx-core/cache -mindepth 1 -deleteBecause you moved the core, that path points at the new location. Using the old in webroot path here is the most common reason a scheduler quietly never fires.
| Component | MODX 3 requirement | What to install on Ubuntu |
|---|---|---|
| PHP | 8.1 minimum, 8.2 or higher recommended | Distribution PHP FPM package |
| Database | MySQL 5.7 minimum, MySQL 8.0+ or MariaDB 10.6+ recommended | mariadb-server |
| Web server | Apache 2.4+ or nginx 1.18.x recommended | nginx |
| Required extensions | curl, dom, fileinfo, gd, json, pdo, simplexml, xml, xmlwriter, zip, zlib | Listed in the apt command above |
| Memory | 64M recommended floor | Set 256M for package installs |
If you would rather run MODX on a cPanel host than manage a server, our walkthrough on installing MODX on Bluehost covers the panel driven equivalent. For a comparison of what a full control panel adds on top of a bare Linode, see the guide to launching CyberPanel on Hostinger. And if you are building several sites on this box, the same stack pattern shows up in our notes on running Drupal on Linode.
Troubleshooting
Setup wizard reports a failed dependency check. A PHP extension is missing. The wizard names it. Install the matching package, for example apt install php8.3-intl, restart PHP FPM, then reload the setup page rather than starting over.
Manager loads but every page returns 404 on the front end. Friendly URLs are on in MODX but Nginx has no rewrite. Confirm the @modx named location and its try_files fallback are present, and that you reloaded Nginx after editing.
Blank white page after moving the core. One of the four config.core.php files still points at the old path. Grep for the old location with grep -r MODX_CORE_PATH /var/www/modx and fix every match, including the one inside the relocated core.
Cannot upload files in the media browser. Ownership drifted, usually after copying files as root. Run chown -R www-data:www-data /var/www/modx /var/www/modx-core and confirm upload_max_filesize and client_max_body_size both allow the size you are trying.
Scheduled resources never publish. The cron entry is missing, pointing at the wrong core path, or running as the wrong user. Check with crontab -u www-data -l and confirm the PHP binary path with which php.
Frequently asked questions
What size Linode do I need for MODX?
A 1 GB Nanode runs a small MODX site fine because MODX caches aggressively and its footprint is modest. Move to 2 GB if you install ImageMagick, run several sites on the instance, or expect sustained traffic. Storage is usually the constraint before memory.
Should I use the Traditional or Advanced distribution?
Advanced, in almost every case. It lets you place the core directory outside the web root during setup rather than moving it afterward and editing four config files. Traditional is only simpler if you are installing on a host that forbids paths above the document root.
Which PHP version does MODX 3 require?
PHP 8.1 is the minimum since MODX 3.2, and the documentation recommends 8.2 or higher. MODX 3.0 originally shipped with a PHP 7.2 floor, so older tutorials will tell you something different. Check the requirements page rather than trusting an article’s date.
Do I have to move the core directory?
You do not have to, but you should. The core holds your database credentials, cached data and error logs. Leaving it inside the web root means a single misconfigured rule can expose all of it. The deny rule in the Nginx config above is a second layer, not a substitute.
How do I keep MODX updated?
Back up the database and files first, then download the same distribution type for the new version, upload it over the existing install, and run /setup/ again choosing Upgrade. Delete the setup directory afterward. Extras update separately through the manager’s Installer.
The bottom line
MODX on Linode is a comfortable pairing. The application is lightweight, the requirements are all satisfied by stock Ubuntu packages, and a small instance goes a long way. Install the LEMP stack, use the Advanced distribution so the core lands outside the web root on the first pass, and let certbot handle TLS.
The two steps that separate a working install from a fragile one are the core relocation and the cron entry. Get the core out of the document root and update all four config files, then confirm the scheduler actually runs against the new path. After that, MODX is one of the quieter content systems to operate, and this box will keep serving without much attention from you.
