ServerAvatarDocs
Reference & troubleshooting

Stack differences

LEMP, LAMP, OLS, MERN and Docker — what each stack serves, which screens it hides, and everything that changes on OpenLiteSpeed.

The stack is chosen once, by the installer's --stack= flag, and recorded on the server. Almost every "why is that screen not there" question answers to it.

curl -fsSL https://raw.githubusercontent.com/DipaliRadadiya/open-source-sa/main/install.sh \
  | sudo bash -s -- --stack=lemp

A stack is two decisions: which web server gets installed, and what kind of application this box will serve. The second one is the one the rest of the panel reads.

The five presets

StackWeb serverServesPanel-managed databases
lempnginxPHP, staticYes
lampApachePHP, staticYes
olsOpenLiteSpeedPHP, staticYes
mernnginxNode.js, staticYes
dockernginxContainers onlyNo

mern maps to nginx because MERN uses nginx — it is not a web server of its own; nginx sits in front of your Node processes.

The stack cannot be changed from the panel

There is no screen that turns a PHP server into a container server. The decision is made by the installer and lives in the server's capability record. Moving a box between stacks means reinstalling it.

What "serves PHP" actually means

Every stack has PHP installed, including the Docker one — the panel is itself a PHP application, so it could hardly not. That is a different question from whether the box will host PHP sites, and the panel keeps the two apart.

So on a Docker server the PHP runtime is present and working, and the create catalog still offers you no PHP site types. That is deliberate, not a bug.

Which screens your stack shows

The sidebar is built from the stack, so two servers running the same version of OSS Panel can legitimately show different menus.

The OSS Panel dashboard for the server docs-oss-main: a LEMP box showing its IP, processor and kernel, a runtimes row listing php 8.4.26, node 24.21.0, redis 7.0.15, nginx 1.24.0, MySQL 8.0.46, MongoDB 8.0.32 and PostgreSQL 16.15, an "All 8 services running" badge, and live CPU, memory, swap, disk and load tiles

  • Databases appears wherever the box runs applications on the host — every stack except Docker. A container server says no: an application that needs a database brings one as a container, and the panel's own storage is SQLite regardless.
  • Docker appears everywhere, but on a non-container stack it only explains itself.
  • Node.js appears on every stack, including LEMP — and that is on purpose. A LEMP box hosts no Node sites, but Node is a build tool for PHP ones: the panel's own build-command placeholder is npm ci && npm run build, offered on any git-deployed site. Hiding the screen wherever Node sites are not served would take it away from every Laravel site that builds its assets.
  • PHP follows the opposite rule: the screen is shown where the box serves PHP sites, so LEMP, LAMP and OLS have it and MERN and Docker do not — even though PHP is installed on all five.

The OSS Panel sidebar on a MERN server, listing Dashboard, Applications, Databases, System Users, Firewall, Cron Jobs, Fail2ban, System Logs, Services, Node.js, Docker, Settings, Disk Cleaner, Backups, Activity Log and Server Sync — with no PHP entry between Services and Node.js

The Docker screen on a LEMP server showing an empty state that reads "Not a container server — This server doesn't host containers, so it has no Docker networks or volumes."

The same rule hides application types. A site type whose serving profile this box cannot host is removed from the create catalog entirely rather than shown greyed out — see Application types for the full catalog and what each stack leaves in it.

The same catalog on two stacks

An OpenLiteSpeed server serves PHP and static, so its catalog is the PHP one — 13 types:

The create-application catalog on an OpenLiteSpeed server with the All category selected, showing thirteen types: From Git repo, Nextcloud, phpMyAdmin, PrestaShop, WordPress, Akaunting, Blank PHP site, Craft CMS, Joomla, Mautic, Moodle, Statamic and Static site

A MERN server serves Node and static, so the same screen offers five — and the CMS category disappears with them, because nothing is left in it:

The create-application catalog on a MERN server with the All category selected, showing five types — n8n, Uptime Kuma, Node-RED, NodeBB and Static site — and category tabs reading Popular, Development, Tools, Productivity and All, with no CMS tab

Static site is the only type on both: it is the one profile every stack except Docker can serve.

A server the panel did not build

A box adopted from another panel has no recorded stack. The panel treats that as unknown, not as nothing: it offers PHP, Node and static, because a migrated server is certainly already hosting something and answering "hosts nothing" would empty its catalog on a working machine.

If the guess is wrong, record the truth once:

cd /var/www/panel/backend
php artisan server:record-stack lemp   # or lamp | ols | mern | docker

How the web server is detected

Normally there is nothing to detect — the installer writes the record and the panel reads it. Detection only runs on a server nobody recorded, and it has one rule worth knowing: a running unit beats a leftover config directory.

apt remove apache2 does not delete /etc/apache2, so a box running OpenLiteSpeed with a purged Apache can still look like an Apache server to anything that only checks for directories. When two candidates exist, the panel asks systemd which one is actually running.

A recorded stack is never silently overruled

If the record says Apache and the box plainly runs OpenLiteSpeed, the panel corrects itself only when the recorded web server is not installed at all and exactly one supported web server is running. Anything less clear-cut is left alone and reported by System health instead, with the server:record-stack command that settles it. Quietly writing vhosts for a web server nobody chose would be the worse bug.

OpenLiteSpeed: what changes

OLS is the stack that differs most, because it does not use PHP-FPM at all. It runs LSPHP — a different interpreter build, with different packages, different paths, and no per-version systemd service.

Per-site isolation works, but differently

On nginx and Apache each site gets its own PHP-FPM pool and its own socket. On OpenLiteSpeed each site gets its own external app: its own LSAPI socket, its own processor name, and extUser set to that site's system user.

Both arrive at the same place — one site's PHP cannot read another site's .env — by different means.

Both stacks refuse the unsafe configuration

PHP-FPM will not start a pool with no user =, so the mistake is impossible there. OpenLiteSpeed has no equivalent backstop: a vhost with no extUser is perfectly valid and runs the site's PHP as the server's own account, nobody — which every other site would also fall back to, giving the whole box one identity. So the panel checks first and refuses to write an OpenLiteSpeed vhost for an application that has no system user.

This is why the create form insists on a system user and offers to generate one — that account is what the vhost will run the site's PHP as:

The Application details step of the create form on an OpenLiteSpeed server, with Name set to demo-ols, Domain set to demo-ols.example.test, a hint reading "Point this domain's A record to: 203.0.113.10", "Generate a new system user" selected, and a Username of demo-ols-2 beside a masked generated password

Sites created by the panel are isolated from the start. Sites adopted from elsewhere, or created before isolation shipped, can be brought in line:

cd /var/www/panel/backend
php artisan php:isolate-all

What the panel writes for an application called demo-ols looks like this — its own processor, its own socket, and its own user:

/usr/local/lsws/conf/vhosts/demo-ols/vhconf.conf
extprocessor lsphp84-demo-ols {
  type        lsapi
  address     uds://tmp/lshttpd/lsphp84-demo-ols.sock
  path        /usr/local/lsws/lsphp84/bin/lsphp
  extUser     demo-ols
  extGroup    demo-ols
  env         PHP_INI_SCAN_DIR=:/home/demo-ols/demo-ols/.panel/php
}

The socket is named after the application's slug, not its domain, so renaming a domain does not strip the site of its interpreter. OpenLiteSpeed confirms the switch in its own log when the worker starts:

[LocalWorker::workerExec] Config[lsphp84-demo-ols]: suExec uid 1001 gid 1001
  cmd /usr/local/lsws/lsphp84/bin/lsphp, final uid 1001 gid 1001

A new site answers on HTTP before it answers on HTTPS

Until you issue a certificate for it, an OpenLiteSpeed site's vhssl block points at the panel's reject certificate (CN=unmatched.invalid), so HTTPS returns 403 while HTTP already serves the site. That is deliberate: an un-certificated vhost fails closed rather than answering under the panel's own certificate. Issue SSL from the application's Domains & SSL screen and the block is rewritten with the real certificate.

.htaccess is mostly not read

OpenLiteSpeed only re-reads .htaccess after a restart, so the panel does not rely on it. Rewrite rules and the 8G firewall rules are rendered as directives inside each site's vhconf.conf instead, from the same rule source the Apache version uses.

One site type is the exception: WordPress. LiteSpeed Cache talks to the OpenLiteSpeed cache module through .htaccess and nothing else, so for a WordPress application the panel does treat that file as live. Changing an application's site type changes this behaviour with it.

This is why an .htaccess you drop into a non-WordPress site on OLS appears to do nothing: it is not being read. Put the rule in the application's settings so the panel writes it into the vhost.

Extensions: a shorter list, and a trap

The LSPHP base install is deliberately smaller than the PHP-FPM one:

Packages installed
PHP-FPMfpm, cli, common, mysql, pgsql, curl, mbstring, xml, zip, gd, intl, bcmath, soap, sqlite3, redis, igbinary, opcache
LSPHPcommon, mysql, pgsql, curl, intl, sqlite3, redis, igbinary, opcache

No capability is lost. mbstring, xml, zip, gd, bcmath and soap are compiled into the LSPHP interpreter — they load on a box with none of those packages installed.

The trap is that LiteSpeed still names them. lsphp84-gd resolves as a package the index knows and apt refuses to install: it looks real in a search and kills the transaction anyway. So the panel checks every extension package with apt-cache policy before installing and skips the ones with no installation candidate, rather than letting one bad name take down the whole install.

The PHP screen filtered to "mongo", showing a single extension row — mongodb, "Connects to MongoDB" — switched off, above a collapsed "Built into PHP (16)" section

Do not assume extension parity between stacks

The screenshot above is a LEMP server, where mongodb is one of the 80 extensions on offer. An OpenLiteSpeed server of the same version offers 21, and mongodb is not among them — what LSPHP can install is whatever LiteSpeed publishes as lsphpXX-<name> for your PHP version, which is not the set Ubuntu ships. If an application needs an extension, check the Extensions list on the OpenLiteSpeed server itself.

Measured on an OpenLiteSpeed server running the same version: 8 of the 21 are installed (curl, igbinary, intl, mysql, opcache, pgsql, redis, sqlite3) and the other 13 are available to install — apcu, dbg, imagick, imap, ldap, mailparse, memcached, msgpack, pear, pspell, snmp, sybase and tidy.

Extensions cannot be switched off on OpenLiteSpeed

The Extensions list behaves differently here. Every installed extension reads Always on instead of carrying a toggle, and the screen says so: "On OpenLiteSpeed an installed extension is always on. You can install one here, but not switch it off." To stop using one, uninstall it.

The same screen also counts Built into PHP (47) on LSPHP against 16 on a PHP-FPM box — the compiled-in set described above, shown as a number.

The Extensions panel on an OpenLiteSpeed server reading "8 of 21 turned on" and "On OpenLiteSpeed an installed extension is always on. You can install one here, but not switch it off", listing curl, igbinary, intl, mysql, opcache, pgsql and redis each marked "Always on" with no toggle, above a collapsed "Built into PHP (47)" section

Everything else about the PHP screen — installing a version, choosing the default, editing php.ini — works the same on every stack.

The PHP screen on a LEMP server: an Install version button, a PHP 8.4 card badged Default and Supported listing the three applications that use it, and an Extensions tab reading "15 of 80 turned on"

Caveats

  • The web server, not the stack, decides the vhost format. Two lemp and mern servers both run nginx and get the same vhost layout; what differs is what they are allowed to serve.
  • Changing the server's default PHP version does not move your applications — each one keeps its own. That is true on every stack.
  • Docker and MERN servers still have PHP installed, but they hide the PHP screen. The tab is gated on whether the box serves PHP sites, not on whether PHP exists — so it is present on LEMP, LAMP and OLS, and absent on MERN and Docker even though the panel itself is running on PHP there.
  • OpenLiteSpeed supports the 8G web firewall, same rule set as Apache; see Web firewall.

On this page