CloudLinux OS components
- Reseller limits
- LVE-Stats 2
- CageFS
- MySQL Governor
- PHP Selector
- Python Selector
- Ruby Selector
- Node.js Selector
- Apache mod_lsapi PRO
- NGINX lsapi module
- Additional integration components
- Apache suexec module
General information and requirements
LVE-Stats 2
General information and requirements
Why is it needed?
- Old LVE-statistics store averages as integer numbers, as % of CPU usage. If user used 100% of CPU for 1 second within an hour, it is only 1-2% for a minute, and 0 for 5 minutes. Data in old LVE-statistics is aggregated to 1-hour intervals. So, such peak load will noExat be recorded and we need to store data with much higher precision.
- 100% CPU usage in old lve statistics means “all cores”. On 32 core servers usage is not visible for most users (as they are limited to 1 core).
- Old LVE-statistics does not provide a way to determine a cause of LVE faults, i.e. what processes are running when user hits LVE limits.Example
- Notifications in old LVE-statistics are not accurate because they are based on average values for CPU, IO, IOPS.
- Old LVE-statistics functionality is hard to extend.
Major improvements and features
- increased precision of statistics;
- CPU usage is calculated in terms of % of a single core (100% usage means one core);
- lvestats-server emulates and tracks faults for CPU, IO, IOPS;
- lvestats-server saves “snapshots” of user’s processes and queries for each “incident” - added new lve-read-snapshot utility;
- improved notifications about hitting LVE limits (more informative and without false positives);
- implemented ability to add custom plugins;
- MySQL and PostGreSQL support;
- more pretty, scalable, interactive charts;
- snapshots include HTTP-requests.
Note
mod_proctitle
has to be enabled for HTTP request collection to be available
What features will be implemented in the future?
- Notifications for control panels other than CPanel.
- Burstable Limits/server health: We are monitoring server health ( LA , memory , idle CPU ) and automatically decreasing/increasing limits based on server health.
- Reseller Limits: plugin would analyze usage per group of users (reseller’s usage), and do actions.
- Suspend/notify plugin: would detect that user is being throttled for 10 minutes, and suspend him (just because), or notify, or increase limits.
Installation and update
To install, please execute:
yum install lve-stats
To update:
yum update lve-stats
Settings of old lve-stats (ver. 0.x) are imported automatically on the first install/update of a new lve-stats package.
SQLite database file is located in /var/lve/lvestats2.db
, data from old lve-stats (ver. 0.x) are being migrated automatically in the background. Migrating process can last 2-8 hours (during this time lags are possible when admin is trying to check statistics, at the same time users will not be affected). Migrating the latest 30 days, SQLite DB stable migration is provided.
Currently, the new lve-stats supports all databases available in CloudLinux OS.
Note
You can also use LVE-stats 2 CLI
Downgrade
If you have any problems after update, downgrade lve-stats2 to the previous stable version by running:
yum downgrade lve-stats
and contact CloudLinux OS support at https://cloudlinux.zendesk.com/hc/requests/new
Note
You may need to rename *.rpmsave
files to original ones in order to restore settings for old lve-stats (/etc/sysconfig/lvestats
, /etc/sysconfig/cloudlinux-notify
).
Note
You can also use LVE-stats 2 CLI
Configuration
The main configuration file /etc/sysconfig/lvestats2
contains the following options:
db_type
- selects appropriate database type to use;connect-string
- connection string for PostGreSQL and MySQL database, has the following form:connect_string = USER:PASSWORD@HOST[:PORT]/DATABASE
Default port is used for specific database, if port is not specified (typical port is 3306 for MySQL and 5432 for PostGreSQL). Connection string is not used for sqlite database.
server_id
- sets the name of the server (at most 10 characters). This option is to use with centralized database ( PostGreSQL or MySQL). For use with sqlite database, value of this option should be "localhost" (without quotes).plugins
– path to directory containing custom plugins for lve-stats (default path/usr/share/lve-stats/plugins
).db_timeout
- period of time to write data to database (in seconds); default value is 60 seconds.timeout
- timeout for custom plugins (seconds). If plugin execution does not finish within this period, plugin is terminated. Default value is 5 seconds.interval
- duration of one cycle of lvestats-server (seconds). This should be less than total duration of execution of all plugins. Default value is 5 seconds. Increasing this parameter makes precision of statistics worse.keep_history_days
- period of time (in days) to keep history in th database. Old data is removed from the database automatically. Default value is 30 days.mode
– sets compatibility output mode (compatibility with older lveinfo version- Value
v1
enables compatibility with old version of lveinfo. - Value
v2
enablesextended
output mode, but can break LVE plugins for control panels (statistics in LVE Manager, Resource Usage, etc). Support ofv2
mode will be added to LVE plugins in the recent future. When mode parameter is absent, later version of lveinfo is implied.
- Value
disable_snapshots
- disable snapshots and incidents. Possible values:true
false
hide_lve_more_than_maxuid
- disable displaying of lve ids more than max uid in resource usage. Possible values:true
false
use_big_uids
- the option is available from lvestats version3.0.14-1
. It allows using the user uids more than 109 and up to 231-2 (2 147 483 646). Top border is the biggest value whichkmodlve
can use as LVE ID. You should recreate lvestats database by commandlve-create-db --recreate
if you change the option's value fromfalse
totrue
. Possible values:true
false
Configuration files for plugins are located in /etc/sysconfig/lvestats.config
directory.
/etc/sysconfig/lvestats.config/SnapshotSaver.cfg
contains the following options:
period_between_incidents
- the minimal interval of time between incidents (in seconds). If minimal interval of time between LVE faults is greater than value specified, than new "incident" will begin and new snapshots will be saved. Default value is 300 seconds.snapshots_per_minute
- the maximum number of snapshots saved per minute for specific LVE id (default is2
).max_snapshots_per_incident
- the maximum number of snapshots saved for one "incident". Default is10
.litespeed
- enable or disable data import from LiteSpeed, default isauto
(autodetect);On
|on
|1
- force use litespeed;Off
|off
|0
- force use apache
/etc/sysconfig/lvestats.config/StatsNotifier.cfg
contains the following options:
NOTIFY_ADMIN
– enables notification for admin (Y/N
, defaultN
);NOTIFY_RESELLER
– enables notification for reseller (Y/N
, defaultN
);NOTIFY_CUSTOMER
- enables notification for customers (Y/N
, defaultN
);NOTIFY_INCLUDE_RESELLER_CUSTOMER
–Y
=notify all users,N
=notify only hoster's users (whos reseller is root), default =N
;NOTIFY_CPU
– notify about CPU faults when customer hits 100% of his CPU limit (Y/N
, defaultN
);NOTIFY_IO
- notify about IO faults when customer hits 100% of his IO limit (Y/N
, defaultN
);NOTIFY_IOPS
- notify about IOPS faults when customer hits 100% of his IOPS limit (Y/N
, defaultN
);NOTIFY_MEMORY
- notify about memory faults (Y/N
, defaultN
);NOTIFY_EP
– notify about entry processes faults (Y/N
, defaultN
);NOTIFY_NPROC
– notify about number of processes faults (Y/N
, defaultN
);NOTIFY_MIN_FAULTS_ADMIN
– minimum number of faults to notify admin (default1
);NOTIFY_MIN_FAULTS_USER
– minimum number of faults to notify customer (default1
);NOTIFY_INTERVAL_ADMIN
– period of time to notify admin (default12h
);NOTIFY_INTERVAL_USER
– period of time to notify customer (default12h
);NOTIFY_FROM_EMAIL
- sender email address. For example:NOTIFY_FROM_EMAIL=main_admin@host.com
;NOTIFY_FROM_SUBJECT
- email message subject. For example:NOTIFY_FROM_SUBJECT=Message from notifier
REPORT_ADMIN_EMAIL
- custom email for admin reporting. For example:REPORT_ADMIN_EMAIL=report_email@host.com
NOTIFY_CHARSET_EMAIL
– charset type for email. Available for lve-stats-2.9.4-1 and later. Default isus-ascii
. For example:NOTIFY_CHARSET_EMAIL=utf-8
. If your email templates include non-Latin letters, it is recommended to use the UTF-8 encoding.
These values can also be set using cloudlinux-config CLI utility
Templates of notifications are located here:
/usr/share/lve/emails/en_US/admin_notify.txt
/usr/share/lve/emails/en_US/reseller_notify.txt
/usr/share/lve/emails/en_US/user_notify.txt
/usr/share/lve/emails/en_US/admin_notify.html
/usr/share/lve/emails/en_US/reseller_notify.html
Note
Notifications about LVE faults are implemented for CPanel, Plesk, and DirectAdmin.
After changing any options above, please restart lvestats service:
service lvestats restart
/etc/logrotate.d/lvestats
- configuration file for /var/log/lve-stats.log rotation
Note
You can also use LVE-stats 2 CLI
LVE-stats2 and DB servers compatible work setup
- LVE-stats2 and MySQL DB server compatible work setup
- LVE-stats2 and PostgreSQL DB server compatible work setup
- Customize LVE-stats2 notifications
LVE-stats2 and MySQL DB server compatible work setup
Note
Run all the commands below under root.
1. MySQL server setup
If MySQL Server is not installed, then install it according to control panel documentation.
For non-panel system:
CloudLinux OS 6
yum install mysql mysql-server service mysqld start chkconfig mysqld on
CloudLinux OS 7
yum install mariadb mariadb-server systemctl start mariadb.service systemctl enable mariadb.service
2. Database setup
Run MySQL administrative utility:
mysql
.In utility run the commands:
- creating server DB. Also, check Note below.
CREATE DATABASE db_lvestats2;
- creating a user for LVE Stats 2 server to work under. Also, check Note below.
CREATE USER 'lvestats2'@'localhost' IDENTIFIED BY 'lvestats2_passwd';
- granting all the privileges for all DB tables to the user. Use the username and DB name from the points above.
GRANT ALL PRIVILEGES ON db_lvestats2.* TO 'lvestats2'@'localhost';
- refreshing privileges information.
FLUSH PRIVILEGES;
- Exit administrative utility
(Ctrl+d)
.
Note
DB name, username and their passwords above are given for an example - you can use any of your choices. Using old DB from LVE Stats version 1 is also acceptable as LVE Stats2 uses different tables and the old information will not be corrupted.
3. LVE-stats2 setup
- Stop LVE Stats 2 server by running the command:
service lvestats stop
- In server configuration file
/etc/sysconfig/lvestats2
, edit the following options:db_type = mysql
connect_string = lvestats2:lvestats2_passwd@localhost/db_lvestats2
Note
connect_string
option value is used in format: user:pass@host/database
. Username, password and DB name must be the same as in point 2 of Database Setup above.
- After making changes in configuration files run:
/usr/sbin/lve-create-db
For DB primary initialization (creating tables, indexes, etc). There is no need to create anything in the DB manually.
- When done, restart server by running:
service lvestats restart
4. Additional security settings
If you need to provide access to LVE Stats information utilities (lveinfo
, lvechart
, lve-read-snapshot
) for different users, then we recommend creating one more DB user with read-only privilege to guarantee information security. It can be done by running the following commands in administrative utility:
- creating a user (check Note above)
CREATE USER 'lvestats2_read'@'localhost' IDENTIFIED BY 'lvestats2_read_passwd';
- granting read-only privilege to the user
GRANT SELECT ON db_lvestats2.* TO 'lvestats2_read'@'localhost';
- refreshing privileges information
FLUSH PRIVILEGES;
If LVE Stats2 server is set correctly (see information below), the information utilities will work under this user.
If you need to provide access to information utilities to other users, then in order to guarantee information security you should do the following:
- Assign permission 600 to the main configuration file (
/etc/sysconfig/lvestats2
), so that it could be read only by LVE Stats 2 server and by utilities that run under root. - Copy
/etc/sysconfig/lvestats2
to/etc/sysconfig/lvestats2.readonly
, assign permission 644 to the new file, so that it could be read by any user but could only be changed by root. - In
/etc/sysconfig/lvestats2.readonly
file, in the lineconnect_string
, specify DB user with read-only permission, created above.
These steps allow hiding main DB user username/password from other system users.
If there is no need in such access differentiation, then /etc/sysconfig/lvestats2
file access permission should be 644, so that it could be read by all users and could be changed only by root.
5. Using special characters in database password
Since scheme ://user:password@host[:port]/database_name
URI is used in connect_string
config option, then usage of special characters in user DB password is not allowed.
To use special symbols in the password, it must be converted to escape-sequence. You can convert a password to escape-sequence in a console as follows:
echo -n '[You_P@$$]:' | perl -MURI::Escape -ne 'print uri_escape($_)."\n"'
%5BYou_P%40%24%24%5D%3A
Or replace the symbols manually:
! # $ & ' ( ) * + , / : ; = ? @ [ ]
%21 %23 %24 %26 %27 %28 %29 %2A %2B %2C %2F %3A %3B %3D %3F %40 %5B %5D
After that сonnect_string
will look as follows:
сonnect_string=lvestats2:%5BYou_P%40%24%24%5D%3A@localhost/db_lvestats2
LVE-stats2 and PostgreSQL DB server compatible work setup
Note
Run all the commands below under root.
1. PostgreSQL server installation and setup
PostgreSQL installation and initialization
For control panels use proper documentation for installation on the links: сPanel, Plesk.
For non-panel CloudLinux OS, run the following commands:
- CloudLinux OS 6
yum install postgresql-server postgresql service postgresql initdb service postgresql start chkconfig postgresql on
- CloudLinux OS 7
yum install postgresql-server postgresql postgresql-setup initdb systemctl start postgresql systemctl enable postgresql
Setup
In
/var/lib/pgsql/data/pg_hba.conf
config file change user authentication mode. Add the following lines (place before all other authentication parameters):# IPv4 local connections for lve-stats-2.x host dblvestat all 127.0.0.1/32 password # IPv6 local connections for lve-stats-2.x host dblvestat all ::1/128 password
These lines enable user authentication by the password for IP4/IP6 connections. You can set other modes if needed.
Apply config changes by running:
service postgresql restart
2. DB for LVE-stats-2.x - creating and setup
- Run standard PostgreSQL psql administrative utility:
sudo -u postgres psql postgres
OR for сPanel
psql -w -U postgres
In utility run:
creating server DB. Also, check Note below.
CREATE DATABASE dblvestat;
creating a user for LVE Stats 2 server to work under. Also, check Note below.
CREATE USER lvestat WITH password 'passw';
granting lvestat user all privileges for work with dblvestat DB.
GRANT ALL privileges ON DATABASE dblvestat TO lvestat;
exit
psql
utility:\q
OR alternatively:
Ctrl+d
Note
DB name, username and their passwords above are given for an example - you can use any of your choices. Using old DB from LVE Stats version 1 is also acceptable as LVE Stats 2 uses different tables and the old information will not be corrupted
3. LVE-stats-2.x setup
- Stop lve-stats2 server by running:
service lvestats stop
- In server config file
/etc/sysconfig/lvestats2
edit options for connecting to DB:
db_type = postgresql
connect_string=lvestat:passw@localhost/dblvestat
If DB is going to be used as centralized for multiple hosts then collect_usernames parameter must be changed:
collect_usernames=true
Note
connect_string
option value is of the format: user:pass@host/database
. Username, password and DB name must be the same as in Database Setup section above.
- After making changes in configuration files, for DB primary initialization (creating tables, indexes, etc), run:
/usr/sbin/lve-create-db
- There is no need to create anything in the DB manually. When done, restart server by running:
service lvestats restart
4. Additional security settings
If you need to provide access to LVE Stats information utilities (lveinfo
, lve-read-snapshot
) for other users (or if CageFS is disabled), then in order to guarantee DB security the following steps are required:
- Create a DB user with read-only permission:
CREATE USER lvestat_read WITH password 'passw';
GRANT CONNECT ON DATABASE dblvestat to lvestat_read;
\connect dblvestat;
GRANT SELECT ON lve_stats2_history, lve_stats2_history_gov, lve_stats2_history_x60, lve_stats2_incident, lve_stats2_servers, lve_stats2_snapshot, lve_stats2_user TO lvestat_read;
Assign root ownership and permission 600 to the main configuration file (
/etc/sysconfig/lvestats2
), so that it could be read only by LVE Stats 2 server and by utilities that run under root.Copy
/etc/sysconfig/lvestats2
to/etc/sysconfig/lvestats2.readonly
, assign permission 644 to the new file, so that it could be read by any user but could be changed only by root.In
/etc/sysconfig/lvestats2.readonly
file, in the lineconnect_string
, specify DB user with read-only permission, created above.These steps allow hiding main DB user username/password from other system users.
If there is no need in such access differentiation, then
/etc/sysconfig/lvestats2
file access permission should be 644, so that it could be read by all users and could be changed only by root.When done, restart server by running:
service lvestats restart
5. Using special characters in database password
Since scheme ://user:password@host[:port]/database_name
URI is used in connect_string
config option, then usage of special characters in user DB password is not allowed.
To use special symbols in the password, it must be converted to escape-sequence. You can convert a password to escape-sequence in a console as follows:
echo -n '[You_P@$$]:' | perl -MURI::Escape -ne 'print uri_escape($_)."\n"'
%5BYou_P%40%24%24%5D%3A
OR replace the symbols manually:
! # $ & ' ( ) * + , / : ; = ? @ [ ]
%21 %23 %24 %26 %27 %28 %29 %2A %2B %2C %2F %3A %3B %3D %3F %40 %5B %5D
After that сonnect_string
will look as follows:
сonnect_string=lvestats2:%5BYou_P%40%24%24%5D%3A@localhost/db_lvestats2
Customize LVE-stats2 notifications
Jinja2 is used as a template engine for the notifications.
The templates for notifications are located in /usr/share/lve/emails/LOCALE
, where LOCALE
is the directory with localization name (language codes are formed according to ISO 639-1 and ISO 639-2).
By default the templates for English are set: /usr/share/lve/emails/en_US.
.
/usr/share/lve/emails/en_US
contains the following templates:
admin_notify.html
admin_notify.txt
for administrator;reseller_notify.html
reseller_notify.txt
for reseller;user_notify.txt
for user.
Starting from lve-stats-4.1.2
, it allows server administrators to use their own lvestats notifier email notification templates.
To use the custom templates, place them and the locales.json
file to the /etc/cl.emails.d/LOCALE
directory. File names are the same as in general /etc/cl.emails.d/LOCALE
file.
If the /etc/cl.emails.d/LOCALE
doesn't exist or doesn't contain the templates, you can use the /usr/share/lve/emails/LOCALE
directory, as it was in previous versions of lve-stats.
Please do not edit the templates in the the /usr/share/lve/emails
and place the new updated templates in the /etc/cl.emails.d
directory.
The notification is formed as Multipart content type RFC1341(MIME).
The plain text is taken from the .txt
files, html version - from the .html
template.
In case when only one template is present (.txt
or .html
) the notification is sent as a Non-multipart content type notification.
It is better to use Multipart content type notifications because when a mail client can not display an html-format message, then it will be displayed as plain text version.
To localize notifications, copy standard templates into directory with the proper locale name and translate the template. Also you can customize the main template making proper changes into it.
The list of variables that can be used in the template:
Variable | Example | Description |
TONAME | Customer | Notification receiver user name. Taken from profile in the control panel, by default - Customer for user, Administrator for administrator, Reseller for reseller. |
TOMAIL | support@cloudlinux.com | Notification receiver email address. |
DOMAIN | wordpress.test247.cloudlinux.com | Main domain. Available only for user. |
LOCALE | en_US | Locale in which the notification is sent. Available only for user. |
RESELLER | root | User reseller. Available only for user. |
PERIOD | 12 hours | Verification and notification sending period. |
LOGIN | wordpress | User login in the system. |
ID | 500 | User ID in the system. |
lPMem lEP PMemF lVMem anyF IOf VMemF lCPU aIOPS aEP aPMem IOPSf lIO lIOPS aIO EPf aCPU aVMem NprocF aNproc lNproc CPUf | See description in lveinfo --help output. Available only for users | |
STATS_HTML | html table with the list of users that exceeded limits. Available for administrator and reseller. | |
STATS | ASCII - table with the list of users that exceeded limits. Available only for admins and resellers. |
Sender’s email address by default is administrator email address from control panel settings (root@{hostn_name}
if there is no email in the control panel).
It can be changed with NOTIFY_FROM_EMAIL
option in the config /etc/sysconfig/lvestats.config/StatsNotifier.cfg
For example:
NOTIFY_FROM_EMAIL=support@hostername.com
To apply changes restart lve-stats
service:
service lvestats restart
for CloudLinux OS 7
systemctl restart lvestats.service
Default subject is Hosting account resources exceeded
. It can be changed for each template (and for localized templates as well). To change subject, in the very beginning of the file (no blank lines allowed in the beginning of the template) add the field Subject:
, leave two blank lines after it and add template body.
Customized subjects can be taken only from the templates with the resolution *.txt
(admin_notify.txt
, reseller_notify.txt
, user_notify.txt
). Changes apply without lvestats
restart.
For backward compatibility the subject can be also changed with the key NOTIFY_FROM_SUBJECT
in the config /etc/sysconfig/lvestats.config/StatsNotifier.cfg
.
Customized subjects have the higher priority than the key NOTIFY_FROM_SUBJECT
.
Example for the file user_notify.txt
Subject: Customized subject example
Dear {{TONAME}},
Your {{DOMAIN}} web hosting account exceeded one or more of its resources within the last {{PERIOD}}.
{% if epf %}Exceeded the maximum of {{lep}} concurrent website connections. Your website was not available {{epf}} times because of this problem.
{% endif %}{% if pmemf %}Exceeded the physical memory limit of {{lpmem}}KB. Your website was not available {{pmemf}} times because of this problem.
{% endif %}{% if vmemf %}Exceeded the virtual memory limit of {{lvmem}}KB. Your website was not available {{vmemf}} times because of this problem.
{% endif %}{% if nprocf %}Exceeded the number of processes limit of {{lnproc}}. Your website was not available {{nprocf}} times because of this problem.
{% endif %}{% if cpuf %}You reached limit of {{lcpu}} of total server CPU usage {{cpuf}} times. Your website was forced to load slower to reduce its CPU usage.
{% endif %}{% if iof %}You reached limit of {{lio}}KB/s disk io rate {{iof}} times. The disk io speed for your account was slowed as a result of this problem.
{% endif %}{% if iopsf %}You reached limit of {{liops}} I/O operations {{iopsf}} times. The disk io speed for your account was slowed as a result of this problem.
{% endif %}
To view full details about your web hosting account's resource usage, including the time of each incident listed above, please click the link below and log into your cpanel hosting control panel, then click the "Resource Usage" link under the "Logs and Statistics" section.
http://{{DOMAIN}}:2083
If your account is regularly exceeding it's available resources, please consider upgrading to a higher level hosting plan that includes more resources. If you have any questions or need help with anything, just reply to this email and let us know.
Sincerely,
Your Friendly Web Hosting Support Team
Note
The email template should be in the UTF-8 encoding. The other encodings are not supported.
Starting from lve-stats v. 3.0.15-1, it allows to localize the words that before were imported directly from the lve-stats program code and couldn't be changed.
The email template looks like follows:
Dear {{TONAME}},
Following accounts experienced issues in the past {{PERIOD}}{% if HOSTNAME is defined %} on host {{HOSTNAME}}{% endif %}
{{STATS}}
Sincerely,
Your Friendly Web Hosting Support Team
Before, the {TONAME}
was replaced with “Administrator”/”Reseller”/”Customer” according to the type of the addressee. The {PERIOD}
was replaced with the duration of the period during which the limits faults were detected. The period duration includes the words "days"/"hour"/"minutes"/"seconds".
In the new version, in order for the lve-stats notifier to include these words in the letter in the language corresponding to the addressee locale, you should create a file for the required locale /usr/share/lve/emails/<encoding_name>/locale_defines.json
with the following content:
{
"NOTIFY_FROM_SUBJECT": "Your server has lve-stats faults",
"PERIOD": {
"days": "days", "hours": "hour(s)", "minutes": "minutes", "seconds": "seconds"
},
"TONAME": {
"admin": "Administrator", "reseller": "Reseller", "customer": "Customer"
}
}
The file format should be JSON, and the file encoding should be UTF-8. If this file is found and successfully read, the words from it will be used in emails. In case of any file reading/parsing error, a corresponding message will be written in the lve-stats log, and the contents of the file will be completely ignored. If a key in the JSON file content is missing, then lve-stats notifier uses the word contained in the body of the program (just like in previous lve-stats versions). Also, this file allows you to override/localize the subject of the email.
It should be noted that this override of the subject line is the highest priority. I.e., if you want to use the subject from the configuration file /etc/sysconfig/lvestats.config/StatsNotifier.cfg
, then do not specify the NOTIFY_FROM_SUBJECT
key in the locale_defines.json
.
Plugins
- Creating a plugin for LVE-stats2
- Introduction
- Server plugin arrangement
- Plugin configuration
- Types of plugins
- Examples of plugins
- File info and format for /var/lve/info file
LVE-stats2 comes with a set of generic plugins:
Plugin Name | Order | Default | Period (seconds) | Description |
LVECollector | 1000 | Y | 5 | Collects usage/limits data from /proc/lve/list |
CPUInfoCollector | 2000 | Y | 5 | collents info about CPU - /proc/cpuinfo |
LVEUsernamesCollector | 3000 | Y | 3600 | collects usernames & user ids to match uid <-> lve id later on |
LVEUsageAnalyzer | 4000 | Y | 5 | analyzes usage of LVE |
LveUsageAggregator | 5000 | Y | 60 | aggregates data by time periods |
DBGovSaver | 6000 | Y | 5 | Saves data about database governor |
FileSaver | 7000 | Y | 5 | Saves LVE data into /var/lve/info |
CloudLinuxTopFileSaver | 8000 | Y | 60 | saves data used by cloudlinux-top to /var/lve/cloudlinux-top.json |
DBSaver | 9000 | Y | 60 | save LVE data to database |
DbUsernamesSaver | 10000 | Y | 3600 | saves users name to database |
DBSaverX60 | 11000 | Y | 3600 | saves aggregated hourly data into database |
SnapshotSaver | 12000 | Y | 30 | collects & saves snapshots data |
StatsNotifier | 13000 | Y | varied | notify user/admin based on usage |
HistoryCleaner | 14000 | Y | 3600 | removes old usage |
ResMEMCollector | 1500 | N | 30 | collects physical memory usage from processes RES field instead of /proc/lve/list |
LVEDestroyer | - | N | 5 | destroys LVEs that weren't active for X iterations. Number of iterations is passed from config using iterations variable. iterations=0 means plugin disabled |
To enable non-default plugin, copy or link it to /usr/share/lve-stats/plugins
directory.
For example to enable ResMEMCollector
plugin, do:
ln -s /usr/share/lve-stats/plugins.other/res_mem_collector.py /usr/share/lve-stats/plugins/
service lvestats restart
Creating a plugin for LVE-stats2
Introduction
LVE Stats 2 complex has scalable architecture, which allows to connect custom plugins.
LVE Stats server searches for plugins in the directory which is specified with plugins parameter of server’s /etc/sysconfig/lvestats2 configuration file. Default directory is /usr/share/lve-stats/plugins.
Each plugin must be of a Python class, must be written in Python language and its file must have .py extension. Files with all other extensions will be ignored. For normal server work access permission 400 is enough; owner – root .
Plugin classes can be of the same name, but better not, because classes' names can affect the set of parameters in set_config method. You can find detailed plugins' configuring information below, in appropriate chapter.
Plugin class must contain execute() method, which is invoked by the server every 5 seconds (by default, can be changed by interval parameter of configuration file). Also set_config method (configuration settings) can be available. You can find more info in Plugins Configuration chapter.
Additionally the following attributes can be set (plugin class instance variable):
- order (integer) - defines plugin's position in the server's plugin list, (more info in Servers Plugin Arrangement ).
- timeout (integer or float ) – the longest allowable duration of one launch of the plugin (execute method). Default value of timeout parameter is 5 seconds.
- period (integer) – sets the interval between two launches of execute plugin method in seconds. If not defined, then plugin runs every 5 seconds ( interval parameter in configuration file).
When execute() method of the plugin is invoked, the server creates an attribute now in it, where launch time is recorded. This value is equal to what a standard Python function time.time() returns. All the plugins launched one after another receive the same value of now attribute from the server. now is overwritten before execute() method is invoked.
The previous value of now attribute is not saved by the server. If plugin needs it, it has to save it by itself.
Plugin class can be inherited from LveStatsPlugin class, which is the part of the server itself. This is not obligatory, but inheritance can help to avoid different errors in servers work, particularly if a plugin doesn't contain required execute method.
LveStatsPlugin class is defined in the file: /opt/alt/python27/lib/python2.7/site-packages/lvestats/core/plugin.py .
Server plugin arrangement
When the server starts, it performs the search of plugins in the directory specified in /etc/sysconfig/lvestats2 configuration file. This directory is scanned only when the server starts, therefore if any plugin was added into the directory, the server has to be restarted with the following command:
service lvestats restart.
After successful restart, the plugins are graded and executed ascending by order attribute. If any plugin order attribute is not set, it is considered as a Python language constant sys.maxint (which is usually 9223372036854775807). This in fact means that such plugins will be executed in the last. If any plugins has similar order meanings, their execution order is unpredictable.
The server invokes execute method of all plugins one after another.
When the server invokes execute() method of any plugin, it transmits a data dictionary ( lve_data argument) into plugin. The dictionary is common for all the plugins. Any plugin can read, write and change any data in this dictionary. LVE Stats 2 server doesn't control this area. That is why one must be careful while developing new plugins, in order not to change or corrupt other plugins' data which can break their functionality.
If an exception occurs in execute() method, its text and python stack trace is recorded into server log /var/log/lve-stats and all the changes made to lve_data dictionary before the exception happened are lost.
The keys of the lve_data dictionary are recommended to look like “ PluginName_Key ” , in order the plugins do not corrupt other data accidentally.
Server contains some standard plugins which define and use the following keys in the common dictionary lve_data: LVE_VERSION, stats, old_stats, procs and lve_usage . User plugins can use data from these keys, but it is recommended not to change them if there is no special need, because it can break the next plugins in the execution queue.
Key | Content |
LVE_VERSION | LVE version. The same as console command lvectl lve-version produces. |
stats | Dictionary, that contains lve id’s as keys and LVEStat class objects as values. Every LVEStat object contains values of usages and limits taken from /proc/lve/list file for every LVE Id . Dictionary keys – integer lve id , including 0 for “ default ” LVE. This dictionary is updated on each iteration of lvestats-server (every 5 seconds by default). LVEStat – is a standard server class, it can be imported with the command from lvestats.core.lvestat import LVEStat. The class is described in the file /opt/alt/python27/lib/python2.7/site-packages/lvestats/core/lvestat.py . Here you can find the whole list of data fields and their functions. |
old_stats | stats content from the previous iteration. Before the first iteration – empty dictionary. |
totalHz | When LVE_VERSION is 4, real CPU frequency in Hz multiplied by number of cores. When LVE_VERSION > 4, CPU speed is in conventional units and equals to 1000000000 * cores (1 GHz per core). |
procs | Quantity of CPU cores. |
lve_usages | Contains accumulated LVE statistics for each 5-seconds interval in current minute. Cleared each minute. |
lve_usage | Contains aggregated LVE Statistics for “previous” minute to store to database. Overwritten each minute. |
Each plugin’s instance lifetime is from the moment it was loaded till the server stops working. But if execute() method working time exceeds timeout, the plugin will be terminated and restarted in the next iteration. All changes to the lve_data dictionary will be lost.
During servers graceful shutdown (restart, server shutdown, commands service lvestats stop, service lvestats restart
), each plugin receives SIGTERM signal. This is useful to correctly unload the plugin (terminate all subsidiary processes, save data to files etc.). If a plugin doesn't need to “finalize” its execution before termination, then there's no need to implement this signal handler. Below you can see an example of such handler.
Note
If a plugin implements handler for SIGTERM, then this handler must end with sys.exit(0)
command. Otherwise plugin process will not be terminated correctly and will become orphaned.
Plugin configuration
LVE Stats 2 Server allows to configure each plugin separately.
On initialization stage the server invokes set_config() method of the plugin and locates there a dictionary which contains:
- all parameters from file /etc/sysconfig/lvestats2 (global).
- plugin's individual configuration file parameters (if one exists). Configuration files must be located in /etc/sysconfig/lvestats.config directory, have .cfg extension and be the same format as /etc/sysconfig/lvestats2 . Files in this directory are matched with the plugins by name. For instance, if plugin class is Plugin1_class , then server will try to find and download /etc/sysconfig/lvestats.config/Plugin1_class.cfg. Names are case sensitive. If any plugin doesn't have an individual configuration file, then it's not an error. In this case plugin will just receive parameters from /etc/sysconfig/lvestats2 .
Note
An individual configuration file of every plugin is loaded after server configuration file. That is why if it contains any parameters with names similar to ones of server config, then plugin will use parameters from its individual config rather than server config parameters.
If a plugin doesn't require any configuration to be done, then set_config method can be skipped.
In addition, plugins can use their own configuration methods.
Types of plugins
According to server architecture, plugins can be of the following types:
- collectors
- analyzers
- persistors
- notifiers
Collectors are designed to collect information; analyzers – to analyze it and form some other data on its basis; persistors – to save information from the common dictionary into files, databases, etc.; notifiers - to notify system users about any events.
This division is rather arbitrary. There is an opportunity to execute all the actions on collection, analysis and saving the information in one and only plugin. But at the same time the division into functionally independent parts allows to build flexible and easily configurable system for collecting and processing the data.
Also it is possible to implement the systems of lazy-write, planning of collecting/processing tasks and notifying users about different events.
Examples of plugins
Here is a practical example of a user plugin.
Specification:
To trace specified file size changes. The name of file being traced must be specified in configuration file, which allows to change it without modifying the plugin itself. If file size has been changed, it has to be written as a message into our log. The name of log must be specified in configuration file as well.
File size must be checked with default interval (5 seconds), and log notification must be held once a minute (to avoid resource expend for possibly regular write).
System administrator must receive emails with file size at the moment the email was sent. These notifications must be sent even if the file size hasn’t been changed. Notification emails must be read periodicity from configuration file as well as sender/receiver emails .
As file size check, fixing the result and notification sending must be held with different periods, then it’s impossible to realize all the tasks by means of one plugin. The fact that one minute (60 seconds) is multiple to 5 seconds doesn’t matter in this case, because default period can be changed in server’s configuration file, but the condition of fixing the result once a minute is a part of the specification, which can not be violated. In addition, notification email period is known in advance, as it is specified by user in configuration file.
That is why we realize 4 plugins: collector, analyzer, persistor and notifier.
Collector
Collector's aim is to determine the size of a proper file.
# FSize_watcher_collector.py
# Example plugin for monitoring file size.
# Part 1. Collector
import os
from lvestats.core.plugin import LveStatsPlugin
# Key name
COLLECTOR_KEY = 'FSizeWatcher_fsize'
COLLECTOR_KEY_FILENAME = 'FSizeWatcher_fname'
class FSize_watcher_collector (LveStatsPlugin):
# this plugin should be first in chain
order = 0
# File to monitoring
file_to_monitoring = None
def __init__(self):
pass
# Sets configuration to plugin
def set_config(self, config):
self.file_to_monitoring = config.get('file_to_monitoring', None)
pass
# Work method
def execute(self, lve_data):
try:
# if monitoring file absent, do nothing
if self.file_to_monitoring is None or not os.path.exists(self.file_to_monitoring):
return
# Get file size
stat_info = os.stat(self.file_to_monitoring)
fsize = stat_info.st_size
# Place file name and file size to server data dictionary
lve_data[COLLECTOR_KEY_FILENAME] = self.file_to_monitoring
lve_data[COLLECTOR_KEY] = fsize
except (OSError, IOError):
# file absent or any other error - remove size from dictionary
del lve_data[COLLECTOR_KEY]
Plugin algorithm is extremely simple – file size is read and written into data dictionary. Files name is read from set_config method configuration. If the name is not specified, then None is written into appropriate variable. All the errors are completely ignored (e.g. if specified file doesn't exist or there's no way to read any of it's information).
order attribute is specified as 0 to make this plugin go the first among three. Data collector must always be the first in plugins logical chain, because it provides all the necessary information for the analyzer which goes the next. Specific values of order can be of any kind, but what is important is that when the server starts, all the plugins line up in proper sequence: collector – analyzer – persistor .
In order to make plugin work, we have to create configuration file /etc/sysconfig/lvestats.config/FSize_watcher_collector.cfg with the following content:
# Config file for FSize_watcher_collector plugin
# Please define monitoring file here
# file_to_monitoring = /usr/local/cpanel/logs/error_log
file_to_monitoring = /usr/local/cpanel/logs/access_log
Note that file name FSize_watcher_collector without .cfg extension matches plugin class name.
file_to_monitoring option is read by plugin in set_config method and contains file’s full name for monitoring.
Files for monitoring, suggested in the actual example - /usr/local/cpanel/logs/error_log and /usr/local/cpanel/logs/access_log - are real, these are cPanel control panel logs.
The first file is errors log; the second is appeal log, is refreshed during common work with panel (e.g. if user email address is changed).
Errors log tracking is more important, but appeal log monitoring allows to illustrate plugins work more in details, because it is refreshed more often.
Note that plugin can monitor one file only.
Analyzer
Analyzer decides if the file's size has changed and gives a command to persistor to refresh log.
# FSize_watcher_analyzer.py
# Example plugin for monitoring file size.
# Part 2. Analyzer
from lvestats.core.plugin import LveStatsPlugin
# Key name from collector plugin
COLLECTOR_KEY = 'FSizeWatcher_fsize'
# Key name 1 for saver plugin
SAVER_KEY = 'FSizeWatcher_fsize_to_store'
# Key name 2 for saver plugin
SAVER_DATA_PRESENCE = 'FSizeWatcher_fsize_present'
class FSize_watcher_analyzer (LveStatsPlugin):
# this plugin should be second in chain
order = 1
# Last file size
file_last_size = 0
# Plugin run period in secondsperiod = 60
def __init__(self):
pass
# work method
def execute(self, lve_data):
# Default setting for saver
lve_data[SAVER_DATA_PRESENCE] = 0
# Check presence data
if COLLECTOR_KEY not in lve_data:
return
# Get file size from server data dictionary
fsize = lve_data[COLLECTOR_KEY]
# Check, if file size changed, store it for saver plugin
if fsize == self.file_last_size:
return
# Put new size for saver plugin
lve_data[SAVER_KEY] = fsize
self.file_last_size = fsize
lve_data[SAVER_DATA_PRESENCE] = 1
This plugin is extremely simple as well. It starts after collector (order=1) , searches for file size in the dictionary and compares it with the previous index. If it has changed, then it writes a sign of presence of a new size into the dictionary. If no changes seen, then sign resets. The previous file size is stored in the plugin itself in file_last_size variable. Note that they are stored during the whole server lve-stats lifetime.
If file size is not found in data dictionary, then plugin just ends.
All the errors are completely ignored.
Analyzer is unconfigurable, that is why it doesn’t require any configuration file and it doesn’t contain set_config method.
Plugin starts every 60 seconds (1 minute), because we need data fixation to be performed one time in a minute.
Persistor
Persistor saves information from the common dictionary into files, databases, etc.
# FSize_watcher_saver.py
# Example plugin for monitoring file size and last modification date-time.
# Part 3. Data saver
import signal
import sys
import time
from lvestats.core.plugin import LveStatsPlugin
# Key name 1 for saver plugin
SAVER_KEY = 'FSizeWatcher_fsize_to_store'
# Key name 2 for saver plugin
SAVER_DATA_PRESENCE = 'FSizeWatcher_fsize_present'
# Monitoring file name
COLLECTOR_KEY_FILENAME = 'FSizeWatcher_fname'
class FSize_watcher_saver (LveStatsPlugin):
# this plugin should be third in chain
order = 2
# Plugin run period in seconds
period = 60
# Log filename
log_file_name = None
# First run flag
is_first_run = True
def __init__(self):
signal.signal(signal.SIGTERM, self.sigterm_handler)
# Sets configuration to plugin
def set_config(self, config):
# Get log filename
self.log_file_name = config.get('log_filename', None)
# work method
def execute(self, lve_data):
# do nothing, if log file not defined
if not self.log_file_name:
return
try:
# Check presence data
if SAVER_DATA_PRESENCE not in lve_data or lve_data[SAVER_DATA_PRESENCE] == 0:
# No data
return
# Get file size from server data dictionary
fsize = lve_data[SAVER_KEY]
# Store data to log
f = open(self.log_file_name, 'a')
if self.is_first_run:
f.write('%s - FSize_watcher started. Monitoring file: %s, saving data period=%d sec\n' % (time.asctime(time.localtime()), lve_data[COLLECTOR_KEY_FILENAME], self.period))
self.is_first_run = False
f.write('%s - FSize_watcher: file size is %d bytes\n' % (time.asctime(time.localtime()), fsize))
f.close()
except:
# Ignore all errors
pass
# Terminate handler
def sigterm_handler(self, signum, frame):
if self.log_file_name:
try:
# Store data to log file
f = open(self.log_file_name, 'a')
f.write('%s - File watcher saver plugin: TERMINATE\n' % time.asctime(time.localtime()))
f.close()
pass
except:
# Ignore all errors
pass
# Terminate process
sys.exit(0)
Configuration file /etc/sysconfig/lvestats.config/FSize_watcher_saver.cfg
:
# Config file for FSize_watcher_saver.py plugin
# Please define log filename here
log_filename = /var/log/FSize_watcher.log
This plugin starts after analyzer (order=2) , checks new file size presence
flag, and if positive – writes it into log. If the flag is cleared (which means the size hasn't changed), then plugin simply ends.
Starts once in a minute (period=60).
Also this plugin shows the work of signal handler.
Plugin constructor registers handler-function of a proper signal: signal.signal(signal.SIGTERM, self.sigterm_handler) . This means, that when the server finishes its work, then sigterm_handler method of plugin class will be invoked. In the actual example the function just writes a notification into log, tracing the fact of it's invocation.
Pay attention on sys.exit(0) command in the end of the handler. Find the information on it in Server Plugin Arrangement section.
In addition see into examples of file log /var/log/FSize_watcher.log formed by the plugins above:
Tue Feb 3 13:06:24 2015 - FSize_watcher started. Monitoring file: /usr/local/cpanel/logs/access_log, saving data period=60 sec
Tue Feb 3 13:06:24 2015 - FSize_watcher: file size is 122972890 bytes
Tue Feb 3 13:07:25 2015 - FSize_watcher: file size is 122975507 bytes
Tue Feb 3 13:08:25 2015 - FSize_watcher: file size is 122978124 bytes
Tue Feb 3 13:09:25 2015 - FSize_watcher: file size is 122978997 bytes
Tue Feb 3 13:10:25 2015 - FSize_watcher: file size is 122981033 bytes
Tue Feb 3 13:11:25 2015 - FSize_watcher: file size is 122982052 bytes
Tue Feb 3 13:13:25 2015 - FSize_watcher: file size is 122983798 bytes
Tue Feb 3 13:20:15 2015 - File watcher saver plugin: TERMINATE
and
Thu Feb 5 13:07:27 2015 - FSize_watcher started. Monitoring file: /usr/local/cpanel/logs/error_log, saving data period=60 sec
Thu Feb 5 13:07:27 2015 - FSize_watcher: file size is 14771849 bytes
Thu Feb 5 14:03:32 2015 - FSize_watcher: file size is 14771995 bytes
Thu Feb 5 15:01:36 2015 - FSize_watcher: file size is 14772434 bytes
Thu Feb 5 17:15:47 2015 - FSize_watcher: file size is 14772873 bytes
Thu Feb 5 18:47:54 2015 - FSize_watcher: file size is 14775213 bytes
Thu Feb 5 19:11:56 2015 - FSize_watcher: file size is 14775652 bytes
Thu Feb 5 21:09:05 2015 - FSize_watcher: file size is 14776091 bytes
Thu Feb 5 23:06:14 2015 - FSize_watcher: file size is 14776530 bytes
Fri Feb 6 00:47:23 2015 - FSize_watcher: file size is 14778870 bytes
Fri Feb 6 01:02:24 2015 - FSize_watcher: file size is 14779309 bytes
Fri Feb 6 02:00:28 2015 - FSize_watcher: file size is 14779434 bytes
Fri Feb 6 03:16:34 2015 - FSize_watcher: file size is 14779873 bytes
Fri Feb 6 05:04:42 2015 - FSize_watcher: file size is 14779998 bytes
Fri Feb 6 05:12:43 2015 - FSize_watcher: file size is 14780437 bytes
Fri Feb 6 05:56:50 2015 - FSize_watcher: file size is 14780551 bytes
Fri Feb 6 06:01:50 2015 - FSize_watcher: file size is 14780975 bytes
Fri Feb 6 06:03:51 2015 - FSize_watcher: file size is 14782183 bytes
Fri Feb 6 06:04:51 2015 - FSize_watcher: file size is 14782575 bytes
Fri Feb 6 06:18:52 2015 - FSize_watcher: file size is 14782647 bytes
Fri Feb 6 06:21:52 2015 - FSize_watcher: file size is 14782898 bytes
Fri Feb 6 06:48:54 2015 - FSize_watcher: file size is 14785238 bytes
Fri Feb 6 07:09:56 2015 - FSize_watcher: file size is 14785677 bytes
Tue Feb 6 08:03:15 2015 - File watcher saver plugin: TERMINATE
You can see that log record is being held once a minute (what we actually need), new file size is written.
Also we can notice that handler SIG_TERM was executed, signaling that plugin received the notification about server shut-down.
Notifier
Notifier informs system users about any events.
# FSize_watcher_saver.py
# Example plugin for monitoring file size and last modification date-time.
# Part 4. Notifier
import time
import smtplib
from lvestats.lib.commons import dateutil
from lvestats.core.plugin import LveStatsPlugin
# Key name
COLLECTOR_KEY_FSIZE = 'FSizeWatcher_fsize'
COLLECTOR_KEY_FILENAME = 'FSizeWatcher_fname'
# email message pattern
EMAIL_MESSAGE_PATTERN = """Hello, administrator!
Size of the file '%s' is %d bytes.
"""
class FSize_watcher_notifier (LveStatsPlugin):
# Default period
DEFAULT_PERIOD_STR = '12h'
# this plugin should be third in chainorder = 3
# Timeout
timeout = 20
# Notifier Log filename
log_file_name = '/var/log/FSize_watcher_notifier.log'
# Email from address
email_from = None
# Email to address
email_to = None
# Email subject
email_subject = None
# Sets configuration to plugin
def set_config(self, config):
# Email settings
self.email_from = config.get('notify_from_email', None)
self.email_to = config.get('notify_to_email', None)
self.email_subject = config.get('notify_from_subject', 'Message from FSize_watcher_notifier plugin')
# Notify period
s_period = config.get('notify_period', None)
if s_period:
self.period = dateutil.parse_period2(s_period)
else:
self.period = dateutil.parse_period2(FSize_watcher_notifier.DEFAULT_PERIOD_STR)
f = open(self.log_file_name, 'a')
f.write('%s - FSize_watcher_notifier plugin: configure\n' % time.asctime(time.localtime()))
f.write(' - Period: %s\n' % self.period)
f.write(' - From: %s\n' % self.email_from)
f.write(' - To: %s\n' % self.email_to)
f.write(' - Subject: \'%s\'\n' % self.email_subject)
f.close()
# work method
def execute(self, lve_data):
if COLLECTOR_KEY_FSIZE not in lve_data or COLLECTOR_KEY_FILENAME not in lve_data:
return
if not self.email_from or not self.email_to:
f = open(self.log_file_name, 'a')
f.write('%s - FSize_watcher_notifier plugin error: email_from or email_to not set\n')
f.close()
return
try:
from email.mime.text import MIMEText
# Send email
msg = MIMEText(EMAIL_MESSAGE_PATTERN % (lve_data[COLLECTOR_KEY_FILENAME], lve_data[COLLECTOR_KEY_FSIZE]))
msg['Subject'] = self.email_subject
msg['From'] = self.email_from
msg['To'] = self.email_to
s = smtplib.SMTP('localhost')
s.sendmail(self.email_from, [self.email_to], msg.as_string())
s.quit()
f = open(self.log_file_name, 'a')
f.write('%s - FSize_watcher_notifier plugin: email message was successfully sent\n' % time.asctime(time.localtime()))
f.close()
except Exception as e:
f = open(self.log_file_name, 'a')
f.write('%s - FSize_watcher_notifier plugin error:\n%s\n' % (time.asctime(time.localtime()), str(e)))
f.close()
Configuration file /etc/sysconfig/lvestats.config/FSize_watcher_notifier.cfg :
# Config file for FSize_watcher_notifier.py plugin
# Please define email options here
NOTIFY_FROM_EMAIL=user@hostname
NOTIFY_FROM_SUBJECT=Message from FSize_watcher_notifier
NOTIFY_TO_EMAIL=admin@hostname
NOTIFY_PERIOD=12h
Plugin’s index number equals 3 ( order=3 ), that is why notifier starts after the rest. But since it uses only data formed by collector , then its order may equal any number bigger that collectors order (>0).
Notifier reads the necessary parameters from the configuration (email address, topic, period) and writes them into its own log as reference.
Plugin’s execute method checks the availability of all the necessary data (email parameters, collectors data) and sends the message. All the notifications are written into the notifier's own log.
If any data is missing, the message is not sent.
Log example:
Thu Feb 5 11:51:34 2015 - FSize_watcher_notifier plugin: configure
- Period: 60.0
- From: user@hostname
- To: admin@hostname
- Subject: 'Message from FSize_watcher_notifier'
Thu Feb 5 11:51:35 2015 - FSize_watcher_notifier plugin: email message was successfully sent
Thu Feb 5 11:52:35 2015 - FSize_watcher_notifier plugin: email message was successfully sent
Thu Feb 5 11:53:35 2015 - FSize_watcher_notifier plugin: email message was successfully sent
Thu Feb 5 11:54:35 2015 - FSize_watcher_notifier plugin: email message was successfully sent
Thu Feb 5 11:57:00 2015 - FSize_watcher_notifier plugin: configure
- Period: 43200.0
- From: user@hostname
- To: admin@hostname
- Subject: 'Message from FSize_watcher_notifier'
Thu Feb 5 11:57:00 2015 - FSize_watcher_notifier plugin: email message was successfully sent
File info and format for /var/lve/info file
This file is used by control panels to display to user their 'current' usage. The file is updated every 5 seconds by lve-stats.
When writing to this file we make sure that: average CPU/IOPS/MEM is never greater then LIMIT for that resource.
Example:
0,0,20,0,2500,0,262144,0,0,262144,0,0,100,0,0,0,0,1024,1024,0,0,0,0 600,1,20,2492,2500,70,262144,0,0,262144,33,0,100,1,0,0,0,1024,1024,0,5,0,0 200,0,20,0,2500,0,262144,0,0,262144,0,0,100,0,0,0,0,1024,1024,0,0,0,0 500,0,20,0,2500,0,262144,0,0,262144,0,0,100,0,0,0,0,1024,1024,0,0,0,0
First line of the file is ' default limits '.
Fields:
# 0 - id
# 1 - mep (average entry processes)
# 2 - lep (limit ...)
# 3 - cpu_usage (average speed)
# 4 - lcpu (limit spped)
# 5 - mem_usage (average virtual memory)
# 6 - lmem (limit ...)
# 7 - mem_fault (number of virtual memory faults)
# 8 - mep_fault (number of entry processes faults)
LVE_VERSION >=6
# 9 - lmemphy (limit physical memory)
# 10 - memphy (average ...)
# 11 - memphy_fault (faults ...)
# 12 - lnproc (limit number of processes)
# 13 - nproc (average ...)
# 14 - nproc_fault (faults ...)
# 15 - lcpuw (CPU weight -- deprecated not used)
# 16 - io_usage (average IO usage)
# 17 - io_limit (limit ...)
LVE_VERSION >=8
#18 - liops (limit IOPS)
#19 - iops (average IOPS)
Note
You can also use LVE-stats 2 CLI
Troubleshooting
lvestats service and utilities write fatal errors to system log.
There is /var/log/lve-stats.log
file with additional information (warnings, tracebacks for errors).
To see which letters were sent via lves-tats notifier in the logs, do the following:
- In the
/etc/sysconfig/lvestats2
, specifylogging_level=debug
; - Execute the
service lvestats restart
command.
CageFS
General information and requirements
CageFS is a virtualized file system and a set of tools to contain each user in its own 'cage'. Each customer will have its own fully functional CageFS, with all the system files, tools, etc.
The benefits of CageFS are:
- Only safe binaries are available to user
- User will not see any other users, and would have no way to detect presence of other users & their user names on the server
- User will not be able to see server configuration files, such as Apache config files.
- User's will have limited view of /proc file system, and will not be able to see other users' processes
At the same time, user's environment will be fully functional, and user should not feel in any way restricted. No adjustments to user's scripts are needed. CageFS will cage any scripts execution done via:
- Apache (suexec, suPHP, mod_fcgid, mod_fastcgi)
- LiteSpeed Web Server
- Cron Jobs
- SSH
- Any other PAM enabled service
Note
mod_php is not supported, MPM ITK requires a custom patch
Note
CageFS is not supported for H-Sphere.
See also Compatibility Matrix.
Minimum Requirements:
- kernel: CL6 with lve1.2.17.1 or later, CL7.
- 7GB of disk space.
Depending on your setup, and number of users, you might also need:
- Up to 8MB per customer in
/var
directory (to store custom/etc
directory) - 5GB to 20GB in
/usr/share
directory (to store safe skeleton of a filesystem)
Warning
If at any time you decide to uninstall CageFS, please make sure you follow uninstall instructions
CageFS quirks
Due to the nature of CageFS, some options will not work as before or will require some changes:
- lastlog will not work (
/var/log/lastlog
). - PHP will load
php.ini
from/usr/selector/php.ini
. That file is actually a link to the realphp.ini
file from your system. So the samephp.ini
will be loaded in the end. - You have to run
cagefsctl --update
any time you have modifiedphp.ini
, or you want to get new/updated software inside CageFS. - CageFS installation changes
jailshell
to regular bash on cPanel - read why.
Installation and update
To install CageFS:
yum install cagefs
/usr/sbin/cagefsctl --init
That last command will create skeleton directory that might be around 7GB in size. If you don't have enough disk space in /usr/share, use following commands to have cagefs-skeleton
being placed in a different location:
mkdir /home/cagefs-skeleton
ln -s /home/cagefs-skeleton /usr/share/cagefs-skeleton
The commands above should be executed before the cagefsctl --init
.
Also, it is needed approximately 4Kb of disk space per one user for the /var/cagefs
directory. You should place the /var/cagefs
directory on partition, which is large enough and has disk quota enabled.
For example, to create the /var/cagefs
directory on the /home
partition, execute the following commands before the cagefsctl --init
:
mkdir /home/cagefs
ln -s /home/cagefs /var/cagefs
IMPORTANT
Please make sure to turn on disk quota for a partition where the /var/cagefs
directory is located, or move the /var/cagefs
to a partition where disk quota is enabled. This is needed to prevent users from abusing disk quota inside CageFS.
If the /var/cagefs
directory is already created, you can move it. How to move the /var/cagefs
directory: https://docs.cloudlinux.com./#moving-var-cagefs-directory
IMPORTANT
If you are placing skeleton in /home
directory on cPanel servers, you must configure the following option in cPanel WHM: WHM -> Server Configuration -> Basic cPanel/WHM Setup -> Basic Config -> Additional home directories
Change the value to blank (not default Home ). Without changing this option, cPanel will create new accounts in incorrect places.
CageFS will automatically detect and configure all necessary files for:
- cPanel
- Plesk
- DirectAdmin
- ISPmanager
- Interworx
- MySQL
- PostgreSQL
- LiteSpeed
Web interface to manage CageFS is available for cPanel, Plesk 10+, DirectAdmin, ISPmanager & Interworx. Command line tool would need to be used for other control panels.
Once you initialized the template you can start enabling users. By default CageFS is disabled for all users.
Starting from cagefs-6.1-27 fs.proc_can_see_other_uid
will be migrated (one time) from /etc/sysctl.conf into /etc/sysctl.d/90-cloudlinux.conf . If this variable is not set in either file, it will default to 0.
It is strongly advised against setting this variable in 90-cloudlinux.conf
. Define it in /etc/sysctl.conf
or in some other config file with an index number greater than 90-cloudlinux.conf
, e.g. /etc/sysctl.d/95-custom.conf
.
You can find more information on fs.proc_can_see_other_uid
automatic migration in Kernel Config Variables.
Note
You can also use CageFS CLI
Uninstalling
To uninstall CageFS, start by disabling and removing all directories:
/usr/sbin/cagefsctl --remove-all
That command will: disable CageFS for all customers, unmount CageFS for all users, removes /usr/share/cagefs-skeleton & /var/cagefs directories. It will not remove /etc/cagefs directory.
Remove CageFS RPM:
yum remove cagefs
Managing users
CageFS provides for two modes of operations:
- Enabled for all, except those that are disabled.
- Disabled for all, except those that are enabled.
Mode #1 is convenient for production operation, where you want all new users to automatically be added to CageFS. Mode #2 is convenient while you test CageFS, as it allows you to enable it on one by one for your customers.
To start using CageFS you have to select one of the mode of operations:
/usr/sbin/cagefsctl --enable-all
/usr/sbin/cagefsctl --disable-all
/usr/sbin/cagefsctl --toggle-mode
To enable individual user do:
/usr/sbin/cagefsctl --enable [username]
/usr/sbin/cagefsctl --disable [username]
/usr/sbin/cagefsctl --list-enabled
/usr/sbin/cagefsctl --list-disabled
/usr/sbin/cagefsctl --display-user-mode
Note
You can also use CageFS CLI
Configuration
File system templates
Warning
Please do not modify any existing files in the /etc/cagefs/conf.d
directory because they may be overwritten while updating CageFS package. You should create a new file with a unique name instead.
CageFS creates a filesystem template in /usr/share/cagefs-skeleton
directory. CageFS template will be mounted for each customer. The template is created by running:
/usr/sbin/cagefsctl --init
To update the template, you should run:
/usr/sbin/cagefsctl --update
The behavior of the commands (and the files copied into /usr/share/cagefs-skeleton directory) depends on the configuration files in /etc/cagefs/conf.d
You can add additional files, users, groups and devices into CageFS template by adding .cfg file, and running:
/usr/sbin/cagefsctl --update
To delete files from CageFS template, remove corresponding .cfg file, and run:
/usr/sbin/cagefsctl --update
Here is an example openssh-clients.cfg file:
[openssh-clients]
comment=OpenSSH Clients
paths=/etc/ssh/ssh_config, /bin/hostname, /usr/bin/scp, /usr/bin/sftp, /usr/bin/slogin, /usr/bin/ssh, /usr/bin/ssh-add, /usr/bin/ssh-agent, /usr/bin/ssh-copy-id, /usr/bin/.ssh.hmac, /usr/bin/ssh-keyscan, /usr/libexec/openssh/sftp-server, /etc/environment, /etc/security/pam_env.conf
devices=/dev/ptmx
Example mail.cfg file:
[mail]
comment=Mail tools
paths=/bin/mail, /etc/aliases.db, /etc/mail, /etc/mailcap, /etc/mail.rc, /etc/mime.types, /etc/pam.d/smtp.sendmail, /etc/rc.d/init.d/sendmail, /etc/smrsh, /etc/sysconfig/sendmail, /usr/bin/hoststat, /usr/bin/Mail, /usr/bin/mailq.sendmail, /usr/bin/makemap, /usr/bin/newaliases.sendmail, /usr/bin/purgestat, /usr/bin/rmail.sendmail, /usr/lib64/sasl2/Sendmail.conf, /usr/lib/mail.help, /usr/lib/mail.tildehelp, /usr/lib/sendmail.sendmail, /usr/sbin/mailstats, /usr/sbin/makemap, /usr/sbin/praliases, /usr/sbin/sendmail.sendmail, /usr/sbin/smrsh, /var/log/mail, /var/spool/clientmqueue, /var/spool/mqueue
users=smmsp
groups=smmsp
There is an easy way to add/delete files from particular RPMs into CageFS. That can be done by using --addrpm
and --delrpm
options in cagefsctl
. Like:
cagefsctl --addrpm ffmpeg
cagefsctl --update
Note
ffmpeg RPM should be installed on the system already.
Excluding files
To exclude files and directories from CageFS, edit file:/etc/cagefs/custom.black.list
And add files or directories in there, one per line.
Execute the following command to apply changes:
cagefsctl --force-update
Please do not edit /etc/cagefs/black.list
file because it is replaced during the update of CageFS package.
Excluding users
To exclude users from CageFS, create a file (any name would work) inside /etc/cagefs/exclude
folder, and list users that you would like to exclude from CageFS in that file (each user in separate line).
Then execute the following command to apply changes:
cagefsctl --user-status USER
And check that the command shows Disabled
.
Mount points
Note
Please do not mount the entire /var
directory into CageFS (i.e. do not add the /var
to the cagefs.mp
). This will break CageFS.
CageFS creates individual namespace for each user, making it impossible for users to see each other's files and creating high level of isolation. The way namespace is organized:
- /usr/share/cagefs-skeleton with safe files is created
- Any directory from the server that needs to be shared across all users is mounted into
/usr/share/cagefs-skeleton
(a list of such directories is defined in /etc/cagefs/cagefs.mp) - /var/cagefs/[prefix]/username directory for each user. Prefix is defined as last two digits of user id. User id is taken from /etc/passwd file.
- Separate /etc directory is created and populated for each user inside /var/cagefs/[prefix]/username
- /tmp directory is mounted for each user separately into ~username/.cagefs/tmp directory
- Additional custom directories can be mounted for each user by defining them in /etc/cagefs/cagefs.mp
- You can define custom directories per user using virt.mp files [CageFS 5.1 and higher]
To define individual custom directories in /etc/cagefs/cagefs.mp following format is used:
@/full/path/to/directory,permission notation
This is useful when you need to give each user its own copy of a particular system directory, like:
@/var/run/screen,777
Such entry would create separate /var/run/screen for each user, with permissions set to 777
To modify mount points, edit /etc/cagefs/cagefs.mp. Here is an example of cagefs.mp:
/var/lib/mysql
/var/lib/dav
/var/www/cgi-bin
/var/spool
/dev/pts
/usr/local/apache/domlogs
/proc
/opt
@/var/spool/cron,700
@/var/run/screen,777
If you want to change mount points, make sure you re-initialize mount points for all customers:
cagefsctl --remount-all
Per user virtual mount points
[CageFS 5.1 and higher]
- Please, see Split by username feature, as it might be simpler to implement in some cases.
Starting with CageFS 5.1 you can specify additional directories to be mounted inside user's CageFS. This can be specified for each user. To specify virtual mount points for a user, create a file:
/var/cagefs/[prefix]/[user]/virt.mp
Inside that file, you can specify mount points in the following format:
virtdir1,mask
@subdir1,mask
@subdir2,mask
virdir2,mask
@subdir3,mask
@subdir4,mask
>virtdir3,mask
@subdir5,mask
@subdir6,mask
# comments
- mask is always optional, if missing 0755 is used
- Create virtual directory subdir/virtdir , mount it to:
- skeleton jaildir/virtdir
- inside virtual directory, create directories subdir1, subdir2
- mount virtdir1/subdir1 to subdir/virtdir/subdir1
- if virtdir is started with >, create directory subdir/virtdir , but don't mount it into jaildir . This is needed for cases when virtdir is inside home base dir.
- if file /var/cagefs/[prefix]/[user]/virt.mp is missing -- no virt directories are loaded for that user.
Note that CageFS will automatically create those files for Plesk 10 & higher.
For example if we have Plesk 11.5 with two users cltest1, and cltest2:
cltest1 uid 10000 has domains: cltest1.com, cltest1-addon.com and sub1.cltest1.com
cltest2 uid 10001 has domains: cltest2.com, cltest2-addon.com
In such case we would have file /var/cagefs/00/cltest1/virt.mp :
>/var/www/vhosts/system,0755
@cltest1-addon.com,0755
@cltest1.com,0755
@sub1.cltest1.com,0755
and file: /var/cagefs/01/cltest2/virt.mp:
>/var/www/vhosts/system
@cltest2-addon.com
@cltest2.com
Split by username
[CageFS 5.3.1+]
Sometimes you might need to make sure that directory containing all users would show up as containing just that user inside CageFS. For example, if you have directory structure like:
/home/httpd/fcgi-bin/user1
/home/httpd/fcgi-bin/user2
Then we can add the following line to /etc/cagefs/cagefs.mp file:
%/home/httpd/fcgi-bin
and execute:
cagefsctl --remount-all
After that each subdirectory of /home/httpd/fcgi-bin will be mounted for appropriate user in CageFS: /home/httpd/fcgi-bin/user1 will be mounted for user1 and /home/httpd/fcgi-bin/user2 will be mounted for user2 .
Splitted by user’s UID mounts
Note
Requires CageFS v.7.4.2-1 and later
In addition to splitted by username mounts, there is an ability to “split” mounts by user’s UID. This feature is useful for systems with non-unique UIDs, i.e. when multiple users have the same UID.
Using splitted by UID mounts is more preferable over splitted by username mounts, because you can mount the same directory for all users with the same UID. Also, splitted by UID mounts work fine with renaming of the users (when username changes but UID remains the same).
For example if you have a directory structure like the following:
/data/uids/1000/data.db
/data/uids/1001/data.db
Then you can add the following line to the /etc/cagefs/cagefs.mp
file:
*/data/uids
and execute
cagefsctl --remount-all
After that each subdirectory of the /data/uids
will be mounted for the appropriate user in CageFS. The /data/uids/1000
directory will be mounted for the user with UID 1000 and the /data/uids/1001
directory will be mounted for the user with UID 1001.
Mounting users home directory inside CageFS
CageFS 6.1-1 (and later) has improved mounting user’s home directory that is applied for users with home directories like /home/user or /homeN/user (where N = 0,1,..9).
In such case, earlier versions of CageFS always mount user’s home directory to /home/user and create symlink /homeN -> /home when needed, so user’s home directory can be accessed both via /home/user and /homeN/user . This quirk leads to some rare incompatibilities between CageFS and other software (for example OpenCart), because real path of user’s home directory in CageFS and in real file system can differ.
New CageFS mounts user’s home directory in a way that its real path in CageFS is always the same as in real file system. Additionally, CageFS searches for symlinks like /homeX -> /homeY and /homeX/user -> /homeY/user in real system and creates such symlinks in user’s CageFS when found.
This new mounting mode is enabled by default. You can switch to old mounting mode by executing the following commands:
touch /etc/cagefs/disable.home.dirs.search
cagefsctl --force-update
cagefsctl --remount-all
Note
New mounting mode will be disabled automatically when "mounting base home directory" mode is enabled (mount_basedir=1
setting in /etc/cagefs/cagefs.base.home.dirs file).
How to hide directory inside mount point
Note
For files outside a mount point, use blacklisting, see: Excluding files
To hide directories inside a mount point, create a file in the /etc/cagefs/empty.dirs
directory (you can use any name) with a list of directories to be hidden (these directories will look like empty for users in CageFS).
Note
Please do not edit the supplied config file (/etc/cagefs/empty.dirs/emptied_dirs.default
).
Example
Let’s take a /var/www
directory which contains the following folders: icons
and html
. To hide the /var/www
directory content from users inside CageFS, we will do the following:
- Create the
custom.empty
file with a single record:/var/www
- Place the
custom.empty
file to the/etc/cagefs/empty.dirs
directory - Run the
cagefsctl --remount-all
command
Now, all users inside CageFS will see the /var/www
directory as an empty directory even if there is /var/www/html
in the /etc/cagefs/cagefs.mp
.
Base home directory
If you have a custom setup where home directories are in a special format, like: /home/$USERNAME/data , you can specify it using regular expressions. This is needed by CageFS to create safe home space for end user, where no other users are visible.
We will create empty: /var/cagefs/[prefix]/$USERNAME/home , and then mount /home/$USERNAME in that directory
To do that, create a file: /etc/cagefs/cagefs.base.home.dirs
With content like:
^/home/
^/var/www/users/
If there is no such file, the home directory without last component will be considered as a base dir, like with /home/$USERNAME we would create /var/cagefs/[prefix]/$USERNAME/home , and then mount /home/$USERNAME in there
With /home/$USERNAME/data as a home dir, we would assume that /home/$USERNAME is the base directory, and we would create /var/cagefs/[prefix]/$USERNAME/home/$USERNAME/data and then we would mount /home/$USERNAME/data -- which would cause each user to see empty base directories for other users, exposing user names.
Sharing home directory structure among users
When you want to share directory structure among multiple users, you can add following line at the top of the /etc/cagefs/cagefs.base.home.dirs file. This is useful on the systems that support sites with multiple users, with different home directories inside the main 'site' directory.
mount_basedir=1
For example:
user1 has home directory /var/www/vhosts/sitename.com/web_users/user1 user2 has home directory /var/www/vhosts/sitename.com/web_users/user2 site admin has home directory /var/www/vhosts/sitename.com
So, content of /etc/cagefs/cagefs.base.home.dirs should be the following:
mount_basedir=1
^/var/www/vhosts/[^/]+
Directory structure in /var/www/vhosts/sitename.com will be mounted in CageFS for appropriate users.
Each user will have access to whole directory structure in /var/www/vhosts/sitename.com (according to their permissions).
Note
You should execute cagefsctl --remount-all
in order to apply changes to CageFS (i.e. remount home directories).
PostgreSQL support
CloudLinux OS 7:
CageFS works with any PostgreSQL version installed from CloudLinux OS or CentOS repositories. PostgreSQL packages for CloudLinux OS 7 come from the upstream (CentOS) unmodified. PostgreSQL’s socket is located in /var/run/postgresql directory. This directory is mounted to CageFS by default (in cagefs-5.5-6.34 or later).
When PostgreSQL has been installed after CageFS install, please add line:
/var/run/postgresql
tо /etc/cagefs/cagefs.mp file and then execute:
cagefsctl --remount-all
The steps above are enough to configure CageFS to work with PostgreSQL.
CloudLinux OS 6:
CageFS provides separate /tmp directory for each end user. Yet, PostgreSQL keeps its Unix domain socket inside server's main /tmp directory. In addition to that, the location is hard coded inside PostgreSQL libraries.
To resolve the issue, CloudLinux OS provides a version of PostgreSQL with modified start up script that can store PostgreSQL's socket in /var/run/postgres. The script automatically creates link from /tmp to that socket to prevent PostgreSQL dependent applications from breaking.
In addition to that, CageFS knows how to correctly link this socket inside end user's /tmp directory.
To enable PostgreSQL support in CageFS:
Make sure you have updated to latest version of PostgreSQL.
Edit file /etc/sysconfig/postgres, and uncomment SOCK_DIR line.
Update CageFS configuration by running:
cagefsctl --reconfigure-cagefs
- Restart PostgreSQL by running:
service postgresql restart
If you are using cPanel, you would also need to modify file: /etc/cron.daily/tmpwatch
And update line:
flags=-umc
to:
flags=-umcl
to prevent symlink from being removed.
PAM configuration
CageFS depends on pam_lve module for PAM enabled services. When installed, the module is automatically installed for following services:
- sshd
- crond
- su
The following line is added to corresponding file in /etc/pam.d/
:
Where 100 stands for minimum UID to put into CageFS & LVE , and 1 stands for CageFS enabled.
Filtering options for commands executed by proxyexec
You can disallow a user in CageFS to execute specific commands with some specific dangerous options via proxyexec.
To do so, you should create <command>.json
file in the /etc/cagefs/filters
directory and specify the names of options you want to disable.
For example, to disable some options of sendmail
command, /etc/cagefs/filters/sendmail.json
is created with the following content:
{
"default": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
]
},
"/usr/sbin/sendmail": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
]
},
"/var/qmail/bin/sendmail": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
]
},
"/usr/sbin/sendmail.sendmail": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
]
},
"/usr/local/cpanel/bin/sendmail": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
]
}
}
You can specify options for different paths separately (for example, /usr/sbin/sendmail
or /var/qmail/bin/sendmail
).
If the path to the program being executed does not match any path specified in the config file, then default parameters are used.
deny
list should contain options that should be disallowed for use by users (the black list of options, all other options will be allowed).- You can specify the white list of options in the
allow
list (all other options will be denied). - You cannot specify both white and black list (
allow
anddeny
).
It is possible to verify that a path specified as a parameter for an option does not refer outside of the user’s home directory. This check is performed for options specified in the restrict_path
list. All issues are reported in /var/log/secure
log file.
NOTE: By default, option filters only compare the starting parts of arguments with entries specified by lists. For instance, if option "-f" is forbidden, "-f /etc/list" will be forbidden, but "-vf /etc/list" will not.
Starting from cagefs v. #7.4.12-1, specifying a "strict_options": true
switch inside a filter file entry enables an extended parsing mechanism where each short option from a cluster is parsed separately.
It is recommended to enable this option, unless it causes issues with the restricted command's functionality.
{
"default": {
"deny": [
"-be",
"-bem"
],
"restrict_path": [
"-C",
"-D"
],
"strict_options": true
}
}
Executing by proxy
Some software has to run outside CageFS to be able to complete its job. It includes such programs as passwd, sendmail, etc. CageFS provides proxyexec technology to accomplish this goal: you can define any program to run outside CageFS by specifying it in any file located in the /etc/cagefs/
which ends with .proxy.commands
. In the examples below we use custom.proxy.commands
, but you can use any other name, e.g. mysuperfile.proxy.commands
.
Warning
Do not edit the existing /etc/cagefs/proxy.commands
file as it will be overwritten with the next CageFS update.
Also you should create a config file in /etc/cagefs/conf.d/
and define there a path to the binary or to one of it's parent directories.
Warning
Binary shouldn't be located in one of the directories specified in /etc/cagefs/cagefs.mp. Binaries from directories in /etc/cagefs/cagefs.mp are always executed inside cagefs.
The syntax of the /etc/cagefs/[*.]proxy.commands
file is as follows:
ALIAS[:wrapper_name]=[username:]path_to_executable
Parameter | Description |
---|---|
ALIAS | Any name unique within all /etc/cagefs/\[*.\]proxy.commands files. Used as an identifier. |
wrapper_name | Optional field. The name of the wrapper file which is used as a replacement for an executable file (set by path_to_executable ) inside CageFS. Possible values: - a name of a wrapper you place into the /usr/share/cagefs/safeprograms directory;- noproceed - a reserved word which means that the wrapper is not needed, e.g. when it is already installed by other ALIAS. Often used for the commands with several ALIAS as in the example below.- omit this field - default wrapper cagefs.proxy.program will be used.Used in cases when you'd like to give access only to the part of binary functions but it is not possible to do that using options filtering. Note: wrapper works inside CageFS with user rights and executes “real” scripts using proxy daemon. |
path_to_executable | A path to an executable file that will run via proxyexec. |
username | Optional field. A name of a user on whose behalf path_to_executable will run in the real system. If username is not specified, then path_to_executable will run on behalf of the same user who is inside CageFS. |
Once the program is defined, run this command to populate the skeleton:
cagefsctl --force-update
Users with duplicate UIDs
Sometimes hosters may have users with non-unique UIDs. Thus, proxyexec
may traverse users' directories to find a specific one. That behavior turns into inappropriate if the user's directory is not cached locally (for example LDAP is used).
To turn this feature off, run:
touch /etc/cagefs/proxy.disable.duid
Or to activate it back, run:
rm /etc/cagefs/proxy.disable.duid
Examples
Let's have a script that must do some stuff outside CageFS and return a result to a user. Let's name it superbinary
and place it into the /my/scripts/
directory.
In the examples below, we will use a small script that:
- checks if it works inside or outside of CageFS
- prints a number of users in the
/etc/passwd
file
We use the /etc/passwd
file because it is truncated inside the cage by default and we can easily see the difference between CageFS and the “real” system by just counting lines in it.
cat /opt/scripts/superbinary
............
#!/usr/bin/env bash
if [[ -e /var/cagefs ]]; then
echo "I am running without CageFS"
else
echo "I am running in CageFS"
fi;
echo "I am running as: `whoami`"
echo "Number or records in /etc/passwd: `cat /etc/passwd | wc -l`"
First, let’s check that CageFS works: create a user and disable the cage:
useradd test
cagefsctl --disable test
Then, run the following command as root
and you will see the following output:
[root ~]# su - test -c "/my/scripts/superbinary"
I am running without CageFS
I am running as: test
Number or records in /etc/passwd: 49
Now, enable CageFS for the test
user and run the command again:
[root ~]# cagefsctl --enable test
[root ~]# su - test -c "/my/scripts/superbinary"
-bash: /my/scripts/superbinary: No such file or directory
As you can see the access to the file is restricted by CageFS.
Example 1. Make users in CageFS be able to execute a script which must work outside CageFS
Add the following line into the /etc/cagefs/custom.proxy.commands
:
MYSUPERBINARY=/my/scripts/superbinary
Then run the cagefsctl --force-update
, which will place a special wrapper instead of your script inside CageFS. And run your script again:
[root ~]# su - test -c "/my/scripts/superbinary"
I am running without CageFS
I am running as: test
Number or records in /etc/passwd: 49
To compare, let’s count a number of users in the /etc/passwd
directly:
[root ~]# su - test -c "cat /etc/passwd | wc -l"
25
Result: the script escapes from CageFS and has access to all files which a user with disabled CageFS has.
Example 2. Permissions escalation
Let's imagine that you need to give the users the ability to run a script which gets information about their domains from the apache.conf
. To do that, you need root permissions. You can achieve that with proxyexec.
First, run the following:
echo "MYSUPERBINARY=root:/my/scripts/superbinary" > /etc/cagefs/custom.proxy.commands
And then, run the example script again:
[root ~]# su - test -c "/my/scripts/superbinary"
I am running without cagefs
I am running as: root
Number or records in /etc/passwd: 49
As you can see, the script now works with root permissions, as set in the custom.proxy.commands
file. In order to get information about a user who runs the script, use the following environment variables:
PROXYEXEC_UID
PROXYEXEC_GID
Example:
[root ~]# id test
uid=1226(test) gid=1227(test) groups=1227(test)
[root ~]# su - test -c "/my/scripts/superbinary"
I am running without CageFS
I am running as: root
Number or records in /etc/passwd: 49
PROXYEXEC_UID=1226
PROXYEXEC_GID=1227
Result: users can run the script that gains the root permissions and work outside CageFS. Of course, you can set any other user instead of root in the custom.proxy.commands
.
Example 3. Custom proxyexec wrapper
Let’s modify the test binary in a next way:
[root ~]# cat /my/scripts/superbinary
#!/usr/bin/env bash
FILE="$1"
if [[ -e /var/cagefs ]]; then
echo "I am running without CageFS"
else
echo "I am running in CageFS"
fi;
echo "I am running as: `whoami`"
echo "Number or records in ${FILE}: `cat ${FILE} | wc -l`"
echo "PROXYEXEC_UID=${PROXYEXEC_UID}"
echo "PROXYEXEC_GID=${PROXYEXEC_GID}"
Now users can pass any path to the file as an argument. In order to restrict possible parameters (file paths) that users can pass, you can use the custom proxyexec wrapper.
First, duplicate the default wrapper and give it a name, e.g. cagefs.proxy.mysuperbinary
.
[root ~]# cp /usr/share/cagefs/safeprograms/cagefs.proxy.program /usr/share/cagefs/safeprograms/cagefs.proxy.mysuperbinary
The default wrapper already contains a check that does not allow to run it by the root user:
#!/bin/bash
##CageFS proxyexec wrapper - ver 15
if [[ $EUID -eq 0 ]]; then
echo 'Cannot be run as root'
exit 1
fi
...
Add the new check below:
if [[ $1 == "/etc/passwd" ]]; then
echo "it is not allowed for user to view this file!"
exit 1
fi
Now, set a custom binary name in the custom.proxy.commands
:
[root ~]# cat /etc/cagefs/custom.proxy.commands
MYSUPERBINARY:cagefs.proxy.mysuperbinary=root:/my/scripts/superbinary
Run skeleton update and check that everything works as expected:
[root ~]# cagefsctl --force-update
[root ~]# su - test -c "/my/scripts/superbinary /etc/passwd"
it is not allowed for user to view this file!
[root ~]# su - test -c "/my/scripts/superbinary /etc/group"
I am running without CageFS
I am running as: root
Number or records in /etc/group: 76
PROXYEXEC_UID=1226
PROXYEXEC_GID=1227
Notes and warnings
- Make sure that a directory with your script is not listed in the
/etc/cagefs/cagefs.mp
(is not mounted inside the cage). Otherwise, the proxyexec will not work because CageFS will not be able to replace your script with a special wrapper inside the cage. - Use this feature with caution because it gives users the ability to execute specified commands outside CageFS. SUID commands are extremely dangerous because they are executed not as a user, but as an owner of the file (typically root). You should give users the ability to execute safe commands only. These commands should not have known vulnerabilities. You should check that users cannot use these commands to get sensitive information on a server. You can disable specific dangerous options of programs executed via proxyexec using filtering options.
- In cPanel, all the scripts located in the
/usr/local/cpanel/cgi-sys/
, that user might need to execute, should be added to the custom*.proxy.commands
file.
Custom /etc files per customer
[4.0-5 and later]
To create a custom file in /etc directory for end user, create a directory:
/etc/cagefs/custom.etc/[username]
Put all custom files, and sub-directories into that direcotry.
For example, if you want to create custom /etc/hosts file for USER1 , create a directory:
/etc/cagefs/custom.etc/USER1
Inside that directory, create a hosts file, with the content for that user.
After that execute:
cagefsctl --update-etc USER1
If you are making changes for multiple users, you can run:
cagefsctl --update-etc
To remove a custom file, remove it from /etc/cagefs/custom.etc/[USER] directory, and re-run:
cagefsctl --update-etc
Moving cagefs-skeleton directory
Sometimes you might need to move cagefs-skeleton from /usr/share to another partition.
There are two ways:
- If
/usr/share/cagefs-skeleton
is not created yet ( cagefsctl --init wasn't executed), then execute:
mkdir /home/cagefs-skeleton
ln -s /home/cagefs-skeleton /usr/share/cagefs-skeleton
cagefsctl --init
- If /usr/share/cagefs-skeleton already exists, see this article
Moving /var/cagefs directory
To move /var/cagefs
to another location:
cagefsctl --disable-cagefs
cagefsctl --unmount-all
Verify that /var/cagefs.bak
directory does not exist (if it exists - change name "cagefs.bak" to something else)
cp -rp /var/cagefs /new/path/cagefs
mv /var/cagefs /var/cagefs.bak
ln -s /new/path/cagefs /var/cagefs
cagefsctl --enable-cagefs
cagefsctl --remount-all
Verify that the following command gives empty output:
cat /proc/mounts | grep cagefs.bak
Then you can safely remove /var/cagefs.bak:
rm -rf /var/cagefs.bak
TMP directories
CageFS makes sure that each user has his own /tmp directory, and that directory is the part of end-user's quota.
The actual location of the directory is $USER_HOME/.cagefs/tmp
Once a day, using cron job, CageFS will clean up user's /tmp directory from all the files that haven't been accessed during 30 days.
This can be changed by running:
cagefsctl --set-tmpwatch='/usr/sbin/tmpwatch -umclq 720'
Where 720 is the number of hours that the file had to be inaccessible to be removed.
By default this is done at 03:37 AM, but you can also force the clean up outdated files that match 'chosen period' of all user's /tmp directories without waiting for a job to be launched by cronjob . Just run:
cagefsctl --tmpwatch
The following paths will be cleaned as well:
/var/cache/php-eaccelerator
(actual location$USER_HOME/.cagefs/var/cache/php-eaccelerator
)/opt/alt/phpNN/var/lib/php/session
(actual location$USER_HOME/.cagefs/opt/alt/phpNN/var/lib/php/session
), where NN corresponds to Alt-PHP version.
You can configure tmpwatch
to clean custom directories inside CageFS.
Create /etc/cagefs/cagefs.ini
configuration file and specify tmpwatch_dirs
directive as follows:
tmpwatch_dirs=/dir1,/dir2
After that directories /dir1
and /dir2
inside CageFS will be cleaned automatically.
Note that actual location of those directories in real file system is $USER_HOME/.cagefs/dir1
and $USER_HOME/.cagefs/dir2
.
Cleanup PHP sessions in cPanel
For cPanel servers, CageFS version 6.0-42 or higher performs cleaning of PHP sessions based on session.gc_maxlifetime
and session.save_path
directives specified in proper php.ini
files.
session.gc_maxlifetime
directive default value is 1440 seconds. Those session files will be deleted, that were created or had metadata (ctime) changes more time ago than it is specified in session.gc_maxlifetime
.
For Alt-PHP versions session.save_path
value is normally /tmp
.
Note
For new installations of Alt-PHP packages, session.save_path
will be changed from /tmp
to /opt/alt/phpNN/var/lib/php/session
, where NN corresponds to Alt-PHP version.
This applies to the following Alt-PHP versions (or later):
- alt-php44-4.4.9-71;
- alt-php51-5.1.6-81;
- alt-php52-5.2.17-107;
- alt-php53-5.3.29-59;
- alt-php54-5.4.45-42;
- alt-php55-5.5.38-24;
- alt-php56-5.6.31-7;
- alt-php70-7.0.23-5;
- alt-php71-7.1.9-5;
- alt-php72-7.2.0-0.rc.2.2.
When using EasyApache 3, session.save_path value is normally /var/cpanel/php/sessions/ea3 or /tmp . Settings for EasyApache 3 are usualy taken from the file /usr/local/lib/php.ini .
When using EasyApache 4, session.save_path value is normally /var/cpanel/php/sessions/ea-phpXX , where XX corresponds to PHP version.
Cleaning is started by cron /etc/cron.d/cpanel_php_sessions_cron , which starts the script /usr/share/cagefs/clean_user_php_sessions twice within one hour.
Note
Script clean_user_php_sessions deletes only files which names match mask sess_[a-z0-9]*
. If php was configured to use non-standart session file prefix in some custom save_handler, these session files wouldn't be managed by clean_user_php_sessions.
The settings for ea-php are located in /opt/cpanel/ea-phpXX/root/etc/php.d/local.ini or in /opt/cpanel/ea-phpXX/root/etc/php.ini , where XX corresponds to the PHP version.
The settings for alt-php are located in /opt/alt/phpXX/etc/php.ini files, where XX corresponds to PHP version.
The cleaning script cleans php sessions for all PHP versions ( ea-php and alt-php ) regardless of whether a version is used or selected via MultiPHP Manager or PHP Selector . When different session.gc_maxlifetime values are specified for the same session.save_path (for different php versions), the cleaning script will use the least value for cleaning session.save_path . So, it is recommended to specify different session.save_path for each PHP version.
Users can define custom value of session.gc_maxlifetime via PHP Selector in order to configure PHP's garbage collector, but that will not affect the script for cleaning PHP sessions. The script cleans PHP sessions based on global values of session.gc_maxlifetime and session.save_path directives taken from files mentioned above. Settings in custom users’ php.ini files are ignored.
Cleanup PHP session files in Plesk
For Plesk servers, CageFS version 6.0-52 or higher is provided with a special cron job for removing obsolete PHP session files. Cleanup script runs once an hour (similar to how it is done in Plesk).
Each time the script runs, it performs the cleanup of the paths:
set by
session.save_path
directive in /opt/alt/phpXX/etc/php.ini files. If session.save_path is missing, then /tmp is used. Session files lifetime is set by session.gc_maxlifetime directive. If it is not found, then 1440 seconds value is used (24 minutes, as in Plesk). Lifetime set in the file is only taken into consideration if it is longer than 1440 seconds, otherwise 1440 seconds is used. All the installed Alt-PHP versions are processed./var/lib/php/session . Files lifetime is only defined by Plesk script /usr/lib64/plesk-9.0/maxlifetime . If the script is missing or returns errors, then this directory is not processed.
The following features are applied during the cleanup:
- all the users with UID higher than specified in /etc/login.defs are processed. Each user is processed independently from one another.
- only directories inside CageFS are being cleaned. The paths of the same name in the physical file system are not processed.
- in all the detected directories, all the files with the names that correspond to
sess_
search mask are removed, the rest of the files are ignored. - the files older than specified lifetime are removed.
- all non-fatal errors (lack of rights, missing directory) are ignored and do not affect the further work of the script.
Disable PHP sessions cleanup on cPanel and Plesk
Here is a possible workaround for PHP session expiration problem (session lives longer than it is possible in a control panel). To use your own custom PHP sessions cleanup scripts - you can turn off built-in sessions cleanup implementation in the following way: add clean_user_php_sessions=false
line to /etc/sysconfig/cloudlinux .
Syslog
By default, /dev/log should be available inside end user's CageFS . This is needed so that user's cronjobs and other things that user dev/log would get recorded in the system log files.
This is controlled using file /etc/rsyslog.d/schroot.conf with the following content:
$AddUnixListenSocket /usr/share/cagefs-skeleton/dev/log
To remove presence of dev/log inside CageFS, remove that file, and restart rsyslog service.
Excluding mount points
How to exclude mounts from namespaces for all LVEs
By default, all mounts from the real file system is inherited by namespaces of all LVEs . So, destroying all LVEs may be required in order to unmount some mount in real file system completely. Otherwise, mount point remains busy after unmounting it in the real file system because this mount exists in namespaces of LVEs .
lvectl start
command saves all mounts from real file system as “default namespace” for later use in all LVEs . lve_namespaces service executes lvectl start
command during startup.
In lve-utils-2.0-26 (and later) there is an ability to exclude specific mounts from namespaces for all LVEs . In order to do so, please create a file /etc/container/exclude_mounts.conf with list of mounts to exclude (one mount per line) as regular expressions, and then execute lvectl start
:
cat /etc/container/exclude_mounts.conf
............
^/dir1/
^/dir2$
lvectl start
After that, all new created LVEs will be without /dir2 mount and without mounts that start with /dir1/ (like /dir1/x , /dir1/x/y , etc). To apply changes to existing LVEs you should recreate LVEs :
lvectl destroy all
lvectl apply all
Note
You should recreate all LVEs only once after creating /etc/container/exclude_mounts.conf file. After that the configuration changes will be applied to all new LVEs automatically.
Shared memory (/dev/shm) isolation in CageFS
Note
Requires cagefs-6.2.1-1
or later
The /dev/shm
in a real file system directory is “world-writable”. This directory from the real file system is mounted to CageFS by default, so /dev/shm
directory is common for all users by default. However, it is possible to improve security and isolate /dev/shm
(shared memory) for each user in CageFS.
To enable /dev/shm
isolation, do the following steps:
- Delete
/dev/shm
line from the/etc/cagefs/cagefs.mp
file
sed -i -e '/^\/dev\/shm/d' /etc/cagefs/cagefs.mp
- Create a configuration file with mount options for shared memory
echo 'mode=0777' > /etc/cagefs/dev.shm.options
- Remount CageFS to apply changes
cagefsctl --remount-all
You can also specify additional mount options.
For example, you can specify the size of shared memory in megabytes:
echo 'mode=0777,size=1m' > /etc/cagefs/dev.shm.options
cagefsctl --remount-all
Or you can specify the size of user’s physical memory limit (PMEM) in percentage:
echo 'mode=0777,size=50%' > /etc/cagefs/dev.shm.options
cagefsctl --remount-all
To disable /dev/shm
isolation, do the following steps:
- Delete configuration file
rm -f /etc/cagefs/dev.shm.options
- Validate
/etc/cagefs/cagefs.mp
file
cagefsctl --check-mp
- Add
/dev/shm
line to/etc/cagefs/cagefs.mp
file
echo '/dev/shm' >> /etc/cagefs/cagefs.mp
- Remount CageFS to apply changes
cagefsctl --remount-all
Note
you should specify mode=0777
. It is required for the proper operation of shared memory inside CageFS. This is not a security issue because the /dev/shm
directory is isolated for each user and visible inside a user’s CageFS only.
Note
/dev/shm
is mounted with nosuid,nodev,noexec
mount options always (both in “isolated /dev/shm
” mode and not). You cannot change this behavior.
Note
“isolated /dev/shm
” mode will become the default in the future CageFS releases.
Note
when the size of the /dev/shm
is specified in percentage of user’s physical memory limit (PMEM), you should remount CageFS after changing PMEM limit in order to change the size of shared memory allocated for the /dev/shm
in user’s CageFS. To do so, execute cagefsctl --remount-all
Preventing process from entering CageFS on error
Starting from CageFS v.7.2.0-1, you can prevent a process from work if it can't enter to CageFS. The option is disabled by default.
To enable it, run the following commands:
touch /etc/cagefs/fail.on.error
cagefsctl --remount-all (cagefsctl --remount <user>)
To disable it, run the following commands:
rm -f /etc/cagefs/fail.on.error
cagefsctl --remount-all (cagefsctl --remount <user>)
The message “Act like CageFS is disabled” in the /var/log/messages
will be displayed regardless the file /etc/cagefs/fail.on.error
is available or not.
Integration with control panels
CageFS comes with a plugin for various control panels.
The plugin allows to:
- Initialize CageFS;
- Select mode of operation;
- See and modify the list of enabled/disabled users;
- Update CageFS skeleton.
cPanel
CageFS Plugin
CageFS plugin for cPanel is located in Plugins section of WHM and called CageFS User Manager .
Note
Take a note that the configuration of CageFS for users is located at the Users tab in the main menu of LVE Manager and the global CageFS settings (Toggle, update skeleton and others) are located at the Options tab in the main menu of LVE Manager inside the section "CageFS".
It allows to initialize CageFS, select users CageFS will be enabled for, as well as update CageFS skeleton.
To enable CageFS for a proper user (users), in CageFS User Manager choose a user from the list on the right ( Disabled users) and click Toggle . The user will move to the list on the left ( Enabled users).
To disable a user (users), choose a user from the list on the left ( Enabled users) and click Disable CageFS . The user will move to the list on the right ( Disabled users).
To update CageFS skeleton, click Update CageFS Skeleton .
CageFS inbuilt in Cloudlinux Manager
To enable or disable CageFS for a proper user (users), in Cloudlinux Manager , go to the Users tab and use the Toggle next to the chosen user(s) from the list under the CageFS column.
To update CageFS skeleton, go to Cloudlinux Manager > Options > CageFS and click on the Update button next to CageFS Skeleton:
Plesk
CageFS is an option inbuilt in Cloudlinux Manager that allows initializing and updating CageFS template, as well as managing users and mode of operation for CageFS.
To enable or disable CageFS for a proper user (users), in Cloudlinux Manager , go to the Users tab and use the Toggle next to the chosen user(s) from the list under the CageFS column.
To update CageFS skeleton, go to Cloudlinux Manager > Options > CageFS and click on the Update button next to CageFS Skeleton:
ISPManager
CageFS comes with plugin for ISP Manager to enable/disable CageFS on per user base. In edit user section chose Permission tab. Mark CageFS User Mode checkbox and click OK to apply.
Or you can manage global CageFS settings via CageFS menu
See also CageFS CLI tools.
MySQL Governor
General information and requirements
Warning
The "All" mode will be deprecated starting from September 1, 2021. You can read more here.
MySQL Governor is software to monitor and restrict MySQL usage in shared hosting environment. The monitoring is done via resource usage statistics per each MySQL thread.
MySQL Governor has two active modes of operations:
- off - In this mode MySQL Governor will not throttle customer's queries, instead it will let you monitor the MySQL usage.
- abusers - In this mode, once user goes over the limits specified in the MySQL Governor, all customer's queries will execute inside that user's LVE.
More details of the governor operation modes are described in the Modes of operation section
MySQL Governor allows to restrict customers who use too much resources. It supports following limits:
CPU | % | CPU speed relative to one core. 150% would mean one and a half cores |
READ | bytes | bytes read. Cached reads are not counted, only those that were actually read from disk will be counted |
WRITE | bytes | bytes written. Cached writes are not counted, only once data is written to disk, it is counted |
You can set different limits for different periods: current, short, med, long. By default those periods are defined as 1 second, 5 seconds, 1 minute and 5 minutes. They can be re-defined using configuration file. The idea is to use larger acceptable values for shorter periods. Like you could allow a customer to use two cores (200%) for one second, but only 1 core (on average) for 1 minute, and only 70% within 5 minutes. That would make sure that customer can burst for short periods of time.
Customers will also be limited to a finite number of concurrent connections, this number is 30 by default and can be changed. This is done so they wouldn't use up all the MySQL connections to the server. MySQL Governor can also kill off slow SELECT queries.
MySQL Governor limits interaction with LVE limits
How is interaction between MySQL Governor and LVE organized?
The main purpose of MySQL Governor is to monitor how many common resources are used by each user for working with MySQL/MariaDB and to manage usage restrictions for such resources by LVE containers.
Before any SQL request, MySQL Governor determines which user sent the request and if this user exceed limits, the MySQL Governor pushes the request to appropriate LVE container.
This is how common server resources can be managed.
Why the СPU/IO charts are different for database and LVE usage?
SQL requests are not limited inside LVE, so there are not any calculations for IO usage there. It can be clearly viewed via the lve-stats charts:
Blue chart (database):
This is the user’s real IO Database usage which was calculated by MySQL Governor.
Green chart (LVE):
This is the user’s IO Database usage which was calculated by lve-stats.
Also, for different types of database load (for example in case, there is a huge amount of short requests), CPU usage charts for LVE and database can be different.
Take a look on this chart:
Blue (database) CPU usage:
It is calculated by MYSQL Governor and the value is identical with top/htop values.
Green (LVE) CPU usage:
It is calculated by lve-stats. The values are less on the LVE CPU usage chart because user requests are placed in the LVE only for part of the time.
For what purpose are the IO limits of MySQL Governor used?
MySQL Governor uses its limits as triggers to place user’s requests to the LVE. If user’s requests exceed MySQL Governor limits they are placed to the LVE, which already limits resource usage. After some timeout (which can be configured in the MySQL Governor config file requests will not be placed to the LVE. The next placing of the SQL requests to the LVE will occur after the next limits are exceeded.
How exactly does IO limiting work for MySQL/MariaDB requests?
There is no direct IO limitation for database treads. But in case of exceeding governor IO user limits, their requests will be placed into the LVE and CPU LVE limitation will be applied to the requests. And it’s clear that any IO load causes CPU load. So by CPU limits IO usage will be limited indirectly.
Take a look at the next chart. The I/O load is synchronous with the CPU load.
Installation and update
Installation
IMPORTANT
Please note that MariaDB 10.4 release isn’t supported by cPanel, thus you can’t install this version with MySQL Governor + cPanel. More details are available here: https://features.cpanel.net/topic/maria-10-4-support.
IMPORTANT
Please make full database backup (including system tables) before you upgrade MySQL or switch to MariaDB. This action will prevent data loss in case if something goes wrong.
MySQL Governor is compatible only with MySQL 5.x, 8.0; MariaDB & Percona Server 5.6.
To install MySQL Governor on your server install governor-mysql package at first:
yum remove db-governor db-governor-mysql # you can ignore errors if you don't have those packages installed
yum install governor-mysql
Then configure MySQL Governor properly.
The installation is currently supported only on cPanel, Plesk, DirectAdmin, ISPmanager, InterWorx , as well as on servers without control panel.
If you are installing CloudLinux OS on a server running MySQL already, set your current MySQL version before calling installation script:
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mysqlXX
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
Please make sure to specify your current MySQL version instead of XX as follows:
- 55 — MySQL v5.5
- 56 — MySQL v5.6
- 57 — MySQL v5.7
- 80 — MySQL v8.0 (requires MySQL Governor 1.2-37+)
If you are installing CloudLinux OS on a server running MariaDB already, do instead:
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mariadbXX
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
Please make sure to specify your current MariaDB version instead of XX as follows:
- 55 — MariaDB v5.5
- 100 — MariaDB v10.0
- 101 — MariaDB v10.1
- 102 — MariaDB v10.2
- 103 — MariaDB v10.3 [requires MySQL Governor 1.2-36+; for cPanel - MySQL Governor 1.2-41+]
- 104 – MariaDB v10.4 [requires MySQL Governor 1.2-53+]
- 105 - MariaDB v10.5 [requires MySQL Governor 1.2-62+]
- 106 - MariaDB v10.6 [requires MySQL Governor 1.2-76+]
- 1011 - MariaDB v10.11 [requires MySQL Governor 1.2-103+]
Updated note
MariaDB version 10.4 is available for CloudLinux OS 6.
Installation for Percona Server 5.6 [requires MySQL Governor 1.1-22+ or 1.2-21+]:
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=percona56
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
Please note that MySQL/MariaDB/Percona will be updated from CloudLinux OS repositories.
If you are installing MySQL Governor on a server without MySQL at all, you have an opportunity to choose desired MySQL version to be installed with MySQL Governor installation script. Use --mysql-version flag before calling the installation script:
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=MYSQL_VERSION
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
MYSQL_VERSION could be chosen from the list of versions currently supported by MySQL Governor :
mysql51 | MySQL v5.1 |
mysql55 | MySQL v5.5 |
mysql56 | MySQL v5.6 |
mysql57 | MySQL v5.7 |
mysql80 | MySQL v8.0 (requires MySQL Governor 1.2-37+) |
mariadb55 | MariaDB v5.5 |
mariadb100 | MariaDB v10.0 |
mariadb101 | MariaDB v10.1 |
mariadb102 | MariaDB v 10.2 |
mariadb103 | MariaDB v 10.3 [requires MySQL Governor 1.2-36+; for cPanel - MySQL Governor 1.2-41+] |
mariadb104 | MariaDB v 10.4 [requires MySQL Governor 1.2-53+] |
mariadb105 | MariaDB v 10.5 [requires MySQL Governor 1.2-62+] |
mariadb106 | MariaDB v 10.6 [requires MySQL Governor 1.2-76+] |
mariadb1011 | MariaDB v 10.11 [requires MySQL Governor 1.2-103+] |
percona56 | Percona Server v 5.6 |
Generally, stable and beta channels contain different version of MySQL packages - beta contains newer version than stable or the same one. If you would like to install beta packages, use --install-beta flag instead of --install when calling installation script:
/usr/share/lve/dbgovernor/mysqlgovernor.py --install-beta
Starting with MySQL Governor version 1.2 when installing MySQL/MariaDB MySQL Governor asks for a confirmation of a database version to be installed. To avoid such behavior for the automatic installations, please use --yes flag.
For example:
/usr/share/lve/dbgovernor/mysqlgovernor.py --install --yes
Please note that restore of previous packages in case of failed installation would also be confirmed with --yes
flag.
IMPORTANT
Use --yes flag on your own risk, because it confirms installation in any case - even in case if there are troubles during installation (for example, network problems causing incomplete download of packages), everything would be confirmed.
Note
See also MySQL Governor CLI
Upgrading database server
Important
Upgrade from MySQL 8 to MariaDB 10.x isn't supported due to compatibility issues between these database server versions and will break your database server completely. You can find more information about the compatibility issues here
Warning
Please note that DB Governor is capable of upgrading your database to a newer version, including sequential upgrades, but we make no guarantee that such upgrades do not affect the operation of the database, its components, control panel operation and other functions of database. Always create a backup copy of your data.
In order to change MySQL version you should run the following commands:
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=MYSQL_VERSION
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
where MYSQL_VERSION
is the target database server version that should be replaced with the value from the table above.
IMPORTANT
Make sure you have full database backup (including system tables) before you switch. This action will prevent data loss in case if something goes wrong.
Uninstalling
To remove MySQL Governor:
/usr/share/lve/dbgovernor/mysqlgovernor.py --delete
The script will install original MySQL server, and remove MySQL Governor.
Configuration and operation
- Configuration
- Modes of operation
- MySQL Governor limits
- Starting and stopping
- Mapping a user to a database
- Log files
- Change MySQL version
- PrivateDevices mode support
Configuration
Warning
The "All" mode will be deprecated starting from September 1, 2021. You can read more here.
MySQL Governor configuration is located in /etc/container/mysql-governor.xml
It is best to modify it using dbctl tool.
Once configuration file is updated, please, restart the MySQL Governor using:
service db_governor restart
<governor>
<!-- 'off' - do not throttle anything, monitoring only -->
<!-- 'abusers' - when user reaches the limit, put user's queries into LVE for that user -->
<!-- 'all' - user's queries always run inside LVE for that user -->
<!-- 'single' - single LVE=3 for all abusers. -->
<!-- 'on' - deprecated (old restriction type) -->
<!-- To change resource usage of restricted user in LVE mode use command /usr/sbin/lvectl set 3 --cpu=<new value> --ncpu=<new value> --io=<new value> --save-all-parameters -->
<lve use="on|single|off|abusers|all"/>
<!-- connection information -->
<!-- If host, login and password are not present, this information is taken from /etc/my.cnf and ~root/.my.cnf -->
<!-- Use symbol specified in prefix to figure out hosting accounts (mysql username will be split using prefix_separator, and first part will be used as account name). If prefix is not set, or empty -- don’t use prefixes/accounts -->
<!-- db governor will try to split MySQL user names using prefix separator (if present)and statistics will be aggregated for the prefix (account name) -->
<connector host="..." login="..." password=".." prefix_separator="_"/>
<!-- Intervals define historical intervals for burstable limits. In seconds -->
<intervals short="5" mid="60" long="300"/>
<!-- log all errors/debug info into this log -->
<log file=”/var/log/dbgovernor-error.log” mode=”DEBUG|ERROR”/>
<!-- s -- seconds, m -- minutes, h -- hours, d -- days -->
<!-- on restart, restrict will disappear -->
<!-- log file will contain information about all restrictions that were take -->
<!-- timeout - penalty period when user not restricted, but if he hit his limit during this period he will be restricted with higher level of restrict (for more long time) -->
<!- level1, level2, level3, level4 - period of restriction user for different level of restriction. During this period all user's requests will be placed into LVE container -->
<!-- if user hits any of the limits during period of time specified in timeout, higher level of restrict will be used to restrict user. If user was already on level4, level4 will be applied again -->
<!-- attribute format set an restrict log format:
SHORT - restrict info only
MEDIUM - restrict info, _all_tracked_values_
LONG - restrict info, _all_tracked_values_, load average and vmstat info
VERYLONG - restrict info, _all_tracked_values_, load average and vmstat info, slow query info -->
<!-- script -- path to script to be triggered when account is restricted -->
<!-- user_max_connections - The number of simultaneous connections of blocked user (in LVE mode) -->
<!-- restriction levels/format are deprecated -->
<restrict level1="60s" level2="15m" level3="1h" level4="1d" timeout="1h"
log="/var/log/dbgovernor-restrict.log" format="SHORT|MEDIUM|LONG|VERYLONG"
script="/path/to/script"
user_max_connections="30"/>
<!-- period (deprecated) - period based restriction that has multiple levels (see above) -->
<!-- limit (by default) - when user hits limits, the account will be marked as restricted and if user does not hit limit again during "unlimit=1m" account will be unrestricted. This mode doesn't have any additional levels/penalties. -->
<restrict_mode use="period|limit" unlimit="1m"/>
<!-- killing slow SELECT queries (no other queries will be killed) -->
<!-- if "log" attribute was set all killed queries will be saved in log file -->
<!-- slow parameter in the <limit name="slow" current="30"/> will no be applied without enabling slow_queries -->
<slow_queries run="on|off" log="/var/log/dbgovernor-kill.log"/>
<!-- Enable or disable saving of statistics for lve-stats - On - enabled, Off-disabled -->
<statistic mode="on|off"></statistic>
<!-- Enable logging user queries on restrict, can be On or Off -->
<!-- Files are saved in /var/lve/dbgovernor-store and being kept here during 10 days -->
<logqueries use="on|off"></logqueries>
<default>
<!-- -1 not use limit(by default, current - required) -->
<limit name="cpu" current="150" short="100" mid="90" long="65"/>
<limit name="read" current="100000000" short="90000000" mid="80000000" long="70000000"/>
<limit name="write" current="100000000" short="90000000" mid="80000000" long="70000000"/>
<!-- Time to kill slow SELECT queries for account, can be different for accounts in seconds(but unit can be specified) -->
<!-- enabled only when slow_queries run="on" -->
<!-- s -- seconds, m -- minutes, h -- hours, d -- days -->
<!-- Requests are checked at 15 second intervals, so a request will be canceled after a timeout + 15 seconds maximum -->
<limit name="slow" current="30"/>
</default>
<!-- name will matched account name, as extracted via prefix extraction -->
<!-- mysql_name will match exact MySQL user name. If both name and mysql_name are present, system will produce error -->
<!-- mode restrict -- default mode, enforcing restrictions -->
<!-- mode norestrict -- track usage, but don’t restrict user -->
<!-- mode ignore -- don’t track and don’t restrict user -->
<user name=”xxx” mysql_name=”xxx” mode=”restrict|norestrict|ignore”>
<limit...>
</user>
<!-- debug mode for particular user. The information logged to restrict log. -->
<debug_user name="xxx"/>
</governor>
These values can also be set using cloudlinux-config CLI utility
Modes of operation
Warning
The "All" mode will be deprecated starting from September 1, 2021. You can read more here.
Note
MySQL Governor 1.0+
Active modes
- abusers - Use LVE for a user to restrict queries (default mode): In that mode, once user goes over the limits specified in the MySQL Governor , all customer's queries will execute inside that user's LVE. We believe this mode will help with the condition when the site is still fast, but MySQL is slow (restricted) for that user. If someone abuses MySQL, it will cause queries to share LVE with PHP processes, and PHP processes will also be throttled, causing fewer new queries being sent to MySQL. Requires
dbuser-map
file. - off - Monitor Only: In that mode MySQL Governor will not throttle customer's queries, instead it will let you monitor the MySQL usage to see the abusers at any given moment in time (and historically). This mode is good when you are just starting and want to see what is going on.
Deprecated modes
- all - Always run queries inside user's LVE (will be deprecated on September 1, 2021): This way there is no need for separate limits for MySQL. Depending on overhead we see in the future, we might decide to use it as a primary way of operating MySQL Governor . The benefit of this approach is that limits are applied to both PHP & MySQL at the same time, all the time, preventing any spikes whatsoever. Requires
dbuser-map
file. - single - Single restricted's LVE for all restricted customers (deprecated): In that mode once customer reaches the limits specified in the MySQL Governor , all customer's queries will be running inside LVE with id 3. This means that when you have 5 customers restricted at the same time, all queries for all those 5 customers will be sharing the same LVE. The larger the number of restricted customers - the less resources per restricted customer will be available.
- on - Synonym for single mode
Note
After the all
mode will be deprecated on September 1, 2021:
- the users, having it, will continue to work with this mode;
- all new installation will not have the
all
mode; - moving to the
all
mode will be forbidden.
If the dbuser-map
file is absent on the server, the abusers
mode emulates the single
.
With the single
and abusers
mode, once user is restricted, the queries for that user will be limited as long as user is using more than limits specified. After a minute that user is using less, we will unrestricted that user.
You can specify modes of operation using dbctl or by changing configuration file.
MySQL Governor limits
MySQL Governor limit setting recommendations
Note
Please note that these recommendations on setting limits for MySQL Governor are general. The exact values of the limits for the effective work of MySQL and the site as a whole depend on many factors.
Here they are:
- the load of the virtual server with incoming requests
- the database size
- SQL queries efficiency
- absolute values of the LVE limits
MySQL Governor allows setting the burstable limits for accounts. To provide that possibility, four levels of limits are defined: current
, short
, middle
, and long
. Correctly set limits can give users more CPU without having a bottleneck on MySQL.
General principles of choosing the limits:
current
andshort
can be more than the LVE limit and should not be less- setting the
current
andshort
limits more than the LVE limit prevents bottlenecks in SQL request processing middle
limit can be more or less that the LVE limitlong
on the contrary, should not be more than the LVE limit- setting the
middle
andlong
limits less than the LVE limit prevents abuse of other processes in the account (Apache, PHP) by MySQL
Example of choosing MySQL Governor limits
- With the default LVE SPEED limit is
100
, the possible values of the MySQL Governor CPU limits can be 250/150/110/90. I.e., we admit the short-term exceeding of the limits for processing SQL requests. - If you face spike CPU consumption with these limits, it is recommended to reduce the excess of the
current
andshort
limits over the LVE limit. For example, to the values 150/110/100/90. - If the average level of CPU consumption is too high, then it is recommended to reduce the
middle
andlong
limits, too. For example, to the values 150/100/80/50. - Then MySQL processes will fall into LVE and be limited by LVE limits more often.
- The same clues are applicable to the IO limits – the
current
andshort
IO limits for MySQL Governor can exceed IO LVE limits, but themiddle
andlong
cannot.
Starting and stopping
To start:
service db_governor start
To stop:
service db_governor stop
Mapping a user to a database
[ MySQL Governor 1.x]
Traditionally MySQL Governor used prefixes to map user to database. With the latest version, we automatically generate user -> database user mapping for cPanel , Plesk and DirectAdmin control panels.
The mapping file is recreated daily by cron.
Mapping recreation is also triggered by the following events on cPanel servers:
- creation of user
- modification of user
- removal of user
You can also rebuild the mapping file manually on cPanel, Plesk and DirectAdmin control panels by running the following command:
/usr/share/lve/dbgovernor/mysqlgovernor.py --dbupdate
The mapping file is located in: /etc/container/dbuser-map
The format of the file:
[dbuser_name1] [account_name1] [UID1]
...
[dbuser_nameN] [account_nameN] [UIDN]
pupkinas_u2 pupkinas 502
pupkinas_u1 pupkinas 502
pupkinas_u3 pupkinas 502
pupkin2a_uuu1 pupkin2a 505
pupkin10_p10 pupkin10 513
pupkin5a_u1 pupkin5a 508
pupkin3a_qq1 pupkin3a 506
pupkin3a_test22 pupkin3a 506
pupkin3a_12 pupkin3a 506
This would specify that db users: pupkinas_u2, pupkinas_u1, pupkinas_u3 belong to user pupkinas with uid (lve id) 502 db user pupkin2a_uuu1 belongs to user pupkin2a with uid 505, etc...
db_governor
service checks this file for modifications every 5 minutes.
If you need to force reload the mapping file, run:
service db_governor restart
Log files
Error_log
MySQL Governor error log is used to track any problems that MySQL Governor might encounter. Error log is located in /var/log/dbgovernor-error.log
Restrict_log
Restrict log is located in /var/log/dbgovernor-restrict.log
Restrictions:
_timestamp_ _username_ LIMIT_ENFORCED _limit_setting_ __current_value_ _restrict_level__ SERVER_LOAD TRACKED_VALUES_DUMP
...
- TRACKED_VALUES_DUMP=busy_time:xx,cpu_time:xx,...
- SERVER_LOAD = load averages followed by output of vmstat
- TRACKED_VALUES_DUMP is available with MEDIUM & LONG format
- SERVER_LOAD is available with LONG format
Kill_log
MySQL Governor kill log is optional log located in the /var/log/dbgovernor-kill.log. Kill log is used to track all killed queries
Change MySQL version
If you would like to change to a different MySQL version, or switch to MariaDB you have to start by backing up existing databases.
Note
For experienced users only. Changing MySQL version is a quite complicated procedure, it causes system table structural changes which can lead to unexpected results. Think twice before proceeding.
IMPORTANT
Please make full database backup (including system tables) before you will do upgrade of MySQL or switch to MariaDB. This action will prevent data losing in case if something goes wrong.
/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=MYSQL_VERSION
/usr/share/lve/dbgovernor/mysqlgovernor.py --install
- If you are using cPanel or DirectAdmin - recompile Apache .
To install beta version of MySQL:
/usr/share/lve/dbgovernor/mysqlgovernor.py --install-beta
MYSQL_VERSION can be one of the following:
auto | default version of MySQL for given OS release (or cPanel settings) |
mysql51 | MySQL v5.1 |
mysql55 | MySQL v5.5 |
mysql56 | MySQL v5.6 |
mysql57 | MySQL v5.7 |
mysql80 | MySQL v8.0 (requires MySQL Governor 1.2-37+) |
mariadb55 | MariaDB v5.5 |
mariadb100 | MariaDB v10.0 |
mariadb101 | MariaDB v10.1 |
mariadb102 | MariaDB v 10.2 |
mariadb103 | MariaDB v 10.3 [requires MySQL Governor 1.2-36+; for cPanel - MySQL Governor 1.2-41+ ] |
mariadb104 | MariaDB v 10.4 [requires MySQL Governor 1.2-53+] |
percona56 | Percona v 5.6 |
- We don't recommend to downgrade from MySQL v5.6, MariaDB 10.x
Note
cPanel does not officially support MariaDB 10.4, that is why we don’t recommend to use it on cPanel servers. Use on your own risk for Plesk servers, because downgrade can corrupt your databases.
Note
MariaDB version 10.4 is not available for CloudLinux OS 6 yet.
Note
See also MySQL Governor CLI
PrivateDevices mode support
MySQL Governor v. 1.2-66 and later on Cloudlinux OS 7 and 8 supports the PrivateDevices mode for the mysqld service.
To switch on the PrivateDevices mode, follow these steps.
On Cloudlinux OS 7
- Make sure that the systemd version is at least 219-78.2.cloudlinux.1
- Add the following instruction into the Service section of the mysqld service file:
PrivateDevices=true
- Invoke
systemctl daemon-reload
- Restart mysqld service
On Cloudlinux OS 8
- Add the following instructions into the Service section of the mysqld service file:
PrivateDevices=true DeviceAllow=/dev/lve BindPaths=/dev/lve
- Invoke
systemctl daemon-reload
- Restart mysqld service
Backing up MySQL
On cPanel server disable MySQL service monitoring before doing the job:
whmapi1 configureservice service=mysql enabled=1 monitored=0
The following script could be used before installing MySQL-governor and MySQL/MariaDB packages to create the backup:
/usr/share/lve/dbgovernor/scripts/mysql_backup.sh
The script mysql_backup.sh
is provided starting from the Governor version 1.2-115.
On cPanel server enable monitoring back:
whmapi1 configureservice service=mysql enabled=1 monitored=1
Note
This operation may take some time.
See also MySQL Governor CLI tools.
MySQL Governor improvements for CPU calculation
In MySQL Governor version 1.2-81, we provide improvements in the algorithm of calculation user CPU usage. New behavior helps to increase precision of resource distribution between server users. By default the new type of CPU usage calculation is tuned on.
Server administrator can turn on/off the new type of CPU usage calculation by using the following command:
dbctl --lve-improved-accuracy off
What is the impact of improvements?
The calculation of CPU usage has become more accurate, so the dbtop
utility provides more correct information to the MySQL Governor and it places user’s requests to the LVE in a proper moment. And as a result, such improvements reduce the possibility of absorbing whole server resources by one user.
One mpre possible outcome of calculation improvements is that some server users will become in need of MySQL Governor limits reconfiguration.
How to view the impact of improvements?
Let’s check the CPU usage charts from CloudLinux statistics (lve-stats).
The new type of CPU usage calculation is turned off.
In this case, CPU usage by database could be less than LVE average CPU usage (blue chart is lower than green chart):
The new type of CPU usage calculation is turned on.
In this case, CPU usage by database become more similar to LVE average CPU usage (blue chart and green chart on the sceen):
FAQ
How is interaction between MySQL Governor and LVE organized?
The main purpose of MySQL Governor is to monitor how many common resources are used by each user for working with MySQL/MariaDB and to manage usage restrictions for such resources by LVE containers.
Before any SQL request, MySQL Governor determines which user sent the request and if this user exceed limits, the MySQL Governor pushes the request to appropriate LVE container.
This is how common server resources can be managed.
Why the СPU/IO charts are different for database and LVE usage?
SQL requests are not limited inside LVE, so there are not any calculations for IO usage there. It can be clearly viewed via the lve-stats charts:
Blue chart (database):
This is the user’s real IO Database usage which was calculated by MySQL Governor.
Green chart (LVE):
This is the user’s IO Database usage which was calculated by lve-stats.
Also for different types of database load (for example in case, there is a huge amount of shot requests), CPU usage charts for LVE and database can be different.
Take a look on this chart:
Blue (database) CPU usage:
It is calculated by MYSQL Governor and the value is identical with top/htop values.
Green (LVE) CPU usage:
It is calculated by lve-stats. The values are less on the LVE CPU usage chart because user requests are placed in the LVE only for part of the time.
For what purpose are the IO limits of MySQL Governor used?
MySQL Governor uses its limits as triggers to place user’s requests to the LVE. If user’s requests exceed MySQL Governor limits they are placed to the LVE, which already limits resource usage. After some timeout (which can be configured in the MySQL Governor config file requests will not be placed to the LVE. The next placing of the SQL requests to the LVE will occur after the next limits are exceeded.
How exactly does IO limiting work for MySQL/MariaDB requests?
There is no direct IO limitation for database treads. But in case of exceeding governor IO user limits, their requests will be placed into the LVE and CPU LVE limitation will be applied to the requests. And it’s clear that any IO load causes CPU load. So by CPU limits IO usage will be limited indirectly.
Take a look at the next chart. The I/O load is synchronous with the CPU load.
Troubleshooting
MariaDB 5.5 and MariaDB 10.0: How to set LimitNOFILE correctly for systemd.
MariaDB 5.5 and MariaDB 10.0 have only file for managing the service, but the file has LSB functions, so it is supported by systemd
.
For adding extra limits, do the following:
- Run:
mkdir /etc/systemd/system/mariadb.service.d/
- Run:
touch /etc/systemd/system/mariadb.service.d/limits.conf
- Add the following content to the the file
/etc/systemd/system/mariadb.service.d/limits.conf
:
[Service]
LimitNOFILE=99999
MySQL Governor lost connection to MySQL - “Can't connect to mysql” messages in /var/log/dbgovernor-error.log (Plesk and DirectAdmin)
This may be caused by changing root/administrator credentials without updating MySQL Governor configuration file.
When you change root or administrator credentials in Plesk or DirectAdmin, you also need to update MySQL Governor configuration file. This could be done with the following command (available since governor-mysql 1.2-38):
/usr/share/lve/dbgovernor/mysqlgovernor.py --update-config-auth
The command updates credentials in MySQL Governor configuration file and restarts db_governor
service afterwards.
After applying the command MySQL Governor successfully connects to MySQL.
Handling Missing Libraries in cl-MariaDB-libs for MySQL Governor (libgovernor_stubs.so)
During the update of latest cl-MariaDB-libs
, issues related to the addition or removal of certain shared libraries in cl-MySQL/cl-MariaDB packages may arise. The presence or absence of these libraries can disrupt the functioning of clients' systems.
When you encounter errors pointing towards missing or newly added libraries after updating the cl-MySQL/cl-MariaDB packages, it's crucial to adjust and address the configurations to restore normalcy.
For instance, the error might resemble the following message:
ImportError: libexample_stubs.so: cannot open shared object file: No such file or directory
The recommended approach to resolving such issues involves three primary steps:
- Verify the Presence of the Library.
Use the command to ascertain the library's presence in the current version:
yum provides '*/libexample_stubs.so'
- Recompiling the Affected Package.
Recompile the affected package for each user, especially if using Python's mysql package (mysqlclient
):
pip install mysqlclient --force --no-cache-dir
However, this is not the ideal solution since sites that are functional may break after a system update.
- Using Utilities to Modify Binary.
If recompilation isn't feasible, patchelf
utility can help remove references to the missing library in the binary:
patchelf --remove-needed libexample_stubs.so path/to/affected/binary.so
Applying the aforementioned steps should rectify the issues, allowing MySQL Governor to function correctly with the updated libraries in cl-MySQL/cl-MariaDB packages.
Always remember to back up your data and configurations before making any changes to ensure a safety net in case of any inadvertent errors. If you continue to face challenges, please reach out to our support team for assistance.
Known limitations
I/O LVE limits don't work for user’s SQL queries
In the MySQL Governor default mode, once users go over the limits, all their SQL queries will execute inside that user's LVE.
This technique was provided with the early 1.1.5 version of MySQL Governor.
It turned out that memory limitation for MySQLrequests causes the OOM (Out Of Memory) issues and as a result database corruptions. So, it was decided not to apply LVE memory limits for SQL queries supplied by MySQL Governor. But the internal implementation of LVE is such that I/O and memory limits work together. That’s why the I/O LVE limits do not apply for user’s SQL queries now.
Nevertheless, SQL queries inside LVE are restricted by CPU limit which indirectly limits I/O usage, too.
PHP Selector
General information and requirements
The main requirements:
- CageFS is installed
- Alt-PHP packages are installed
- Mod_suexec is installed. You can find installation instruction here
- CageFS is initialized without errors
- CageFS is enabled for a domain user-owner
- An appropriate PHP handler is selected for PHP version which is system version. PHP Selector is compatible with the following technologies: suPHP, mod_fcgid, CGI (suexec), LiteSpeed. See also Compatibility Matrix.
- PHP version in the CloudLinux OS PHP selector does not equal to the Native PHP version
Note
PHP Selector is not supported for H-Sphere.
Note
PHP Selector requires native PHP to be installed, otherwise you will get an error message with a proposal to install PHP package. Here are some instructions for different control panels:
After installing native PHP, please run the cloudlinux-selector setup --interpreter=php --json
command in order to reconfigure CageFS and LVE Manager.
Supported versions
The mark x
stands for a supported version.
Cloudlinux 6 | Cloudlinux 7 | Cloudlinux 8 | Cloudlinux 9 | |
---|---|---|---|---|
alt-php 5.1 | x | x | x | |
alt-php 5.2 | x | x | x | x |
alt-php 5.3 | x | x | x | x |
alt-php 5.4 | x | x | x | x |
alt-php 5.5 | x | x | x | x |
alt-php 5.6 | x | x | x | x |
alt-php 7.0 | x | x | x | x |
alt-php 7.1 | x | x | x | x |
alt-php 7.2 | x | x | x | x |
alt-php 7.3 | x | x | x | x |
alt-php 7.4 | x | x | x | x |
alt-php 8.0 | x | x | x | x |
alt-php 8.1 | x | x | x | x |
alt-php 8.2 | x | x | x | x |
alt-php 8.3 | x | x | x | x |
Installation and update
The installation of PHP Selector presumes that you already have CageFS & LVE Manager installed.
Use compatibility matrix to check if your Web Server/PHP mode is supporting PHP Selector. If not, you need a change to one of the supported models.
Installation of different versions of PHP & modules:
yum groupinstall alt-php
Update CageFS & LVE Manager with support for PHP Alternatives:
$ yum update cagefs lvemanager
cPanel/WHM: Make sure 'Select PHP version' is enabled in Feature Manager .
IMPORTANT
Please, do not use settings like SuPHP_ConfigPath
, PHPRC
, PHP_INI_SCAN_DIR
. Do not redefine path to php.ini
and ini-files for PHP modules. Doing that can break PHP Selector functionality.
For example, alternative php5.2 versions should load /opt/alt/php52/etc/php.ini
file and scan /opt/alt/php52/etc/php.d
directory for modules:
Configuration File (php.ini) Path /opt/alt/php52/etc
Loaded Configuration File /opt/alt/php52/etc/php.ini
Scan this dir for additional .ini files /opt/alt/php52/etc/php.d
additional .ini files parsed /opt/alt/php52/etc/php.d/alt_php.ini
Those are default locations for alt-php.
If you need custom PHP settings per user, please change them via "Edit PHP settings" feature of PHP Selector .
If a list of default modules is absent on the server in the /etc/cl.selector/defaults.cfg
file for some alt-PHP version and there is nd_mysqli
extension in this version, then on installation/update of the LVE Manager the mysqli
extension will be disabled and nd_mysqli
extension will be enabled automatically.
- If nd_mysqli module is absent or a list of enabled modules is available, then they won't be changed automatically.
- If alt-PHP is not installed on LVE Manager installation/update, then they won’t be changed automatically.
To change the modules status (enabled/disabled) manually, run the following command in a console:
/usr/sbin/cloudlinux-selector make-defaults-config --json --interpreter=php
Update
To update PHP Selector, run the following command:
yum groupupdate alt-php
This command allows to install newly released versions in PHP Selector.
Note
See also PHP Selector CLI
Installation instructions for cPanel users
- Install CageFS as root via SSH:
yum install cagefs
- Install
alt-php
packages as root:
yum groupinstall alt-php
- Install
mod_suexec
package as root. See installation instructions here. - Verify that CageFS is initialized successfully.
- via SSH by running the following command:
cagefsctl --check-cagefs-initialized
- via cPanel admin interface
Go to cPanel → Admin interface → LVE Manager → Dashboard → click Refresh
If there is a problem you can see Not initialized
- Initilize CageF (if it is not initialized)
- Via SSH
cagefsctl --init
Via cPanel admin interface
Go to cPanel → Admin interface → LVE manager → Options → CageFS INIT
If CageFS was initialized after refreshing Dashboard you will see that CageFS is enabled:
- Enable CageFS to a user
Go to cPanel → Admin interface → LVE manager → Users
- For one user by individual slider (for LVE 1001 in the picture above)
- For a group of user by the CageFS button (for LVE 1002 and 1003 in the picture above)
- Check that system PHP version is not
alt-php
(it should beea-php
)
Go to cPanel → Admin interface → MultiPHP Manager → PHP versions
- Check that an appropriate PHP handler is selected for PHP version which is system version
Go to cPanel Admin interface → MultiPHP Manager → PHP Handlers
- Check version for domain in MultiPHP Selector. It should be equal to the system default version
Go to cPanel Admin interface → MultiPhp Manager → PHP versions → scroll to Set PHP Version per Domain
- Version for domain in User’s interface in PHP Selector should not be equal to the Native version.
LiteSpeed support
Note
LiteSpeed detects CloudLinux OS and applies all settings out-of-the-box.
Note
If your LiteSpeed is installed to a non-standard, custom location path, create a symlink: ln -s /path/to/custom/lsws /usr/local/lsws
then run cagefsctl --setup-cl-selector
.
If the settings were not applied, you can use the following steps to set up LiteSpeed to use PHP Selector.
- Follow PHP Selector installation guide.
- Make sure the following settings are set in the LSWS Web Admin console:
- Configuration ➞ Server ➞ General ➞ CloudLinux OS:
CageFS
orCageFS without suEXEC
- Configuration ➞ Server ➞ General ➞ PHP suEXEC:
Yes
How to set up LiteSpeed version 5.3+ to use PHP Selector
For Plesk
For other control panels
Additionally, we recommend setting up the following parameters:
- Configuration ➞ Server ➞ PHP:
- Click Edit in the PHP Handler Defaults section
- Set Yes in the Run On Startup
- Make sure to set Max Idle Time (for example to 140)
How to set up LiteSpeed version lower than 5.3 to use PHP Selector
Go to the External App tab, External Application ➞ Add.
- The Command line should be
/var/www/cgi-bin/cgi_wrapper/cloudlinux_wrapper
on Plesk. - For other control panels, the Command line should be
/usr/local/bin/lsphp
. - The Run On Start Up line must contain
Yes
orNo
.
For Plesk
For other control panels
Settings in text format:
Name | lsphp_selector |
Address | uds://tmp/lshttpd/lsphp_selector.sock |
Notes | Not Set |
Max Connections | 35 |
Environment | PHP_LSAPI_MAX_REQUESTS=5000 PHP_LSAPI_CHILDREN=35 |
Initial Request Timeout (secs) | 60 |
Retry Timeout (secs) | 0 |
Persistent Connection | Yes |
Connection Keepalive Timeout | Not Set |
Response Buffering | No |
Auto Start | Through CGI Daemon (Async) |
Command | * For Plesk /var/www/cgi-bin/cgi_wrapper/cloudlinux_wrapper * For other control panels /usr/local/bin/lsphp |
Back Log | 100 |
Instances | 1 |
suEXEC User | Not Set |
suEXEC Group | Not Set |
umask | Not Set |
Run On Start Up | Yes |
Max Idle Time | 70 |
Priority | 0 |
Memory Soft Limit (bytes) | 2047M |
Memory Hard Limit (bytes) | 2047M |
Process Soft Limit | 400 |
Process Hard Limit | 500 |
Go to the Script Handler tab. For required suffixes, change the Handler Name to lsphp_selector
.
Note
In order to use PHP Selector and custom php.ini, lsphp5 needs to be in SuEXEC non-daemon mode.
Note
Some PHP configurations require more memory for SuExec to work properly. If you are getting error 500 after switching suEXEC to non-daemon mode, try to increase Memory Soft Limit and Memory Hard Limit for external App to at least 650/800M.
ISPmanager support
As of July 2013, PHP Selector support for ISPmanager is limited to command line utilities. You should still be able to use it.
As always, PHP Selector requires CGI, FCGI or suPHP to work.
You will need to do following modifications:
Create new file /usr/local/bin/php-cgi-etc:
#!/bin/bash
/usr/bin/php-cgi -c /etc/php.ini "$@"
chmod +x /usr/local/bin/php-cgi-etc
Add a line:
path phpcgibinary /usr/local/bin/php-cgi-etc
Make sure there is no other lines with path phpcgibinary
defined in the file.
Restart ISPmanager :
killall ispmgr
After that FCGID wrappers (/var/www/[USER]/data/php-bin/php
) for new users will be like this:
#!/usr/local/bin/php-cgi-etc
You might need to edit/modify wrappers for existing users if you want them to be able to use PHP Selector. You can leave them as is for users that don't need such functionality.
Uninstalling
It is not possible to remove PHP Selector from the system completely as it is an essential part of LVE Manager and CageFS packages. However, you can make PHP Selector unavailable for cPanel and Plesk users.
To do so, go to LVE Manager → PHP Selector and check Disabled as PHP Selector status. Doing so allows you to disable web-interface of the PHP Selector in the user interface but does not reset custom settings (choosing a version of PHP and modules).
To disable PHP Selector and make it has no effect on a PHP version on the sites, run the following command:
- this command resets PHP versions to Native:
cagefsctl --cl-selector-reset-versions
- this command resets PHP modules to Default:
cagefsctl --cl-selector-reset-modules
These commands can affect PHP version of your clients’ web sites. Use them with caution as improper usage might cause your clients’ web sites down.
Note
It is possible to manually uninstall the integral parts of PHP Selector - alt-php packages. However, since CloudLinux OS components heavily rely on them, we do not recommend doing so. Proceed with caution and keep an eye on yum dependencies if you decide to uninstall the packages.
Disabling PHP extension globally
If you want to disable PHP extension globally, you don't need to remove file /opt/alt/phpXX/etc/php.d.all/$EXTENSION.ini . You should just comment out "extension=" directives in it.
The extension will be visible in PHP Selector interface, but selecting it in users's interface will take no effect - extension will be disabled in fact.
Reinstalling of alt-php
packages will not reset settings (will not enable extension again).
Configuration and using
- Setting default version and modules
- Individual PHP.ini files
- How to add additional php.ini file for a user inside CageFS
- Substitute global php.ini for individual customer
- How to substitute global php.ini for individual customer on cPanel server with EasyApache4
- Managing interpreter version
- Including PHP Selector only with some packages - cPanel
- PHP extensions
- FFmpeg
- Native PHP configuration
- How to configure alt-php72-zts to use with PHP Selector
- Using
- Custom PHP.ini options
- End user files and directories
- Compiling your own extensions
- Roll your own PHP
- Detect user's PHP version
- PHP Selector without CageFS
- Configuring "global” php.ini options for all Alt-PHP versions
Setting default version and modules
Administrator can set default interpreter version and extensions for all users. All file operations are actually done by CageFS. CageFS takes settings from /etc/cl.selector/defaults.cfg. Currently the /etc/cl.selector/defaults.cfg is created and handled by CloudLinux OS PHP Selector scripts. It has the following format:
[global]
selector=enabled
[versions]
php=5.4
[php5.4]
modules=json,phar
[php5.3]
modules=json,zip,fileinfo
Individual PHP.ini files
For each customer, inside CageFS, file alt_php.ini is located in /etc/cl.php.d/alt-phpXX (XX - version of PHP, like 52 or 53). The file contains PHP extension settings and extension directives selected by customer. This file exists for each customer, for each PHP version.
Note, that this is 'local' to CageFS, and different users will have different files. The file is not visible in /etc/cl.php.d outside CageFS. If you would like to view that file, use:
# cagefsctl -e USERNAME
to enter into CageFS for that user. Then type: exit
; to exit from CageFS
This file has to be updated using cagefsctl --rebuild-alt-php-ini
after updating alt-php RPMs
Admin can change individual settings for PHP extensions by changing that extension's ini file, like editing /opt/alt/php54/etc/php.d.all/eaccelerator.ini and then running:
cagefsctl --rebuild-alt-php-ini
How to add additional php.ini file for a user inside CageFS
If you want to create additional php.ini
file for a user inside CageFS in order to change some specific PHP options for that user, you can execute the following:
su -s /bin/bash - USER
cd /etc/cl.php.d/alt-php72/
echo "upload_tmp_dir=/tmp" >> custom.ini
The commands above create custom.ini
file that will be used for alt-php72
. By default this approach is valid only for alt-php version selected via PHP Selector. When /etc/cl.selector/symlinks.rules
file contains php.d.location = selector
line, then the approach is valid for all alt-php versions regardless whether it is selected in PHP Selector or not.
You can find more details here.
But the recommended way is to modify PHP options via PHP Selector web or CLI interfaces, as described here.
Substitute global php.ini for individual customer
Sometimes you might want to have a single customer with a different php.ini, than the rest of your customers.
To do that, you will use custom.etc directory functionality
- Move default php.ini into /etc directory and create a symlink to it:
mv /usr/local/lib/php.ini /etc/php.ini
ln -fs /etc/php.ini /usr/local/lib/php.ini
- Change path to php.ini in /etc/cl.selector/native.conf file to:
php.ini=/etc/php.ini
- For each user that needs custom file, create directory /etc/cagefs/custom.etc/USER_NAME/php.ini .
For example if you want to create custom for USER1 and USER2 you would create files:
/etc/cagefs/custom.etc/USER1/php.ini
/etc/cagefs/custom.etc/USER2/php.ini
Create such files for each user that should have custom file.
- Execute:
cagefsctl --force-update
Notes
Make sure that
php.ini
load path is set to/etc/php.ini
Users will be able to override settings of those php.ini files (global or custom) via PHP Selector. If you want to prevent that, you should disable PHP Selector feature.
Even if PHP Selector is disabled, user can override PHP settings by using
ini_set() php
function in PHP script, or byphp -c
command line option.If you modify anything in
/etc/cagefs/custom.etc
directory, you should execute:
cagefsctl --update-etc
in order to apply changes to CageFS for all users.
OR
cagefsctl --update-etc user1 user2
to apply changes to CageFS for specific users.
How to substitute global php.ini for individual customer on cPanel server with EasyApache4
Note
It is enough to put php.ini
in the directory where PHP script is located in order to run the PHP script with a custom php.ini
when using SuPHP. Also, you can use cPanel MultiPHP Manager to create user’s custom php.ini
file, and this approach should work for CGI, FCGI, and LSAPI. Recommended ways to manage php.ini
settings per user are to use cPanel MultiPHP or CloudLinux OS PHP Selector interfaces.
For each user that needs custom file, create directory
/etc/cagefs/custom.etc/USER_NAME/php.ini
.For example, if you want to create a custom file for USER1 and USER2 you would create files:
/etc/cagefs/custom.etc/USER1/php.ini /etc/cagefs/custom.etc/USER2/php.ini
Create such files for each user that should have a custom file.
Execute the following command:
$ cagefsctl --force-update
Configure
php.ini
load path for user’s domains.
When using suphp handler, you should use
SuPHP_ConfigPath
directive in virtual host configuration for these domains, or use this directive in.htaccess
files:suPHP_ConfigPath/etc
.When using mod_lsapi, you should use
lsapi_phprc
directive in virtual host configuration:lsapi_phprc/etc/
. You can find the detailed description ofmod_lsapi
directives here.When using FCGI or CGI, you should implement custom PHP wrapper and redefine the path to
php.ini
via-c
command line option, like below:#!/bin/bash [ -f /etc/php.ini ] && exec /usr/bin/php -c /etc/php.ini exec /usr/bin/php
Notes:
You should restart Apache web server after modifying virtual host configuration for the domains.
Custom
php.ini
may break switching PHP version via CloudLinux OS PHP Selector or cPanel MultiPHP Manager for the appropriate users or domains.When using cPanel ea-php for the domains, additional
php.ini
files may not be loaded, so you should load all needed PHP extensions in custom/etc/php.ini
file:When using CloudLinux OS alt-php, additional
php.ini
files will be loaded:If you have modified anything in
/etc/cagefs/custom.etc
directory, you should execute one of the following:- to apply changes to CageFS for all users, run:
cagefsctl --update-etc
- to apply changes to CageFS for specific users, run:
cagefsctl --update-etc user1 user2
Managing interpreter version
Managing interpreter versions is done by means of manipulating a set of symbolic links that point to different versions of interpreter binaries. For example, if default PHP binary is /usr/local/bin/php
:
- First we move the default binary inside CageFS to
/usr/share/cagefs-skeleton/usr/selector
, and make /usr/local/bin/php a symlink pointing to /etc/cl.selector/php . This operation is done as part of CageFS deployment. - Next suppose we have additional PHP version, say 7.2.5. The information about all additional interpreter binaries and paths for them is kept in /etc/cl.selector/selector.conf . This config file is updated by RPM package manager each time alternative PHP package is added, removed or updated
/usr/bin/selectorctl --list --interpreter=php
will get us list of all available PHP interpreter versions out of /etc/cl.selector/selector.conf file . Next we want to know which PHP version is active for a given user (to supply a selected option in options list). We type:/usr/bin/selectorctl --user USERNAME --interpreter=php --user-current
will retrieve PHP version set for a particular user. The script gets the path from/var/cagefs/LAST_TWO_DIGITS_OF_UID/USERNAME/etc/cl.selector/php
symlink, compares it with contents of /etc/cl.selector/selector.conf file and if path is valid, prints out the current interpreter version./usr/bin/selectorctl --user USERNAME --interpreter=php --set-user-current=7.2
sets the current PHP version for particular user by creating symlink in/var/cagefs/LAST_TWO_DIGITS_OF_UID/USERNAME/etc/cl.selector
directory. All old symlinks are removed, and new symlinks are set.
Including PHP Selector only with some packages (cPanel)
cPanel has a ' Feature Manager ' in WHM that allows you to disable PHP Selector for some of the packages that you offer.
In reality it only disables the icon in cPanel interface. Yet, in most cases it should be enough in shared hosting settings.
You can find more info on ' Feature Manager ' here: http://docs.cpanel.net/twiki/bin/view/11_30/WHMDocs/FeatureManager
Once PHP Selector is enabled, you can find it in the Feature Manager . Disabling it in Feature Manager , will remove the icon for users that are using that particular 'Feature List'
PHP extensions
Configuring Alt-PHP modules loading
CloudLinux OS PHP Selector and Alt-PHP can be used in conjunction with Plesk PHP Selector and cPanel MultiPHP . To be compatible, CloudLinux OS PHP Selector works as follows: modules that are selected in CloudLinux OS PHP Selector are loaded for Alt-PHP version selected in CloudLinux OS PHP Selector only. For the rest Alt-PHP versions default module set is loaded ( /opt/alt/phpXX/etc/php.d/default.ini ) . Described above is default behavior.
Note
If system default PHP version selected in cPanel MultiPHP Manager is not ea-php, then default module set is loaded for all Alt-PHP versions by default (/opt/alt/phpXX/etc/php.d/default.ini).
When "php.d.location = selector" option is in effect, modules selected via PHP Selector will be loaded for all alt-php versions.
This behavior is implemented in CageFS-6.1-10 and later.
In LVE Manager 1.0-9.40+ this behavior can be modified so that modules selected in CloudLinux OS PHP Selector would be loaded for all Alt-PHP versions (with CageFS enabled), which can be quite useful if you use ‘ per directory ’ or ‘ per domain ’ Alt-PHP configuration and want to select modules using CloudLinux OS PHP Selector .
To modify it, create a file /etc/cl.selector/symlinks.rules (read-only for regular users) with the following content: php.d.location = selector
And run the command to apply changes:
/usr/bin/selectorctl --apply-symlinks-rules
- Delete /etc/cl.selector/symlinks.rules file.
- Alternatively remove php.d.location option from the file.
- Alternatively set default value for php.d.location option.
And run the command to apply changes:
/usr/bin/selectorctl --apply-symlinks-rules
FFmpeg
Note
The PHP-FFmpeg project has not been renewed for the last few years and is not compatible with the RHEL 8 based systems. Since code for alt-PHP-FFmpeg is outdated and FFmpeg has a lot of third-party dependencies, this module is not available for CloudLinux OS 8.
Due to possible patent issues CloudLinux OS does not provide FFmpeg libraries ( https://ffmpeg.org/legal.html ). We highly recommend researching if you can legally install FFmpeg extension on your server. This might differ based on where you and your servers are located. More information can be found on the link: https://ffmpeg.org/legal.html
For your convenience we provide FFMPEG PHP binding. For them to work, you need to install FFmpeg package from the “Nux Dextop” repository following the instructions.
Once FFmpeg is installed you can install PHP bindings, by running:
yum install alt-php*ffmpeg
Enable PHP-FFmpeg extension via PHP Selector :
selectorctl --enable-extensions=ffmpeg --user USERNAME --version X.Y
Native PHP configuration
PHP Selector requires access to the native PHP version for proper work. It is specified in the file /etc/cl.selector/native.conf
of the following content (example):
php=/usr/bin/php-cgi
php-cli=/usr/bin/php
php.ini=/etc/php.ini
lsphp=/usr/local/bin/lsphp
php-fpm=/usr/local/sbin/php-fpm
Then execute the following command to apply changes.
cagefsctl --setup-cl-selector
The file is created when installing CageFS on the servers with cPanel, Plesk, DA, Interworx and ISP Manager , if it is missing. On all other servers the file is not being created at all.
That is why, if the file is not created automatically, then it must be created manually and correct paths must be written to its directives.
Access permission 644 must be set:
chmod 0644 /etc/cl.selector/native.conf
How to configure alt-php72-zts to use with PHP Selector
Requirements
To use alt-php72-zts
with PHP Selector you need the following:
cagefs-6.1.8-1
or lateralt-php72-zts-7.2.21-4
or later
Using zts PHP
- Install
alt-php72-zts
with the following command:
yum install alt-php72-zts
- Make sure that
/etc/cl.selector/selector.conf
file contains correct paths to the PHPzts
binaries.
You should remove the old lines:
php 7.2 7.2.20 /opt/alt/php72/usr/bin/php-cgi
php-cli 7.2 7.2.20 /opt/alt/php72/usr/bin/php
And replace them with the lines with the new paths:
php 7.2 7.2.20 /opt/alt/php72/usr/bin/zts-php-cgi
php-cli 7.2 7.2.20 /opt/alt/php72/usr/bin/zts-php
- Make sure that
/opt/alt/php72/etc/php.d.all
path refers to the directory containingini
files forzts
PHP extensions:
cd /opt/alt/php72/etc
ln -fsn php.d.all.zts php.d.all
- Execute the following command:
cagefsctl --setup-cl-selector
Using non-zts PHP
- Make sure that
/etc/cl.selector/selector.conf
file contains correct paths to thenon-zts
PHP binaries.
You should remove the old lines:
php 7.2 7.2.20 /opt/alt/php72/usr/bin/zts-php-cgi
php-cli 7.2 7.2.20 /opt/alt/php72/usr/bin/zts-php
And replace them with the lines with the new paths:
php 7.2 7.2.20 /opt/alt/php72/usr/bin/php-cgi
php-cli 7.2 7.2.20 /opt/alt/php72/usr/bin/php
- Make sure that
/opt/alt/php72/etc/php.d.all
path refers to the directory containingini
files fornon-zts
PHP extensions:
cd /opt/alt/php72/etc
ln -fsn php.d.all.def php.d.all
- Execute the following command:
cagefsctl --setup-cl-selector
Using
Once PHP Selector is installed, you will see the Selector tab in the LVE Manager.
Customers can use PHP Selector client plugin to change their PHP Selctor related settings.
Custom PHP.ini options
PHP Selector allows customer to edit php.ini settings. Admin has a full control over which settings can be modified.
To allow settings to be modifiable, it has to be whitelisted in /etc/cl.selector/php.conf
.
Here are some of the examples of allowed directives:
Directive = safe_mode
Type = bool
Remark = <5.4.0
Comment = Enables PHP safe mode. This mode puts a number of restrictions on scripts (say, access to file system) mainly for security reasons.
Directive = safe_mode_include_dir
Type = value
Remark = <5.4.0
Comment = If PHP is in the safe mode and a script tries to access some files, files from this directory will bypass security (UID/GID) checks. The directory must also be in include_path. For example: /dir/inc
Directive | php.ini setting |
Type | bool, value (any text), list |
Range | list of values for list Type |
Comment | explanation of the setting to display in UI |
Default values, that are shown in PHP Selector web interface, are taken from '/opt/alt/phpXX/usr/bin/php -i' runtime values, if directive is not there, it will use the output of phpinfo() function. So, if you wish to change default value of any option for "alternative" php version, please modify /opt/alt/phpXX/etc/php.ini files (where XX = 55, 54, 53, etc according to php version).
Admin can modify the settings using selectorctl command.
Users can use web interface to modify php.ini settings:
End user files and directories
The following files and directories are created inside CageFS for each customer:
/etc/cl.selector - PHP binaries symbolic links.
/usr/selector/php - Native PHP binaries.
/etc/cl.php.d/alt-php* - Links to enabled modules.
/home/user/.cl.selector/alt_phpXX.cfg - Config file for custom PHP options.
like:
/etc/cl.php.d/alt-php54/fileinfo.ini - /opt/alt/php54/etc/php.d.all/fileinfo.ini
Compiling your own extensions
Sometimes you might want to compile your own PHP extension for your users to use. In most cases, it is better to contact our support by sending us a support ticket . We will try to provide such extension for you via regular updates within 5-7 days.
If you have decided that you want to build it on your own, you would need to build it for each and every supported version of PHP that you have installed. The module installation process is a bit different from standard - you would need to use the version of phpize and php-config binaries that come with particular Alt-PHP version.
The full process for PHP 5.X and 7.X looks as follows:
Download and unpack extension, cd into it's directory.
Execute our version of phpize if necessary:
/opt/alt/phpXX/usr/bin/phpize
- Execute configure with our binary:
./configure --with-php-config=/opt/alt/phpXX/usr/bin/php-config
- Make the .so file:
make
- Copy it to the modules directory (on 32-bit server, use usr/lib/php/modules ).
cp -rp modules/*.so /opt/alt/phpXX/usr/lib64/php/modules/
Add ini file for module to
/opt/alt/phpXX/etc/php.d.all
.Register new Alt-PHP version with:
cagefsctl --setup-cl-selector
Roll your own PHP
To add your own PHP version in PHP Selector :
- Create directory in (like: /opt/alt/php51), and mimic directory structure inside to be similar to the one of PHP versions bundled by CloudLinux OS .
- Put all the ini files for all the modules into /opt/alt/php51/etc/php.d.all
- Create a symbolic link /opt/alt/php51/etc/php.d -> /etc/cl.php.d/alt-php51
Place all such files into /opt/alt/php51/usr/lib/php/modules
Add an absolute path to PHP binaries into /etc/cl.selector/selector.conf using the following format:
php 5.1 5.1.2 /opt/alt/php51/usr/bin/php-cgi
php-cli 5.1 5.1.2 /opt/alt/php51/usr/bin/php
php-fpm 5.1 5.1.2 /opt/alt/php51/usr/sbin/php-fpm
^ ^ ^ ^----- absolute path
| | |---------------------- real version
| | -------------------------- version to display
|--------------------------------- binary to 'substitute'
Execute:
cagefsctl --setup-cl-selector
The new PHP version must be available now for selection in PHP Selector.
Detect user's PHP version
Note
LVE Manager 0.5-63 or higher
PHP Selector provides an easy way to figure out which versions are available and selected for end user from the command line. You can get this information by running:
selectorctl --interpreter=php --user-summary --user=USERNAME
The output:
5.2 e - -
5.3 e - s
5.4 e - -
5.5 e - -
native e d -
The first column defines the PHP version. Native means native PHP version, like the one installed by cPanel with EasyApache.
The second column will contain either e or -. If e is present, it means that given version is enabled, and can be selected by the end user.
The third column can have values d or -. If d is present, that version is considered a 'default' version. Only one PHP version will have d indicator.
The fourth column can have values s or -. If s is present, that is the selected version, currently being used by the end user. Only one PHP version will have s indicator.
In case a user is not inside CageFS, and as such doesn't use PHP Selector , you will see the following error message:
ERROR:User USERNAME not in CageFS
PHP Selector without CageFS
[LVE Manager 2.0-11.1 or higher]
PHP Selector can now be used with CageFS turned off (in case when there is only one user account on the server).
To install run:
yum groupinstall alt-php
yum install cagefs lvemanager
(no need to initialize or turn on CageFS)
selectorctl --setup-without-cagefs USER
( USER - the name of a user who is using selector. If not specified, the first available cPanel account username will be used).
When executing --setup-without-cagefs
, the following actions are performed:
Creating symlinks to the user modules and options for each Alt-PHP version:
/opt/alt/php55/link/conf/alt_php.ini -> /home/USER/.cl.selector/alt_php55.iniIn user home directory creating:
.cl.selector/
“Backup” settings files (selected version, modules, options):
.cl.selector/defaults.cfg
.cl.selector/alt_php44.cfg
Symlinks to the selected version:
.cl.selector/lsphp -> /opt/alt/php44/usr/bin/lsphp
.cl.selector/php.ini -> /opt/alt/php44/etc/php.ini
.cl.selector/php-cli -> /opt/alt/php44/usr/bin/php
.cl.selector/php -> /opt/alt/php44/usr/bin/php-cgi
Additional symlinks for environment variable $PATH (search path) in the file ~/.bashrc :
.cl.selector/selector.path/
.cl.selector/selector.path/php-cgi -> ../php
.cl.selector/selector.path/php -> ../php-cli
Generated ini files with selected modules and options for each version: .cl.selector/alt_php44.ini
.cl.selector/alt_php51.ini
.cl.selector/alt_php52.ini
.cl.selector/alt_php53.ini
.cl.selector/alt_php54.ini
.cl.selector/alt_php55.ini
.cl.selector/alt_php56.ini
.cl.selector/alt_php70.ini
.cl.selector/alt_php71.ini
Symlinks above are being created according to the settings in ~/.cl.selector/defaults.cfg and ~/.cl.selector/alt_php44.cfg files (44 - corresponding PHP version), which are storing PHP Selector settings for the user. These files are usually taken from user home directory backup or when migrating account from another server. Thus, when migrating account from server to server, PHP Selector settings are saved.
If no PHP Selector settings backup files are found when running selectorctl --setup-without-cagefs
, then default settings from /etc/cl.selector/defaults.cfg
global file are applied (as in selector normal mode). If the file is absent, then native PHP version will be selected for the user.
- The following line: PATH=$HOME/.cl.selector/selector.path:$HOME/.cl.selector:$PATH
is being added to the user file ~/.bashrc
Apache PHP handlers settings are not changed.
Also
selectorctl --setup-without-cagefs
command does the following:- Turns off link traversal protection (linksafe);
- Turns off cagefs service.
To get back to the selector normal mode (“with CageFS”) run:
selectorctl --revert-to-cagefs
(CageFS should be initialized by using cagefsctl --init
command before running the command above)
This command removes symlinks:/opt/alt/php55/link/conf/alt_php.ini
-> /home/USER/.cl.selector/alt_php55.ini
turns on link traversal protection (linksafe) and cagefs service.
Note
See also PHP Selector CLI
Configuring "global” php.ini options for all Alt-PHP versions
Note
CageFS 6.0-33 or higher, LVE Manager 2.0-11.2 or higher
There is /etc/cl.selector/global_php.ini
file, where you can specify values of PHP options that should be applied for all Alt-PHP versions that are installed on a server. These settings will also be automatically applied to the new Alt-PHP versions that will be installed later.
Example:
# cat /etc/cl.selector/global_php.ini
[Global PHP Settings]
date.timezone = Europe/Warsaw
error_log = error_log
memory_limit = 192M
Sections are ignored. Only name of an option and a value have meaning.
When an option is absent in /etc/cl.selector/global_php.ini file, than it is not changed (applied) to php.ini for Alt-PHP versions.
date.timezone and error_log options are handled differently than the others. When these options are not in /etc/cl.selector/global_php.ini file, than values for the options will be taken from "native" php.ini file. And when the option is in php.ini for some Alt-PHP version already (and its value is not empty), than value from /etc/cl.selector/global_php.ini will be NOT applied.
Note
CageFS version 6.1.5-1 or later
The behavior above is changed for cPanel servers with EasyApache 4. The /usr/local/lib/php.ini
file is removed for new installations of cPanel v80 and later.
- When
/usr/local/lib/php.ini
file exists,error_log
anddate.timezone
options will be taken from thatphp.ini
file. - When
/usr/local/lib/php.ini
file does not exist,error_log
anddate.timezone
options will be taken from thephp.ini
file for system default PHP version selected in MultiPHP Manager.
This functionality works when the system default PHP version is ea-php
only. When the system default PHP version is alt-php
, error_log
and date.timezone
directives will be NOT taken from that php.ini
file.
To confirm changes (not affecting "date.timezone" and "error_log" options) please run:
/usr/sbin/cagefsctl --setup-cl-selector
To confirm changes (including date.timezone
and error_log
options) please run:
/usr/bin/selectorctl --apply-global-php-ini
/usr/sbin/cagefsctl --apply-global-php-ini
If you don't want to change error_log
, but want to change date.timezone
, you can execute:
selectorctl --apply-global-php-ini date.timezone
Similarly, command selectorctl --apply-global-php-ini error_log
applies error_log and all other options specified in /etc/cl.selector/global_php.ini file, except date.timezone .
So, you can specify 0, 1 or 2 parameters from the list: error_log, date.timezone .
Using --apply-global-php-ini
without arguments applies all global PHP options including two above.
Example:
selectorctl --apply-global-php-ini error_log
selectorctl --apply-global-php-ini date.timezone
selectorctl --apply-global-php-ini date.timezone error_log
The latter command has the same effect as /usr/bin/selectorctl --apply-global-php-ini
.
Note
See also PHP Selector CLI
Integration with control panels
- PHP Selector integration with cPanel/WHM
- PHP Selector integration with Plesk
- PHP Selector integration with DirectAdmin
This is the list of commands that we use to integrate PHP Selector with control panels.
PHP summary:
Command:
/usr/bin/selectorctl --summary
4.4 e -
5.1 e -
5.2 e -
5.3 e -
5.4 e -
5.5 e -
5.6 e -
7.0 e -
7.1 e -
native e d
Command:
/usr/bin/selectorctl --summary --show-native-version
Result:
4.4 e -
5.1 e -
5.2 e -
5.3 e -
5.4 e -
5.5 e -
5.6 e -
7.0 e -
7.1 e -
native(5.6) e d
The first column: PHP version
The second column: enabled or not ( e - enabled)
The third column: if selected as default ( d - default)
Set default version:
/usr/bin/selectorctl --set-current=_VERSION_
Disable version:
/usr/bin/selectorctl --disable-alternative=_VERSION_
Enable version:
/usr/bin/selectorctl --enable-alternative=_VERSION_
List extensions for a version:
/usr/bin/selectorctl --list-extensions --version=5.6
Result:
- apc
- bcmath
- big_int
- bitset
- bloomy
~ bz2
- bz2_filter
~ calendar
- coin_acceptor
- crack
~ ctype
+ curl
+: enabled
~: included in php binary (cannot be disabled) or enabled in php global config file /opt/alt/phpXX/etc/php.ini
-: disabled
Select default extensions (enable comma-separated list of extensions globally for a version):
/usr/bin/selectorctl --version=5.6 --enable-extensions=pdo,json,mysql
Deselect default extensions (disable comma-separated list of extensions globally for a version):
/usr/bin/selectorctl --version=5.6 --disable-extensions=pdo,json,mysql
Replace extensions with comma-separated list of extensions for a version globally:
/usr/bin/selectorctl --version=5.6 --replace-extensions=pdo,json,mysql
Select PHP version for a user:
/usr/bin/selectorctl --set-user-current=_VERSION_ --user=_USER_
List enabled extensions for a user:
/usr/bin/selectorctl --list-user-extensions --user=_USER_ --version=_VERSION_
Enable comma-separated list of extensions for a user:
/usr/bin/selectorctl --enable-user-extensions=pdo,json,mysql --user=_USER_ --version=_VERSION_
Reset user’s extensions to defaults:
/usr/bin/selectorctl --reset-user-extensions --user=_USER_ --version=_VERSION_
Replace user extensions with comma-separated list of extensions:
/usr/bin/selectorctl --replace-user-extensions=EXT_LIST --user=_USER_ --version=_VERSION_
EXT_LIST a is comma separated list of PHP extensions (for example: pdo,json,mysql )
List available options for php.ini editing:
/usr/bin/selectorctl --print-options --user=_USER_ --version=_VERSION_ [--json]
List available options for php.ini editing (print safe strings):
/usr/bin/selectorctl --print-options-safe --user=_USER_ --version=_VERSION_ [--json]
Set php.ini options for end user:
/usr/bin/selectorctl --user=_USER_ --version=_VERSION_ --replace-options=_OPTIONS_ --base64 [--json]
Here is an example of how you can generate OPTIONS in base64 format:
OPTIONS=`echo disable_functions:exec,syslog|base64 -w 0`,`echo display_errors:off|base64 -w 0`,`echo post_max_size:128M|base64 -w 0`
echo $OPTIONS
See also PHP Selector CLI tools.
Bundled PHP extensions
You can find this information in the section List of extensions supported by the alt&ea team for each version of PHP
Python Selector
General information
Python Selector is a CloudLinux OS component that allows each user to easily deploy and manage Python applications. Users can manage applications at the control panel interface level or from the command line (CLI).
Requirements
- cPanel or DirectAdmin control panel. Plesk isn't supported.
- Apache or LiteSpeed webserver. Apache + Nginx (as a reverse proxy) combination is also supported.
- Python Selector uses
mod_passenger
to host Python. For more details aboutmod_passenger
, please read documentation. The needed version will be installed along with Python Selector.
Note!
OpenLiteSpeed is not compatible with Python Selector due to lack of .htaccess
support.
Supported versions
CloudLinux 6 | CloudLinux 7 | CloudLinux 8 | CloudLinux 9 |
---|---|---|---|
alt-python 2.7 | alt-python 2.7 | alt-python 2.7 | alt-python 2.7 |
alt-python 3.3 | alt-python 3.3 | alt-python 3.3 | alt-python 3.3 |
alt-python 3.4 | alt-python 3.4 | alt-python 3.4 | alt-python 3.4 |
alt-python 3.5 | alt-python 3.5 | alt-python 3.5 | alt-python 3.5 |
alt-python 3.6 | alt-python 3.6 | alt-python 3.6 | alt-python 3.6 |
alt-python 3.7 | alt-python 3.7 | alt-python 3.7 | alt-python 3.7 |
alt-python 3.8 | alt-python 3.8 | alt-python 3.8 | alt-python 3.8 |
alt-python 3.9 | alt-python 3.9 | alt-python 3.9 | alt-python 3.9 |
alt-python 3.11 | alt-python 3.10 | alt-python 3.10 | alt-python 3.10 |
alt-python 3.11 | alt-python 3.11 | alt-python 3.11 | |
alt-python 3.12 | alt-python 3.12 | alt-python 3.12 |
Installation
You can install Python Selector using the CloudLinux OS Installation Wizard.
After installation, please make sure that you have set appropriate checkboxes in CloudLinux Manager Options tab to show Python App in the web-interface.
Manual installation
Here you can find the installation steps for supported control panels:
cPanel
To use Python Selector, it is required to install the following:
- alternative Python packages by running the following command:
yum groupinstall alt-python
- CloudLinux Manager, LVE Utils and Phusion Passenger to create isolated Python environments by running the following command:
yum install lvemanager lve-utils alt-python-virtualenv
Phusion Passenger could be installed by using either ea-ruby24-mod_passenger
or ea-ruby27-mod_passenger
. ea-ruby27-mod_passenger
is not compatible with systems running CloudLinux OS 6. CloudLinux OS 7 supports both ea-ruby24-mod_passenger
and ea-ruby27-mod_passenger
. If your system runs CloudLinux OS 8, you can only use ea-ruby27-mod_passenger
.
Adding Python module requires executing permissions to gcc/make
binaries. Please enable compilers in Compiler Access section of WHM, then run:
cagefsctl --force-update
- We recommend use CageFS for better security. See CageFS documentation for details.
DirectAdmin
To use Python Selector, it is required to install the following:
- alternative Python packages by running the following command:
yum groupinstall alt-python
- CloudLinux Manager, LVE Utils and Phusion Passenger to create isolated Python environments by running the following command:
yum install lve-utils lvemanager alt-python-virtualenv alt-mod-passenger
We recommend use CageFS for better security. See CageFS documentation for details.
See also Python Selector UI.
See also Python Selector CLI.
Ruby Selector
General information and requirements
We have the ability to deploy Ruby applications via an application server. Ruby Selector uses mod_passenger
to host Ruby applications.
Ruby Selector works only on cPanel/WHM servers.
Supported versions
Installation and update
Note
The instructions below are suitable only for EasyApache 3 and EasyApache 4. You should follow this instruction if you use LiteSpeed.
To use Ruby Selector install alternative Ruby packages:
yum groupinstall alt-ruby
Note
After installation, please make sure that you have unmarked appropriate checkboxes in VE Manager Options tab to show Ruby App in web-interface. Find the instructions on the link.
Note
Adding Ruby modules requires executing permissions to gcc/make
binaries. Please enable compilers in Compiler Access section of WHM, then run: cagefsctl --force-update
Configuration and using
End user access
You can find an example of Ruby application setup here
Note
See also Ruby Selector CLI section.
Hide Ruby Selector icon
It is possible to hide or show Ruby Selector icon by marking or unmarking proper checkboxes in LVE Manager Options tab.
The same result can be accomplished in CLI by running:
cloudlinux-config set --json --data '{"options":{"uiSettings":{"hideRubyApp":false}}}'
Note
If you are using cPanel/WHM, you can also configure hide/show CloudLinux OS Ruby Selectors in WHM | Feature Manager. For that, you’d need to first uncheck Hide Ruby App in web-interface
in the LVE Manager. This will make the menu appear for all accounts. After that, you are free to disable this app in WHM | Feature Manager for the required feature lists.
Deploying Redmine using Ruby Selector
Note
You can find Redmine version 2.6.0 and newer deployment guide here
EasyApache 4
Note
ea-apache24-mod-alt-passenger
is deprecated in favor of ea-ruby24-mod_passenger
and ea-ruby27-mod_passenger
Starting with cPanel/WHM version 66 provides ea-ruby24-mod_passenger
(more information on the link), this allows creating Ruby applications with cPanel application manager.
CloudLinux OS features its own Python and Ruby Selectors, which allow creating applications with one of mod_passenger
Apache modules:
ea-ruby24-mod_passenger
ea-ruby27-mod_passenger
ea-ruby27-mod_passenger
is not compatible with systems running CloudLinux OS 6. CloudLinux OS 7 supports both ea-ruby24-mod_passenger
and ea-ruby27-mod_passenger
. If your system runs CloudLinux OS 8, you can only use ea-ruby27-mod_passenger
.
The ea-ruby2X-mod_passenger
allows you to run applications via cPanel application manager and Ruby Selector.
To install, run:
yum install lvemanager alt-python-virtualenv
yum install ea-ruby24-mod_passenger
or:
yum install lvemanager alt-python-virtualenv
yum install ea-ruby27-mod_passenger
See also Ruby Selector CLI tools.
Node.js Selector
General information and requirements
Node.js Selector is a CloudLinux OS component that allows each user to easily create Node.js applications, choose Node.js version and other parameters for applications based on their needs.
Supported versions
Requirements
- Node.js Selector requires LVE Manager 4.0 or later.
- It supports cPanel and DirectAdmin servers as well as non-panel installations (Plesk is not supported as it already has Node.js support.) For more details, please go to Plesk & Node.js documentation here and here .
- Node.js Selector uses
mod_passenger
to host Node.js. For more details about mod_passenger and Node.js, please read documentation here and here . - Node.js Selector supports both EasyApache 3 and EasyApache 4.
Note!
OpenLiteSpeed is not compatible with Node.js Selector due to lack of .htaccess
support.
Limitations
Since Node.js Selector uses mod_passenger
to host Node.js, then Node.js Selector has the same limitations as Phusion Passenger. Phusion Passenger cannot load ECMAScript modules and can only load Common js modules. If you get an ERR_REQUIRE_ESM error when starting an application app.js.
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: app.js
In this case you can use the following cjs wrapper app_wrapper.cjs to load esm script app.js:
cat app_wrapper.cjs
(() => import('app.js'))();
Installation and update
Note
Node.js Selector support is added to LiteSpeed Web Server starting from the 5.3RC1 release. See details here.
cPanel
To use Node.js Selector, install Node.js packages by running the following command:
yum groupinstall alt-nodejs
yum install lvemanager lve-utils
Phusion Passenger could be installed by using either ea-ruby24-mod_passenger
or ea-ruby27-mod_passenger
. ea-ruby27-mod_passenger
is not compatible with systems running CloudLinux OS 6. CloudLinux OS 7 supports both ea-ruby24-mod_passenger
and ea-ruby27-mod_passenger
. If your system runs CloudLinux OS 8, you can only use ea-ruby27-mod_passenger
.
Note
ea-apache24-mod-alt-passenger
is deprecated in favor of ea-ruby24-mod_passenger
and ea-ruby27-mod_passenger
For EasyApache 3:
yum install lvemanager lve-utils alt-mod-passenger
yum install cagefs
Note
If during Node.js Selector usage on cPanel servers you get "ENOMEM npm ERR! errno-12" error, try to increase Memory limit in cPanel WHM → Server Configuration → Tweak Settings → System → Max cPanel process memory, then restart cPanel service with the following command to apply changes.
CloudLinux OS 7:
systemctl restart cpanel.service
CloudLinux OS 6:
DirectAdmin
To use Node.js Selector, please install Node.js packages by running the following command:
yum groupinstall alt-nodejs6 alt-nodejs8 alt-nodejs9
yum install lvemanager lve-utils alt-mod-passenger
yum install cagefs
Node.js deployment
The first approach - remote usage of Node.js Interpreters of different versions
The second approach - remote usage of the cloudlinux-selector utility.
Remote usage of Node.js interpreters
- Create a Node.js project in IntelliJ IDEA/WebStorm . You can download this archive and use it as a basis.
- Install alt-nodejs packages on the server in use. See installation instructions.
- Create an application on the server. You can do it by three ways:
- Via UI of the Node.js plugin.
- Using the following command to create an application:
cloudlinux-selector create --interprete=nodejs --json --app-root=<USER_NAME> --app-uri=<APP_NAME> --app-mode=develompent --version=<VERSION> --domain=<DOMAIN>
Note
In the IntelliJ IDEA you can create and run any remote script (Preferences — Remote SSH External Tools — Add).
- Choose a location of the application on the server and synchronize the files with the IntelliJ IDEA project.
- Set up Run/Debug Configurations in the project created.
- Specify a path to the remote Node.js interpreter. To be able to specify the remote interpreter, you should install the Node.js Remote Interpreter plugin first. Please find more information here , using server access credentials for a user (Main menu → Run → Edit configurations...) .
- Specify initial JavaScript file that will be run with the node command (it is the app.js file from the archive).
- Specify Path Mappings between a local and a remote project (Preferences → Deployments → Add) . If you have created your application with the cloudlinux-selector utility or via plugin UI the Path Mappings should be as follows:
/home/<USER_NAME>/<APP_NAME>
- Synchronize the project directories on the local and the remote machine as per Path Mappings specified.
- Deploy the modules on the remote and the local machine with the npm install command (if there are dependent modules). In the UI you can click the Run NPM Install button.
- Run Node.js application with the configuration set at the 4th step (Main menu → Run → Run… → Select configuration) .
- If you are using the application from the archive attached, you can see the running application on port 3003 — http://DOMAIN:3003 .
Note
The port should be available to a server user.
The following information should be displayed on this page:
- A version of the running Node.js interpreter;
- Current environment variables;
- The current time.
So that, you can be sure that deployed modules are used properly.
If you’d like to use a different version of Node.js to run an application, change a path to the interpreter in the configuration settings of the running.
To apply all changes to the project, synchronize all changes with the server and restart the running application.
- To debug a script, set breakpoints in the code and run the configuration via Main Menu (Main menu → Run → Debug… → Select configuration) .
Useful links:
- IntelliJ IDEA : https://www.jetbrains.com/help/idea/configure-node-js-remote-interpreter.html
- Plugin Node.js Remote Interpreter : https://plugins.jetbrains.com/plugin/8116-node-js-remote-interpreter
- WebStorm : https://www.jetbrains.com/help/webstorm/configure-node-js-remote-interpreter.html
Note
It is not required to install Passenger while working in IDE if you are using this approach.
Remote usage of the cloudlinux-selector utility
- Create an application via UI or with the command as described in the Remote Usage of Node.js Interpreters approach, step 3 (a,b).
- Set up project mapping on the local machine with the created remote application /home/<USER_NAME>/<APP_NAME> (Preferences → Deployments → Add).
- Set up the remote commands of cloudlinux-selector (Preferences → Remote SSH External Tools → Add) for the following actions:
Restart application;
Install packages;
Run script;
Change Node.js version for the application. You can see the running app at http://DOMAIN/APPLICATION_URL To apply all changes, restart the application.
See also Node.js Selector CLI tools.
See also Node.js Selector UI.
Troubleshooting
Debugging errors
Since alt-mod-passenger-5.3.7-2, directives such as PassengerFriendlyErrorPages and PassengerAppEnv are available for use from htaccess file. This allows end users to see errors from their application during the development process. For example, if you add one of the following lines to the htaccess file on the application page, you will see the information (if there was an error) similar to one on the picture.
PassengerAppEnv development
PassengerFriendlyErrorPages on
This is a much more convenient approach to developing an application and debugging errors. On the other hand, if these directives are turned off you will see:
In this case, there is no useful information for debugging errors and this is suitable for production mode. More information about PassengerFriendlyErrorPages and PassengerAppEnv.
Known Restrictions and Issues
In some cases running commands e.g.
npm build
can produce an Out Of Memory error.When the error is encountered in Nodejs Selector UI or in the web browser terminal, check the physical and virtual memory LVE limits. Also check the process limits through
ulimit -v -m
command in Terminal UI or "Max data size", "Max address space" or "Max resident set" values inside the/proc/<process_id>/limits
file. Increase the limits if necessary.On cPanel, increase the default process memory limit:
whmapi1 set_tweaksetting key=maxmem value=8192 /usr/local/cpanel/scripts/restartsrv_cpsrvd
Due to bug CPANEL-43590 a server reload might be required for the new maxmem value to become applied.
In some cases, due to bugs in underlying Node.js frameworks (e.g. Out of memory: wasm memory) it could be necessary to increase
maxmem
up to 50 Gb (value=51200
) or even tounlimited
.Sometimes an Out Of Memory error appears in the web browser terminal in cPanel. Because of CPANEL-39397 bug terminal inherences limits of
cpsrvd
process. As a workaround, you could increasemaxmem
value as described above.Alternetive workaround: override soft and hard virtual memory limit only for the user encountering the problem. Override hard limit by adding the following line to the
/etc/security/limits.conf
file:username hard as unlimited
Override soft limit by adding into
$USER_HOME/.bashrc
:ulimit -S -v unlimited
Apache mod_lsapi PRO
General information and requirements
mod_lsapi PRO is an Apache HTTP Server module based on LiteSpeed Technologies API . It serves to execute PHP scripts on a web-server by analogy with other modules like mod_suphp, php-fpm, mod_php. However, mod_lsapi PRO usage offers excellent PHP performance, low memory footprint coupled with great security and support for opcode caching.
How does it work?
- Apache passes handling for PHP request to mod_lsapi PRO;
- mod_lsapi PRO use liblsapi to transfer request to lsphp parent process;
- lsphp is forking child process which executes the request and returns data to mod_lsapi PRO;
mod_lsapi PRO integrates with Apache, allows to handle concurrent requests and manages the lsphp processes
- If there are no requests for lsapi_backend_pgrp_max_idle seconds, lsphp parent process will be terminated;
- If there are no lsphp child processes available when a new request comes, the new lsphp child process will be created;
- lsphp childs process concurrent requests simultaneously;
- The maximum number of simultaneously running lsphp child processes can be set by the lsapi_backend_children directive.
What is lsphp?
lsphp - PHP + LSAPI. What is PHP LSAPI? LiteSpeed Server Application Programming Interface (LSAPI) is designed specifically for seamless, optimized communication between LiteSpeed Web Server and third-party web applications. Now with mod_lsapi PRO this protocol is available for Apache 2.2/2.4.
Using mod_lsapi PRO, we have seen the higher performance than Apache with mod_php, easier installation than php-fpm and easier integration with any control panel. mod_lsapi PRO means faster and more stable dynamic web pages.
Requirements
Currently, the mod_lsapi is not compatible with:
- Apache mod_ruid2 - should be disabled;
- Apache mod_itk - should be disabled;
- PHP-FPM - should be disabled because PHP-FPM is also a PHP Handler just as mod_lsapi.
Optional requirements
- Configured LVE containers for end-users ( recommended - higher security level );
- Installed and configured mod_hostinglimitsfor Apache ( recommended - higher security level );
- Installed mod_suexec for Apache and configured SuExecUserGroup directive for each virtual host ( recommended - higher security level );
- Enabled CageFS for end-users ( recommended - higher security level );
- PHP Selector with alt-php - an easy way to select different PHP versions for each end-user provided by CloudLinux OS;
- ea-php - alternative to alt-php provided by cPanel (for cPanel only).
Installation
mod_lsapi PRO can be installed through YUM package manager, however, the installation process varies depending on the control panel.
Select the control panel you are using:
Note
See also mod_lsapi PRO.
Installing on cPanel servers with EasyApache 4
Install mod_lsapi PRO and related packages through YUM package manager as follows:
yum install liblsapi liblsapi-devel
yum install ea-apache24-mod_lsapi
/usr/bin/switch_mod_lsapi --setup
service httpd restart
For more details about switch_mod_lsapi, please visit switch_mod_lsapi tool.
Installing on Plesk servers
Install mod_lsapi PRO and related packages through YUM package manager as follows:
yum install liblsapi liblsapi-devel
yum install mod_lsapi
/usr/bin/switch_mod_lsapi --setup
Now, when the module is installed, restart Apache to ensure that mod_lsapi PRO is enabled:
service httpd restart
Now LSPHPXY alt-php PHP handlers are available for managing through Plesk PHP Settings.
For more details about switch_mod_lsapi, please visit switch_mod_lsapi tool.
Installing on DirectAdmin servers
Installation process is done with custombuild script:
yum install liblsapi liblsapi-devel
cd /usr/local/directadmin/custombuild
./build update
./build set php1_mode lsphp
./build php n
./build apache
service httpd restart
Installing on servers with no control panel
Note
If there is a php.conf file in Apache's conf.d, which is usually brought by the php or php-fpm packages, then it should be deleted or renamed.
For example, php.conf
can be renamed into php.conf.NO
.
Install mod_lsapi PRO and related packages through YUM package manager as follows:
yum install liblsapi liblsapi-devel
yum install mod_lsapi
/usr/bin/switch_mod_lsapi --setup
service httpd restart
If you are using an alternative Apache - httpd24 , then install mod_lsapi as follows:
yum install liblsapi liblsapi-devel
yum install httpd24-mod_lsapi
/opt/rh/httpd24/root/usr/bin/switch_mod_lsapi --setup
service httpd24-httpd restart
For more details about switch_mod_lsapi, please visit switch_mod_lsapi tool.
Uninstalling
Uninstall mod_lsapi PRO is performed depending on your control panel.
Select the control panel you are using:
Uninstall procedure for cPanel servers with EasyApache 4
Note
If there is a php.conf file in Apache's conf.d, which is usually brought by the php or php-fpm packages, then it should be deleted or renamed.
For example, php.conf
can be renamed into php.conf.NO
.
To remove lsapi handler from cPanel MultiPHP Manager and uninstall mod_lsapi PRO, run a command:
/usr/bin/switch_mod_lsapi --uninstall
yum erase liblsapi liblsapi-devel ea-apache24-mod_lsapi
service httpd restart
Uninstall procedure for Plesk servers
To unregister LSPHP handlers and uninstall mod_lsapi PRO, run the command:
/usr/bin/switch_mod_lsapi --uninstall
yum erase liblsapi liblsapi-devel mod_lsapi
service httpd restart
Uninstall procedure for DirectAdmin servers
Uninstall is done with custombuild script:
cd /usr/local/directadmin/custombuild
./build update
./build set php1_release [any other php mode]
./build php n
./build apache
- mod_php
- fastcgi
- php-fpm
- suphp
Restart Apache afterwards:
service httpd restart
Uninstall procedure for servers with no control panel
To uninstall mod_lsapi PRO, run the command:
/usr/bin/switch_mod_lsapi --uninstall
yum erase liblsapi liblsapi-devel mod_lsapi
rm [path to mod_lsapi.conf]
service httpd restart
If you are using an alternative Apache: - httpd24, then uninstall mod_lsapi PRO as follows:
/usr/bin/switch_mod_lsapi --uninstall
yum erase liblsapi liblsapi-devel httpd24-mod_lsapi
rm [path to mod_lsapi.conf]
service httpd24 restart
Configuration
In order to get mod_lsapi PRO work properly, you'll need to configure Apache. To do this, we use a separate lsapi.conf file.
First of all, for the mod_lsapi PRO work, you need to ensure that the module is loaded. In your lsapi.conf you need to make sure the LoadModule directive has not been commented out. A correctly configured directive may look like this:
LoadModule lsapi_module modules/mod_lsapi.so
In order to enable the module to process requests, you need to add the lsapi_engine directive to your lsapi.conf file as follows:
lsapi_engine On
The mod_lsapi PRO handler can be enabled using the AddType directive. The AddType directive tells Apache that a given filename extension should be handled by mod_lsapi PRO. Apache will assume that and will attempt to execute it when that particular resource is requested by a client.
AddType application/x-httpd-lsphp .php
If no handler is explicitly set for a request, the specified content type will be used as the handler name, therefore, please disable php.conf or any other PHP handler for using mod_lsapi PRO. In this example application/x-httpd-lsphp is a default handler by which mod_lsapi PRO process requests with lsphp binary from /usr/local/bin/ directory.
The final lsapi.conf configuration might look like this:
LoadModule lsapi_module modules/mod_lsapi.so
<IfModule lsapi_module>
lsapi_engine On
AddType application/x-httpd-lsphp .php
lsapi_backend_connect_timeout 100000
lsapi_backend_connect_tries 10
lsapi_backend_children 20
lsapi_backend_pgrp_max_idle 30
lsapi_backend_max_process_time 300
lsapi_debug Off
</IfModule>
In order to mod_lsapi PRO work lsapi.conf should be loaded to Apache through Include directive.
For more detailed description of the module directives please visit Configuration reference.
For installation guide mod_lsapi PRO please visit Installation.
Configuration references
- lsapi_engine
- lsapi_socket_path
- lsapi_poll_timeout
- lsapi_per_user
- lsapi_output_buffering
- lsapi_disable_reject_mode
- lsapi_terminate_backends_on_exit
- lsapi_avoid_zombies
- lsapi_use_req_hostname
- lsapi_debug
- lsapi_set_env
- lsapi_set_env_path
- lsapi_backend_children
- lsapi_backend_connect_tries
- lsapi_backend_connect_timeout
- lsapi_backend_max_process_time
- lsapi_backend_pgrp_max_idle
- lsapi_backend_use_own_log
- lsapi_backend_common_own_log
- lsapi_backend_coredump
- lsapi_backend_accept_notify
- lsapi_backend_pgrp_max_reqs
- lsapi_backend_pgrp_max_crashes
- lsapi_backend_loglevel_info
- lsapi_backend_oom_score_adj
- lsapi-server-tweak Beta
- lsapi_criu
- lsapi_criu_socket_path
- lsapi_criu_imgs_dir_path
- lsapi_backend_initial_start
- lsapi_criu_use_shm
- lsapi_backend_semtimedwait
- lsapi_reset_criu_on_apache_restart
- lsapi_criu_debug
- lsapi_process_phpini
- lsapi_phpini
- lsapi_phprc
- lsapi_tmpdir
- lsapi_enable_user_ini
- lsapi_user_ini_homedir
- lsapi_keep_http200
- lsapi_mod_php_behaviour
- php_value, php_admin_value, php_flag, php_admin_flag
- lsapi_use_suexec
- lsapi_user_group
- lsapi_uid_gid
- lsapi_use_default_uid
- lsapi_target_perm
- lsapi_paranoid
- lsapi_check_document_root
- lsapi_disable_forced_pwd_var
- lsapi_max_resend_buffer
mod_lsapi customization
lsapi_engine
Syntax : lsapi_engine on/off
Default : lsapi_engine off
Context : httpd.conf, htaccess
Description :
Switching mod_lsapi handler on or off.
lsapi_socket_path
Syntax : lsapi_socket_path [path] Default : lsapi_socket_path /var/mod_lsapi
Context : httpd.conf
Description:
Path to backend lsphp sockets. By default /var/mod_lsapi
lsapi_poll_timeout
Syntax : lsapi_poll_timeout [number]
Default : lsapi_poll_timeout 300
Context : httpd.conf, htaccess
Description :
Time to wait for response from the lsphp daemon, in seconds. 0 stands for infinity. For preventing long running processes which can use EP (limit number of entry processes). Default value is 300. Should be more or equal to 0. In the case of wrong format, the default value will be used.
lsapi_per_user
Syntax : lsapi_per_user On/Off
Default : lsapi_per_user Off
Context : httpd.conf
Description :
Invoke master lsPHP process not per VirtualHost but per account. When On, invoke backend not per VirtualHost but per account. Default value is Off. It is possible, for example, to set it to On in global config file and to Off in config files of some particular Virtual Hosts. Then these Virtual Hosts will have a dedicated backend process, while others will have backend processes shared on account basis.
lsapi_output_buffering
Syntax : lsapi_output_buffering On/Off
Default : lsapi_output_buffering On
Context : httpd.conf, virtualhost, htaccess
Description :
Enable or disable output buffering on Apache level. Default value is On.
lsapi_disable_reject_mode
Syntax : lsapi_disable_reject_mode On/Off
Default : lsapi_disable_reject_mode Off
Context : httpd.conf, virtualhost
Description :
If a new HTTP request is coming to LSPHP daemon when all LSPHP workers are still busy, it can process this situation in two different ways. In REJECT mode LSPHP daemon will reject such request immediately. Otherwise, in legacy mode, LSPHP daemon will put this request into infinite queue, until one or more LSPHP daemon becomes free. When HTTP request is rejected in REJECT mode, mod_lsapi will write into Apache error_log the following message: Connect to backend rejected, and the client will receive 507 HTTP response. By default LSPHP daemon in CloudLinux OS uses REJECT mode. It can be switched off with this option.
lsapi_terminate_backends_on_exit
Syntax : lsapi_terminate_backends_on_exit On/Off
Default : lsapi_terminate_backends_on_exit On
Context : httpd.conf
Description :
httpd.conf, On - stop lsphp services on apache restart, Off - leave live started lsphp services on apache restart (for php+opcache). The lsphp will not restart, even if Apache gets restarted.
lsapi_avoid_zombies
Syntax : lsapi_avoid_zombies On/Off
Default : lsapi_avoid_zombies Off
Context : httpd.conf, virtualhost
Description :
Enable or disable a mechanism to avoid creation of zombie processes by lsphp. Default value is Off.
lsapi_use_req_hostname
Syntax : lsapi_use_req_hostname On/Off
Default : lsapi_use_req_hostname Off
Context : httpd.conf, virtualhosts
Description :
By default, we are using hostname from the server_rec structure (off), it means that mod_lsapi takes hostname from the VirtualHost section of the configuration file. Using hostname from the request_rec structure (On) means that mod_lsapi takes hostname from the HOST section of the request. It could be useful for those who use dynamically generated configs for virtual hosts for example with mod_lua.
lsapi_sentry
Syntax : lsapi_sentry On/Off
Default : lsapi_sentry On
Context : httpd.conf
Description :
When this option is enabled, errors that occur in the operation of the mod_lsapi will be sent to the remote sentry server. You can see the error messages that were sent to the sentry server in the directory /var/log/mod_lsapi. If you do not want to send error notifications from your server, you can disable this directive in lsapi.conf.
lsapi_debug
Syntax : lsapi_debug On/Off
Default : lsapi_debug Off
Context : httpd.conf, virtualhost
Description :
Extended debug logging.
Tuning LSPHP backend
lsapi_set_env
Syntax : lsapi_set_env VAR_NAME [VAR_VALUE]
Default : -
Context : httpd.conf
Description :
Pass env variable to lsphp. By default lsphp environment have only TEMP, TMP and PATH variables set.
Example: lsapi_set_env TMP "/var/lsphp-tmp"
Note: PATH env var default "/usr/local/bin:/usr/bin:/bin" cannot be changed because of security reasons.
To change it, use explicitly lsapi_set_env_path option.
Beta
When the lsapi_server_tweak
option is switched On
, this option can be used in the virtualhost context.
lsapi_set_env_path
Syntax : lsapi_set_env_path [path(s)]
Default : lsapi_set_env_path /usr/local/bin:/usr/bin:/bin
Context : httpd.conf
Description :
Change PATH variable in the environment of lsPHP processes. Default path /usr/local/bin:/usr/bin:/bin will be used if not set.
Beta
When the lsapi_server_tweak
option is switched On
, this option can be used in the virtualhost context.
lsapi_backend_children
Syntax : lsapi_backend_children [number]
Default : lsapi_backend_children [EP]
Context : httpd.conf
Description :
Sets maximum number of simultaneously running child backend processes. Optional, a default directive value is equal to 120. LSAPI_CHILDREN environment variable is set according to the following rules:
- If NPROC and EP are unlimited, the directive value is used.
- If NPROC is set to any limited value and the directive value is set to a number less than NPROC-1, the directive value is used.
- If the value is bigger than NPROC-1 and EP is set to unlimited, NPROC-1 is used.
- If the value is bigger than NPROC-1 and EP is set to any limited value, EP+1 is used.
For example, with the default lve settings NPROC=100 and EP=20, the effective LSAPI_CHILDREN will be EP+1, that is LSAPI_CHILDREN=21.
lsapi_backend_connect_tries
Syntax : lsapi_backend_connect_tries [number]
Default : lsapi_backend_connect_tries 20
Context : httpd.conf
Description :
Number of retries to connects to lsPHP daemon.
lsapi_backend_connect_timeout
Syntax : lsapi_backend_connect_timeout [number]
Default : lsapi_backend_connect_timeout 500000
Context : httpd.conf
Description :
Number of usec to wait while lsPHP starts (if not started on request).
lsapi_backend_max_process_time
Syntax : lsapi_backend_max_process_time [number]
Default : lsapi_backend_max_process_time 300
Context : httpd.conf, virtualhost
Description :
Sets env variable LSAPI_MAX_PROCESS_TIME
Optional. Default value is 300.
Timeout to kill runaway processes.
lsapi_backend_pgrp_max_idle
Syntax : lsapi_backend_pgrp_max_idle [number]
Default : lsapi_backend_pgrp_max_idle 30
Context : httpd.conf
Description :
Sets env variable LSAPI_PGRP_MAX_IDLE, in seconds.
Controls how long a control process will wait for a new request before it exits. # 0 stands for infinite.
Optional, default value is 30.
Should be more or equal to 0.
lsapi_backend_use_own_log
Syntax : lsapi_backend_use_own_log On/Off
Default : lsapi_backend_use_own_log Off
Context : httpd.conf, virtualhost
Description :
Redirecting log output of backend processes from Apache error_log to dedicated log file or files, depending on value of lsapi_backend_common_own_log option. If Off, use Apache error log file for backend output, or separate file otherwise.
lsapi_backend_common_own_log
Syntax : lsapi_backend_common_own_log On/Off
Default : lsapi_backend_common_own_log Off
Context : httpd.conf, virtualhost
Description :
It will be used only when lsapi_backend_use_own_log set to On. On - backend processes of the all virtual hosts will share the common log file. Off - every virtual host will have its own backend log file.
lsapi_backend_coredump
Syntax : lsapi_backend_coredump On/Off
Default : lsapi_backend_coredump Off
Context : httpd.conf, htaccess
Description :
env variable LSAPI_ALLOW_CORE_DUMP (On or Off). Pass LSAPI_ALLOW_CORE_DUMP to lsphp or not. If it will be passed - core dump on lsphp crash will be created.
Off by default.
By default LSAPI application will not leave a core dump file when crashed. If you want to have LSAPI PHP dump a core file, you should set this environment variable. If set, regardless the value has been set to, core files will be created under the directory that the PHP script in.
lsapi_backend_accept_notify
Syntax : lsapi_backend_accept_notify On/Off
Default : lsapi_backend_accept_notify On
Context : httpd.conf, virtualhost
Description :
Switch LSAPI_ACCEPT_NOTIFY mode for lsphp. This option can be used both in Global and VirtualHost scopes.This mode is incompatible with PHP 4.4.
lsapi_backend_pgrp_max_reqs
Syntax : lsapi_backend_prgrp_max_reqs [number]
Default : lsapi_backend_max_reqs 0
Context : httpd.conf, virtualhost
Description :
Controls how many requests a control process will process before it exits. Should be more or equal to 0. In the case of wrong format, a default value will be used. Optional, the default value is 0, which means an unlimited number of requests.
lsapi_backend_pgrp_max_crashes
Syntax : lsapi_backend_prgrp_max_crashes [number]
Default : lsapi_backend_max_crashes 0
Context : httpd.conf, virtualhost
Description :
Controls how many crashes of its worker processes a control process will detect before it exits. Should be more or equal to 0. In the case of wrong format, a default value will be used. Optional, the default value is 0, which means an unlimited number of crashes.
lsapi_backend_loglevel_info
Syntax: lsapi_backend_loglevel_info [On/Off]
Default: lsapi_backend_loglevel_info Off
Context: httpd.conf, virtualhost
Description: Controls which log level will be used to write PHP warnings and notices into Apache’s error_log. Optional, the default value is Off
. In that case LOG_WARNING
log level will be used. Otherwise, with On
value, LOG_INFO
log level will be used.
lsapi_backend_oom_score_adj
Syntax: lsapi_backend_oom_score_adj [number]
Default: lsapi_backend_oom_score_adj 0
Context: httpd.conf, virtualhost
Description: This option can be used to apply oom_score_adj values for PHP processes created by mod_lsapi. Value is an integer in the -1000 to 1000 range. The lower the value, the lower the chance that the process will be killed. When your server becomes low on free memory and an OOM killer is invoked then desirable that lsphp processes are sacrificed to free up memory. To do this, you need to set oom_score_adj to a large value. For more information on setting value oom_score_adj, see the page https://man7.org/linux/man-pages/man5/proc.5.html
lsapi_server_tweak
Syntax: lsapi_server_tweak [On/Off]
Default: lsapi_server_tweak Off
Context: httpd.conf
Description: This option, when switched on, allows the use of lsapi_set_env
and lsapi_set_env_path
config options in the virtualhost context.
Connection pool mode
lsapi_with_connection_pool
Syntax : lsapi_with_connection_pool On/Off
Default : lsapi_with_connection_pool Off
Context : httpd.conf
Description :
On/Off - disable enable connect pool, default is Off.
lsapi_backend_max_idle
Syntax : lsapi_backend_max_idle [number]
Default : lsapi_backend_max_idle 300
Context : httpd.conf
Description :
It is relevant only with lsapi_with_connection_pool option switched on. Controls how long a worker process will wait for a new request before it exits. 0 stands for infinite. Should be more or equal to 0. In the case of wrong format default value will be used. Optional, default value is 300.
lsapi_backend_max_reqs
Syntax : lsapi_backend_max_reqs [number]
Default : lsapi_backend_max_reqs 10000
Context : httpd.conf
Description :
It is relevant only with lsapi_with_connection_pool option switched on. Controls how many requests a worker process will process before it exits. Should be more than 0. In the case of wrong format default value will be used. Optional, default value is 10000.
CRIU support
lsapi_criu
Syntax : lsapi_criu On/Off
Default : lsapi_criu Off
Context : httpd.conf
Description :
Enable/disable CRIU for lsphp freezing. Default: Off.
lsapi_criu_socket_path
Syntax : lsapi_criu_socket_path [path]
Default : lsapi_criu_socket_path /var/run/criu/criu_service.socket
Context : httpd.conf
Description :
Set path to socket for communication with criu service. Default: /var/run/criu/criu_service.socket.
lsapi_criu_imgs_dir_path
Syntax : lsapi_criu_imgs_dir_path [path]
Default : lsapi_criu_imgs_dir_path /var/mod_lsapi/
Context : httpd.conf
Description :
Path to folder where images of freezed PHP will be stored. Should be path. Default: /var/mod_lsapi/
lsapi_backend_initial_start
Syntax : lsapi_backend_initial_start [number]
Default : lsapi_backend_initial_start 0
Context : httpd.conf
Description :
Number of requests to virtualhost, when lsphp will be freezed. Default: 0 - means disable freezing.
lsapi_criu_use_shm
Syntax : lsapi_criu_use_shm Off/Signals
Default : lsapi_criu_use_shm Off
Context : httpd.conf
Description :
Method of requests counting. Off - use shared memory. Signals - use signals from child processes to parent. Default: Off
lsapi_backend_semtimedwait
Syntax : lsapi_backend_semtimedwait On/Off
Default : lsapi_backend_semtimedwait On
Context : httpd.conf
Description :
Use semaphore for checking when lsphp process will be started. Speed of start lsphp increased with semaphore using. This method avoid cycles of waiting for lsphp start. Default: On.
lsapi_reset_criu_on_apache_restart
Syntax : lsapi_reset_criu_on_apache_restart On/Off
Default : lsapi_reset_criu_on_apache_restart Off
Context : httpd.conf, virtualhost
Description :
This option allows cleaning all CRIU images on Apache restart.
Setting lsapi_reset_criu_on_apache_restart to On means that on each Apache restart the CRIU images which are stored in directory specified by lsapi_criu_imgs_dir_path directive will be recreated on new request to domain(only after restart).
If this option set to Off then CRIU images won’t be recreated on Apache restart.
lsapi_criu_debug
Syntax: lsapi_criu_debug On/Off
Default: lsapi_criu_debug Off
Context: httpd.conf, virtualhost
Description :
Enable/disable CRIU related debug logging.
PHP configuration management
lsapi_process_phpini
Syntax : lsapi_process_phpini On/Off
Default : lsapi_process_phpini Off
Context : httpd.conf, virtualhost, directory
Description :
Enable or disable phpini_* directive processing. Default value is Off.
lsapi_phpini
Syntax : lsapi_phpini [path]
Default : lsapi_phpini -
Context : httpd.conf, virtualhost, htaccess
Description :
When lsapi_process_phpini option switched to Off, these values will be silently ignored. lsapi_phpini values with absolute filename of php.ini file can be inserted into .htaccess files in order to set custom php.ini which will override/complement settings from system default php.ini.
lsapi_phprc
Syntax : lsapi_phprc [No | Env | Auto | DocRoot]
Default : lsapi_phprc No
Context : httpd.conf, virtualhost
Description : The value of PHPRC env variable.
Special values are "No", "Env", "Auto" and "DocRoot".
Default value is "No" - without PHPRC at all.
"Auto" value stands for php.ini from DocumentRoot of the corresponding VirtualHost if it is present, or from user's home directory otherwise "DocRoot" value stands for php.ini from DocumentRoot of the corresponding VirtualHost.
"Env" value for using PHPRC from the environment, to set it with SetEnv config option, for example
lsapi_phprc No
lsapi_phprc Auto
lsapi_phprc DocRoot
lsapi_phprc Env
lsapi_phprc /etc/
lsapi_tmpdir
Syntax : lsapi_tmpdir [path]
Default : lsapi_tmpdir /tmp
Context : httpd.conf, virtualhost
Description :
Set alternate request body temporary files directory.
lsapi_enable_user_ini
Syntax : lsapi_enable_user_ini On/Off
Default : lsapi_enable_user_ini Off
Context : httpd.conf, virtualhost
Description :
Enable .user.ini files for backend. Same as suphp, php-fpm and fcgid mechanism of .user.ini. Default value is Off.
lsapi_user_ini_homedir
Syntax : lsapi_user_ini_homedir On/Off
Default : lsapi_user_ini_homedir Off
Context : httpd.conf, virtualhost
Description :
If lsapi_enable_user_ini option is set to On, then enable/disable processing .user.ini file in home directory also. Default value is Off.
lsapi_keep_http200
Syntax : lsapi_keep_http200 On/Off
Default : lsapi_keep_http200 Off
Context : httpd.conf, .htaccess
Description :
If set to On, always keep backend's response status as mod_php does. If set to Off, response status can be overridden by Apache as suphp does (in case of call via ErrorDocument directive).
lsapi_mod_php_behaviour
Syntax : lsapi_mod_php_behaviour On/Off
Default : lsapi_mod_php_behaviour On
Context : httpd.conf, virtualhost, directory
Description :
On/Off - disable php_* directives, default On.
php_value, php_admin_value, php_flag, php_admin_flag
Syntax : [php_value|php_admin_value|php_flag|php_admin_flag]
Default :
Context : httpd.conf, virtualhost, htaccess
Description :
mod_php emulation.
Security
lsapi_use_suexec
Syntax : lsapi_use_suexec On/Off
Default : lsapi_use_suexec On
Context : httpd.conf
Description :
Use or not suexec to a target user.
lsapi_user_group
Syntax : lsapi_user_group [user_name] [group_name]
Default : -
Context : httpd.conf, virtualhost, directory
Description :
Set user & group for requests.
lsapi_uid_gid
Syntax : lsapi_uid_gid [uid] [gid]
Default : -
Context : httpd.conf, virtualhost, directory
Description :
Set user & group for request.
lsapi_use_default_uid
Syntax : lsapi_use_default_uid On/Off
Default : lsapi_use_default_uid On
Context : httpd.conf
Description :
Use default Apache UID/GID if no uid/gid set. Values: On/Off. If Off, and no UID/GID set, error 503 will be returned.
lsapi_target_perm
Syntax : lsapi_target_perm On/Off
Default : lsapi_target_perm Off
Context : httpd.conf
Description :
Check target PHP script permissions. If set to On, lsapi will check that script is owned by the same user, as user under which it is being executed. Return 503 error if they don't match. Default: Off.
lsapi_paranoid
Syntax : lsapi_paranoid On/Off
Default : lsapi_paranoid Off
Context : httpd.conf
Description :
Check or not permissions of target php scripts. Optional, default value is Off.
lsapi_check_document_root
Syntax : lsapi_check_document_root On/Off
Default : lsapi_check_document_root On
Context : httpd.conf
Description :
Check or not owner of DOCUMENT_ROOT. Optional, default value is On.
lsapi_disable_forced_pwd_var
Syntax : lsapi_disable_forced_pwd_var On/Off
Default : lsapi_disable_forced_pwd_var Off
Context : httpd.conf, virtualhost
Description :
To disable addition of PWD variable. Default value is Off. If set to On, the PWD variable will not be added into a backend environment.
lsapi_max_resend_buffer
Syntax : lsapi_max_resend_buffer [number]tmp
Default : lsapi_max_resend_buffer 200
Context : httpd.conf, virtualhost
Description :
Maximum buffer in KiB to resend for request that has a body (like POST request body).
See also Apache mod_lsapi PRO CLI tools.
Troubleshooting
Debugging mod_lsapi issues: error_log & sulsphp_log
mod_lsapi errors will be located in error_log and sulsphp_log. Note that errors can appear in both logs at the same time, and you might need to refer to both of them to solve the issue.
See next table for more details:
error_log | sulsphp_log | Solution |
Could not connect to lsphp backend: connect to lsphp failed: 111 Connection refused. Increase memory limit for LVE ID | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase pmem or vmem limits for the user uid. |
Error sending request: ReceiveLSHeader: nothing to read from backend socket | No need to check this log. | lsphp was killed. It can be due to apache restart or lfd. If you see this message too often - change lsapi_terminate_backends_on_exit to Off in lsapi.conf or add to /etc/csf/csf.pignore the following lines: exe:/usr/local/bin/lsphp pexe:/opt/alt/php.*/usr/bin/lsphp |
Error sending request (lsphp is killed?): ReceiveLSHeader: nothing to read from backend socket, referer: http://XXXXXXX Child process with pid: XXXXX was killed by signal: 11, core dump: 0 | No need to check this log. | lsphp has crashed. Next slide will explain what to do (core dump creating). Also, check configuration options for apc and suhosin in php.ini. Once you have a core file generated at DocumentRoot contact https://cloudlinux.zendesk.com/ so we can investigate the cause. |
Could not connect to lsphp backend: connect to lsphp failed: 111 Connection refused | file is writable by others: (///usr/local/bin/lsphp) | Incorrect lsphp file permissions. For fixing: chmod 755 /usr/local/bin/lsphp cagefsctl --force-update. |
Could not determine uid/gid for request | No need to check this log. | UID/GID are not set in virtualhost. Set lsapi_use_default_uid On in lsapi.conf (it is On by default since 0.1-98 version, this solution is for older versions). |
Own id for script file (/xxxx/xxx/xxxx) is xxx; should be xxxx | No need to check this log. | File is not owned by the user PHP executed by. To overwrite (insecure), set lsapi_target_perm Off in lsapi.conf. |
Could not connect to lsphp backend: connect to lsphp failed: 111 Connection refused | Entering jail error | Check if СageFS enabled. Try running cagefsctl --remount-all. |
Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: backend process reset connection: errno 104 (possibly memory limit for LVE ID XXXX too small) | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase PMEM limits for the user UID. |
Reached max children process limit: XX, extra: 0, current: XX, please increase LSAPI_CHILDREN. Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: backend process reset connection: errno 104 (possibly memory limit for LVE ID XXXX too small) | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase value of lsapi_backend_children for UID in vhost.conf or globally in lsapi.conf. |
fork() failed, please increase process limit: Cannot allocate memory Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: backend process reset connection: errno 104 (possibly memory limit for LVE ID XXXX too small) | uid:(xxx); gid:(xxx); uid limit warning: EP should be < than NPROC, current EP: XX, NPROC: XX uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase NPROC limits for the UID. It should be greater than EP and lsapi_backend_children. |
Child process with pid: XXXXXX was killed by signal: 9, core dump: 0 Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: nothing to read from backend socket (LVE ID XXXX | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | These errors occurs when the amount of PMEM limits is incommensurable with the number of EP. Increase PMEM limits or decrease EP number for the user UID. |
totBytesRead (X) != bodyLen (X), referer: XXXX Backend error on sending request(POST /XXXX HTTP/1.1); uri(/XXXX) content-length(X) (lsphp is killed?): ReceiveAckHdr: nothing to read from backend socket (LVE ID XXXX) lsphp(XXXX): Child process with pid: XXXX was killed by signal: 15, core dump: 0 | No need to check this log. | Increase LimitRequestBody (Apache) or/and SecRequestBodyNoFilesLimit (mod_security) configuration limits |
Connect to backend failed: connect to lsphp failed: 13 | No need to check this log. | Check that mod_ruid2 is disabled |
Connect to backend rejected on sending request(POST /XXXXX HTTP/1.1); uri(/XXXXX) | No need to check this log. | Set lsapi_disable_reject_mode On in your lsapi.conf and reload Apache. This way LSPHP daemon will put requests that cannot be served by LSPHP daemon right away into infinite queue, until one or more LSPHP daemon becomes free. Visit Configuration Reference for more info. |
Non-standard apache user
If apache runs under a username other than "apache" or "nobody" , you should rebuild sulsphp (where username is built in for security reasons) with corresponding username:
yum install liblsapi liblsapi-devel
cd ~$ wget [https://repo.cloudlinux.com/cloudlinux/sources/da/mod_lsapi.tar.gz](https://repo.cloudlinux.com/cloudlinux/sources/da/mod_lsapi.tar.gz)
tar zxvf mod_lsapi.tar.gz
cd mod-lsapi-0.1-37
cmake -DHTTPD_USER=<new user name> .
make
make install
- Install: /usr/lib/apache/mod_lsapi. so (or to another correct httpd modules path)
- Install: /usr/sbin/sulsphp
lsphp started under user apache/nobody
Check if SuExecUserGroup specified for virtual hosts. This parameter is used by mod_lsapi for user identification.
Could not connect to lsphp backend: connect failed: 111 Connection refused
Switch in lsapi.conf or mod_lsapi.conf value to: lsapi_terminate_backends_on_exit Off
Check if empty: cat /etc/cron.d/kill_orphaned_php-cron | grep lsphp , then run:
yum install lve-utils
Running PHP for users with UID < 99
If you need to run PHP using mod_lsapi using users with UID < 99, you would need to re-compile sulsphp:
yum install liblsapi liblsapi-devel
cd ~
wget [https://repo.cloudlinux.com/cloudlinux/sources/da/mod_lsapi.tar.gz](https://repo.cloudlinux.com/cloudlinux/sources/da/mod_lsapi.tar.gz)
tar zxvf mod_lsapi.tar.gz
cd mod-lsapi-0.1-XX
cmake -DUID_MIN=80 -DGID_MIN=80 .
make
make install
- Installing: /usr/lib/apache/mod_lsapi.so (or another httpd modules path)
- Installing: /usr/sbin/sulsphp
Apache binary called not httpd (httpd.event, httpd.worker)
yum install liblsapi liblsapi-devel
cd ~
wget https://repo.cloudlinux.com/cloudlinux/sources/da/mod_lsapi.tar.gz
tar zxvf mod_lsapi.tar.gz
cd mod-lsapi-0.1-XX
cmake -DPARENT_NAME="<apache binary name>".
make
make install
- Installing: /usr/lib/apache/mod_lsapi.so (or another httpd modules path)
- Installing: /usr/sbin/sulsphp
WHMCS Status page not accessible after installing CL and mod_lsapi (cPanel).
- add user: useradd userstat
- add to file (to the end of file before </IfModule>) /usr/local/apache/conf/conf.d/lsapi.conf: <Directory /usr/local/apache/htdocs/> lsapi_user_group userstat userstat </Directory>
- service httpd restart
This is safe solution for easyapache rebuilding and cpanel-mod-lsapi updating.
PHP page with Suhosin return 503 error
Make php.ini for suhosin as recommended below:
[suhosin]
suhosin.simulation = Off
suhosin.mail.protect = 1
suhosin.cookie.disallow_nul = Off
suhosin.cookie.max_array_depth = 1000
suhosin.cookie.max_array_index_length = 500
suhosin.cookie.max_name_length = 500
suhosin.cookie.max_totalname_length = 500
suhosin.cookie.max_value_length = 200000
suhosin.cookie.max_vars = 16384
suhosin.get.disallow_nul = Off
suhosin.get.max_array_depth = 1000
suhosin.get.max_array_index_length = 500
suhosin.get.max_name_length = 500
suhosin.get.max_totalname_length = 500
suhosin.get.max_value_length = 1000000
suhosin.get.max_vars = 16384
suhosin.post.disallow_nul = Off
suhosin.post.max_array_depth = 1000
suhosin.post.max_array_index_length = 500
suhosin.post.max_name_length = 500
suhosin.post.max_totalname_length = 500
suhosin.post.max_value_length = 1000000
suhosin.post.max_vars = 16384
suhosin.request.disallow_nul = Off
suhosin.request.max_array_depth = 1000
suhosin.request.max_array_index_length = 500
suhosin.request.max_totalname_length = 500
suhosin.request.max_value_length = 1000000
suhosin.request.max_vars = 16384
suhosin.request.max_varname_length = 524288
suhosin.upload.max_uploads = 300
suhosin.upload.disallow_elf = Off
suhosin.session.cryptua = Off
suhosin.session.encrypt = Off
suhosin.session.max_id_length = 1024
suhosin.executor.allow_symlink = Off
suhosin.executor.disable_eval = Off
suhosin.executor.disable_emodifier = Off
suhosin.executor.include.max_traversal = 8
PHP page with APC return 503 error
Make php.ini for APC as recommended below:
[apc]...apc.shm_segments=1apc.shm_size=32...
Messages appearing in error_log: Child process with pid: XXXXX was killed by signal: 11, core dump: 0
This means that lsphp was crashed. The solution is:
- Check if apc for user enabled. Tune its options as described in previous slide.
- Check if suhosin is enabled for user. Tune its options as described in this article.
- If previous items do not help, contact us at https://helpdesk.cloudlinux.com/
How to get lsphp core dump on crash
- Configure mod_lsapi to allow lsphp to generate core dumps. In mod_lsapi.conf:
lsapi_backend_coredump On
- Enable core file generation in sysctl:
sysctl -w ‘kernel.core_uses_pid=1’
sysctl -w ‘kernel.core_pattern=core.%p’
- Configure system to change max size of core files. In /etc/security/limits.conf add:
user1 soft core unlimited
user1 hard core unlimited
- If /etc/profile.d/limits.sh exists, look up for the following lines:
if [ "$LIMITUSER" != "root" ]; then
ulimit -n 100 -u 35 -m 200000 -d 200000 -s 8192 -c 200000 -v unlimited 2>/dev/null
Add line into ulimit -c unlimited into apachectl script just after another invokes of the ulimit command.
Do cold restart of Apache with the command like this:
service httpd stop; sleep 2; killall lsphp; service httpd start
- You can make sure that ulimit for lsphp is changed to unlimited successfully with the following command:
cat /proc/PID/limits | grep ‘Max core file size’
where PID is a pid of any lsphp process. ps -u user1 | grep lsphp
- Core dump of lsphp will be created in the DocumentRoot of the corresponding virtual server. On cPanel server it should map to
mod_lsapi is not included in output of httpd -M after installation and setup command for cPanel EasyApache 3
Check if the file /usr/local/apache/conf/conf.d/lsapi.conf exists and not empty;
Check if output of the command
cat /usr/local/apache/conf/httpd.conf | grep "/usr/local/apache/conf/conf.d/\*\.conf"
If it is empty:
- Add to "include" section of /var/cpanel/conf/apache/main string:
"include": '"/usr/local/apache/conf/conf.d/*.conf"'
"include":
"directive": 'include'
"items":
...
-
"include": '"/usr/local/apache/conf/conf.d/*.conf"'
"listen":
- Do:
mkdir -p /usr/local/apache/conf/conf.d/;
cp /usr/share/lve/modlscapi/confs/lsapi.conf /usr/local/apache/conf/conf.d/lsapi.conf
- Call:
/scripts/rebuildhttpdconf/scripts/restartsrv_httpd
See also mod_lsapi PRO FAQ here.
CRIU Support
Note
CloudLinux OS 7, CloudLinux OS 7 Hybrid, and CloudLinux OS 8 only
CRIU is Checkpoint/Restore In Userspace , (pronounced kree-oo ), is a software tool for Linux operating system. Using this tool, you can freeze a running application (or part of it) and checkpoint it as a collection of files on disk. You can then use the files to restore the application and run it exactly as it was during the time of freeze (more information on the link https://criu.org/Main_Page ).
mod_lsapi-1.1-1 is the first beta version with freezing PHP implemented. mod_lsapi now supports the following parameters:
Option name | Description | Values | Default |
lsapi_criu | Enable/disable CRIU for lsphp freezing. | On/Off | Off |
lsapi_criu_socket_path | Set path to socket for communication with criu service. | [path to socket] | /var/run/criu/criu_service.socket |
lsapi_backend_semtimedwait | Enable/disable flag for notification about lsphp started. This method avoid cycles of waiting for lsphp start. | On/Off | On |
lsapi_backend_initial_start | Number of request when lsphp should be freezed. | [number] 0 - no freezing | 0 |
lsapi_criu_use_shm | Method of requests counting. Off - use shared memory. Signals - use signals from child processes to parent. | Off/Signals | Off |
lsapi_criu_imgs_dir_path | Path to folder where imgs of freezed PHP will be stored. | [path] | /var/mod_lsapi/ |
lsapi_criu_debug | Enable/Disable CRIU related debug logging. | On/Off | Off |
Example:
lsapi_criu On
lsapi_criu_socket_path /var/run/criu/criu_service.socket
lsapi_backend_semtimedwait On
lsapi_backend_initial_start 15
lsapi_criu_use_shm Off
lsapi_criu_debug Off
When Apache module mod_lsapi detects CRIU enabled (lsapi_criu On) it prepares a directory for images (on the first request of virtualhost) to store ( lsapi_criu_imgs_dir_path /var/mod_lsapi/[dir_name] ), and starts lsphp process. Lsphp increases counter ( lsapi_criu_use_shm Off|Signals ) via shared memory or signals, when counter reaches limit ( lsapi_backend_initial_start 15 ), lsphp sends the request to CRIU for freezing. CRIU service makes images of requested processes. Lsphp will not be frozen if counter has not reached the limit. The next time when lsphp will be stopped, it will be unfrozen from the images.
The images of the processes will be saved even if Apache is restarted. But all images will be deleted after server restart by default configuration. This can be modified by setting the new path lsapi_criu_imgs_dir_path .
Important!
If php.ini or configuration file from php.d is changed, the images must be deleted manually.
Note
CRIU (version lower than criu-lve-3.6-1) can't correctly freeze lsphp with PrivateTmp enabled. For correct work, PrivateTmp must be disabled in httpd.service file .
To disable it, copy httpd.service to /etc/systemd/system and change there PrivateTmp:
cat httpd.service
............
[Unit]
Description=Apache web server managed by cPanel Easy
ApacheConditionPathExists=!/etc/httpddisable
ConditionPathExists=!/etc/apachedisable
ConditionPathExists=!/etc/httpdisable
[Service]Type=forking
ExecStart=/usr/local/cpanel/scripts/restartsrv_httpd --no-verbose
PIDFile=/var/run/apache2/httpd.pid
PrivateTmp=false
[Install]
WantedBy=multi-user.target
http://www.freedesktop.org/software/systemd/man/systemd.unit.html
mkdir /etc/systemd/system/httpd.service.d
echo "[Service]" > /etc/systemd/system/httpd.service.d/nopt.conf
echo "PrivateTmp=false" >> /etc/systemd/system/httpd.service.d/nopt.conf
and
systemctl daemon-reload
CRIU Installation
Criu is installed with dependency to mod_lsapi package. To activate it:
- Enable service and start it:
systemctl enable criu
systemctl start criu
- Edit lsapi.conf file, turn CRIU On and set some defaults:
lsapi_criu On
lsapi_criu_socket_path /var/run/criu/criu_service.socket
lsapi_backend_semtimedwait On
lsapi_backend_initial_start 15
lsapi_criu_use_shm Off
- Restart apache:
service httpd restart
CRIU Image Cleanup
- An option added to the Apache configuration for cleaning all the images earlier saved by CRIU.
Option name | Description | Value | Default |
lsapi_reset_criu_on_apache_restart | This option allows cleaning all CRIU images on Apache restart. | On/Off | Off |
On the next restart of Apache all of the images will be cleaned.
It can be enabled by writing lsapi_reset_criu_on_apache_restart On in lsapi.conf (Virtual Host and .htaccess do not allow to use this option).
Note that this option works only if lsapi_terminate_backends_on_exit is On (default value is On , it is set in lsapi.conf too).
If you need to clean CRIU images for one user you can simply add file to the user's directory with CRIU images (default /var/mod_lsapi/lsapi * criu_imgs ). On the next restart of lsphp the images will be cleaned.
Global reset flag for cleaning all earlier saved images by CRIU.
Current mod_lsapi allows cleaning all images only with one flag file.
Create /usr/share/criu/mod_lsapi/lsphp.criu.reset file. Also don't forget to set such permissions [nobody:nobody] (or [apache:apache] for non cPanel) and access mode [700] to the /usr/share/criu/mod_lsapi directory.
Steps to do :
mkdir /usr/share/criumkdir /usr/share/criu/mod_lsapi
chown nobody:nobody /usr/share/criu/mod_lsapi
touch /usr/share/criu/mod_lsapi/lsphp.criu.reset
On the next requests to all virtual hosts images will be recreated (deleted first and created again later - it depends on lsapi_backend_initial_start value).
- Аdded possibility to clean CRIU images from user space.
If a user needs to clean CRIU images for lsphp, he should create a file: ~/mod_lsapi_reset_me_[vhost_name] . Where [vhost_name] is a ServerName from the VirtualHost block in the configuration file. On the next restart of lsphp, the images will be cleaned.
Example:
cd; touch mod_lsapi_reset_me_criu.test.com
where vhost.conf contains:ServerName criu.test.com
This mode is enabled by default and creates a separate lsphp process for each virtual host.
mod_lsapi_reset_me[vhost_name]
flag will not work for a user when lsapi_per_user option is On
.
- There is (default
off
) option in mod_lsapi that creates only one lsphp process for a user, regardless of the number of his virtual hosts. We don't recommend to use this option with CRIU, but if you use it, make sure that your virtual hosts (under the same user) have the same environment configurations. If they are not the same, this may cause undesirable lsphp process operation.
NGINX LSAPI Module
General information and requirements
The NGINX LSAPI Module is an extension for the NGINX web server, designed to seamlessly integrate the lightweight, high-performance LiteSpeed PHP processing capability directly within the NGINX architecture. This module enables NGINX to efficiently handle PHP requests using the LiteSpeed SAPI, offering an alternative to traditional PHP-FPM or mod_php approaches. It aims to leverage the speed and flexibility of LiteSpeed's PHP processing in environments where the NGINX is the preferred web server.
How does it work?
- NGINX passes handling for PHP request to NGINX LSAPI Module;
- NGINX LSAPI Module uses liblsapi to transfer request to the lsphp parent process;
- lsphp forks the child process, which executes the request and returns data to NGINX LSAPI Module;
- If there are no requests for lsapi_pgrp_max_idle seconds, lsphp parent process will be terminated;
- If there are no lsphp child processes available when a new request comes, the new lsphp child process will be created;
- lsphp children process concurrent requests simultaneously;
- The maximum number of simultaneously running lsphp child processes can be set by the lsapi_backend_children directive.
What is lsphp?
lsphp - PHP + LSAPI. What is PHP LSAPI? LiteSpeed Server Application Programming Interface (LSAPI) is designed specifically for seamless, optimized communication between the LiteSpeed Web Server and third-party web applications. With NGINX LSAPI Module, this protocol is now available for NGINX.
Using NGINX LSAPI Module, we have seen higher performance than NGINX with fastcgi+php-fpm, easier installation than php-fpm and easier integration with any control panel. NGINX LSAPI Module means faster and more stable dynamic web pages.
Optional requirements
- Configured LVE containers for end-users ( recommended - control over resource consumption );
- Enabled CageFS for end-users ( recommended - higher security level );
- PHP Selector with alt-php - an easy way to select different PHP versions for each end-user provided by CloudLinux OS;
- ea-php - alternative to alt-php provided by cPanel (for cPanel only).
Installation
NGINX LSAPI Module can be installed through YUM package manager. However, the installation process varies depending on the control panel.
Select the control panel you are using:
- cPanel
- No control panel - In progress
- Plesk - In progress
- DirectAdmin - In progreess
Installing on cPanel servers with ea-nginx
Install NGINX LSAPI Module and related packages through YUM package manager as follows:
yum install ea-nginx-mod-lsapi --enablerepo=cl-ea4-testing
service nginx restart
Use Apache2Nginx to set up NGINX hosting on the server and automatically convert .htaccess files into corresponding NGINX configuration. For more details, please visit Apache2Nginx.
Uninstalling
The uninstallation process of the NGINX LSAPI Module also varies depending on your control panel.
Select the control panel you are using:
- cPanel
- No control panel - In progress
- Plesk - In progress
- DirectAdmin - In progreess
Uninstallation procedure for cPanel servers with ea-nginx
Remove packages with YUM package manager:
yum erase ea-nginx-mod-lsapi
service nginx restart
To remove NGINX from your system and restore Apache configuration, please visit Apache2Nginx.
Uninstallation procedure for servers with no control panel
Remove packages with YUM package manager:
yum erase ea-nginx-mod-lsapi
rm [path to nginx-mod-lsapi.conf]
service nginx restart
Configuration
Note
If using Apache2Nginx, no configuration is required for NGINX LSAPI Module. The module is automatically configured to process PHP requests.
In order to get NGINX LSAPI Module to work properly, you'll need to configure NGINX. To do this, we use a separate lsapi.conf file.
First of all, you need to make sure that the appropriate LSAPI module configuration exists and contains the correct content.
[root@nginx]# cat /usr/share/nginx/modules/ngx-mod-lsapi.conf
load_module "/usr/lib64/nginx/modules/ngx_http_lsapi_module.so";
In case of ea-nginx the file can be: /etc/nginx/conf.d/modules/ea-nginx-lsapi-module.conf
Then make sure that the loading of dynamic modules is not omitted in your main nginx configuration (nginx.conf).
include /usr/share/nginx/modules/*.conf;
lsapi_enabled on;
The lsapi_enabled parameter is supported in global, server, and local configurations. Therefore, it can be enabled/disabled globally, only for the server, and also only for a specific location.
The LSPHP handler can be enabled using the lsapi_handler directive. The lsapi_handler directive tells NGINX that the files with .php extension should be handled by NGINX LSAPI Module with the selected handler.
lsapi_handler application/x-httpd-lsphp;
If no handler is explicitly set for a request, the specified content type will be used as the handler name, therefore, please disable php.conf or any other PHP handler for using NGINX LSAPI Module. In this example application/x-httpd-lsphp is a default handler by which NGINX LSAPI Module processes requests with the lsphp binary from /usr/local/bin/ directory.
The final lsapi.conf configuration might look like this:
server {
listen 80;
server_name testlsapi.com;
root /home/testlsapi/public_html;
location ~ \.php$ {
lsapi_enabled on;
lsapi_handler application/x-httpd-lsphp;
lsapi_user testlsapi;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
In order for NGINX LSAPI Module to work lsapi.conf should be loaded to NGINX through Include directive.
For a more detailed description of the module directives please visit the Configuration reference.
For the installation guide for NGINX LSAPI Module please visit Installation.
Configuration references
NGINX LSAPI Module customization:
- lsapi_enabled
- lsapi_sock_path
- lsapi_per_user
- lsapi_disable_reject
- lsapi_terminate_backends_ex
- lsapi_avoid_zombies
- lsapi_set_env
- lsapi_env_path
- lsapi_backend_children
- lsapi_retry_max
- lsapi_max_process_time
- lsapi_pgrp_max_idle
- lsapi_own_log
- lsapi_common_own_log
- lsapi_backend_coredump
- lsapi_accept_notify
- lsapi_pgrp_max_reqs
- lsapi_pgrp_max_crashes
- lsapi_backend_loglevel_info
- lsapi_oom_score_adj
- lsapi_use_criu
- lsapi_criu_sock_path
- lsapi_criu_imgs_path
- lsapi_backend_initial_start
- lsapi_criu_use_shm
- lsapi_reset_criu_on_restart
- lsapi_criu_debug
- lsapi_process_phpini
- lsapi_phpini
- lsapi_phprc
- lsapi_tmpdir
- lsapi_enable_user_ini
- lsapi_user_ini_homedir
- lsapi_mod_php_behaviour
- lsapi_param
NGINX LSAPI Module customization
lsapi_enabled
Syntax : lsapi_enabled [on/off]
Example : lsapi_enabled on;
Default : off
Context : main config, server config, local config.
Type : Mandatory
Description :
Enable/disable LSAPI module for nginx, server, or local directory.
lsapi_sock_path
Syntax : lsapi_sock_path [path] Example : lsapi_sock_path /var/ngx_lsapi;
Default : /var/ngx_lsapi
Context : main config Type : Optional
Description:
Path to backend lsphp sockets. By default /var/ngx_lsapi
lsapi_per_user
Syntax : lsapi_per_user [on/off]
Example : lsapi_per_user off;
Default : off
Context : server config, location config Type : Optional
Description :
Invoke the master lsPHP process not per VirtualHost, but per account. When On, invoke backend not per VirtualHost but per account. Default value is off. It is possible, for example, to set it to On in global config file and to Off in config files of some particular Virtual Hosts. Then these Virtual Hosts will have a dedicated backend process, while others will have backend processes shared on account basis.
lsapi_disable_reject
Syntax : lsapi_disable_reject [on/off]
Example : lsapi_disable_reject on;
Default : off
Context : server config
Type : Optional
Description :
If a new HTTP request is coming to LSPHP daemon when all LSPHP workers are still busy, it can process this situation in two different ways. In REJECT mode LSPHP daemon will reject such requests immediately. Otherwise, in legacy mode, LSPHP daemon will put this request into an infinite queue, until one of LSPHP daemons becomes free. When a HTTP request is rejected in REJECT mode, mod_lsapi will write the following message into the NGINX error.log: Connect to backend rejected
, and the client will receive a 507 HTTP response. By default, the LSPHP daemon in CloudLinux OS uses the REJECT mode. It can be switched off with this option.
lsapi_terminate_backends_ex
Syntax : lsapi_terminate_backends_ex [on/off]
Example : lsapi_terminate_backends_ex on;
Default : on
Context : main config
Type : Optional
Description :
nginx.conf, on - stop lsphp services on nginx restart, off - leave live started lsphp services on nginx restart (for php+opcache). The lsphp will not restart, even if NGINX gets restarted.
lsapi_avoid_zombies
Syntax : lsapi_avoid_zombies [on/off]
Example : lsapi_avoid_zombies on;
Default : off
Context : server config
Type : Optional
Description :
Enable or disable a mechanism to avoid the creation of zombie processes by lsphp. The default value is Off.
lsapi_starter_sock
Syntax : lsapi_starter_sock [path]
Example : lsapi_starter_sock /var/run/lsapi-starter.sock;
Default : /var/ngx_lsapi/starter.sock
Context : main config
Type : Optional
Description :
This parameter configures the socket address for the lsphp backend spawner process.
lsapi_starter_log
Syntax : lsapi_starter_log [path]
Example : lsapi_starter_log /var/log/lsapi-starter.log;
Default : -
Context : main config
Type : Optional
Description :
This parameter configures the log file address for the lsphp backend spawner process.
lsapi_log
Syntax : lsapi_log [path]
Example : lsapi_log /var/log/lsapi.log;
Default : -
Context : main config
Type : Optional
Description :
This parameter configures the log file address for the NGINX LSAPI module context.
Note :
This parameter only works if the NGINX LSAPI module is built with the NGX_LSAPI_CUSTOM_LOGGER flag. Otherwise, the NGINX logger will be used for LSAPI module logging.
Tuning LSPHP backend
lsapi_set_env
Syntax : lsapi_set_env [var] [value]
Example: lsapi_set_env TMP "/var/lsphp-tmp";
Default : -
Context : main config
Type : Optional
Description :
Pass an environment variable to lsphp. By default the lsphp environment has only TEMP, TMP and PATH variables set.
Note: PATH env var default "/usr/local/bin:/usr/bin:/bin" cannot be changed because of security reasons.
lsapi_env_path
Syntax : lsapi_env_path [path(s)]
Default : lsapi_env_path /usr/local/bin:/usr/bin:/bin
Context : main config
Type : Optional
Description :
Change PATH variable in the environment of lsphp processes. Default path /usr/local/bin:/usr/bin:/bin will be used if not set.
lsapi_backend_children
Syntax : lsapi_backend_children [number]
Example : lsapi_backend_children 300;
Default : 120
Context : server config
Type : Optional
Description :
Sets the maximum number of simultaneously running child backend processes. Optional - a default directive value is equal to 120.
lsapi_retry_max
Syntax : lsapi_retry_max [number]
Example : lsapi_retry_max 20;
Default : 10
Context : server config
Type : Optional
Description :
Number of retries for connections to the lsPHP daemon.
lsapi_max_process_time
Syntax : lsapi_max_process_time [number]
Example : lsapi_max_process_time 300;
Default : 300
Context : server config
Type : Optional
Description :
Sets the env variable LSAPI_MAX_PROCESS_TIME. Optional - default value is 300. Timeout to kill runaway processes.
lsapi_common_own_log
Syntax : lsapi_common_own_log [on/off]
Example : lsapi_common_own_log on;
Default : off
Context : server config
Type : Optional
Description :
It will be used only when lsapi_backend_use_own_log is set to On. On-backend processes of the all virtual hosts will share the common log file. Off - every virtual host will have its own backend log file.
lsapi_own_log
Syntax : lsapi_own_log [on/off]
Example : lsapi_own_log on;
Default : off
Context : server config
Type : Optional
Description :
Redirecting log output of backend processes from NGINX error.log to dedicated log file or files, depending on the value of the lsapi_common_own_log option. If off, use the NGINX error log file for backend output, or a separate file otherwise.
lsapi_pgrp_max_crashes
Syntax : lsapi_pgrp_max_crashes [number]
Example : lsapi_pgrp_max_crashes 300;
Default : 300
Context : server config
Type : Optional
Description :
Controls how many crashes of its worker processes a control process will detect before it exits. Should be more or equal to 0. In the case of a wrong format, a default value will be used. Optional, the default value is 0, which means an unlimited number of crashes.
lsapi_pgrp_max_idle
Syntax : lsapi_pgrp_max_idle [number]
Example : lsapi_pgrp_max_idle 30;
Default : 30
Context : server config
Type : Optional
Description :
Sets env variable LSAPI_PGRP_MAX_IDLE, in seconds. Controls how long a control process will wait for a new request before it exits. 0 stands for infinite. Optional, default value is 30. Should be more or equal to 0.
lsapi_pgrp_max_reqs
Syntax : lsapi_pgrp_max_reqs [number]
Example : lsapi_pgrp_max_reqs 0;
Default : 0
Context : server config
Type : Optional
Description :
Controls how many requests a control process will process before it exits. Should be more or equal to 0. In the case of a wrong format, the default value will be used. Optional, the default value is 0, which means an unlimited number of requests.
lsapi_backend_loglevel_info
Syntax: lsapi_backend_loglevel_info [on/off] Example: lsapi_backend_loglevel_info on; Example: off Context: server config, location config Type : Optional
Description:
Controls which log level will be used to write PHP warnings and notices into NGINX’s error.log. Optional, the default value is off
. In that case, the warn
log level will be used. Otherwise, with on
value, the info
log level will be used.
lsapi_oom_score_adj
Syntax : lsapi_oom_score_adj [number]
Example : lsapi_oom_score_adj 100;
Default : 0
Context : server config
Type : Optional
Description :
This option can apply oom_score_adj values for PHP processes created by mod_lsapi. Value is an integer in the -1000 to 1000 range. The lower the value, the lower the chance that the process will be killed. When your server becomes low on free memory and an OOM killer is invoked, then it may be desirable for lsphp processes to be sacrificed to free up memory. To do this, you need to set oom_score_adj to a large value. For more information on setting a proper value for oom_score_adj, see the page https://man7.org/linux/man-pages/man5/proc.5.html
lsapi_dump_debug_info
Syntax : lsapi_dump_debug_info [on/off]
Example : lsapi_dump_debug_info on;
Default : off
Context : server config
Type : Optional
Description :
Enable or not lsphp backend debug information dump.
lsapi_accept_notify
Syntax : lsapi_accept_notify [on/off]
Example : lsapi_accept_notify on;
Default : off
Context : server config
Type : Optional
Description :
Switch LSAPI_ACCEPT_NOTIFY mode for lsphp. This option can be used both in Global and VirtualHost scopes. This mode is incompatible with PHP 4.4.
lsapi_backend_coredump
Syntax : lsapi_backend_coredump [on/off]
Example : lsapi_backend_coredump on;
Default : off
Context : server config
Type : Optional
Description :
env variable LSAPI_ALLOW_CORE_DUMP (On or Off). Pass LSAPI_ALLOW_CORE_DUMP to lsphp or not. If it is passed - a core dump on lsphp crash will be created. Off by default. By default LSAPI application will not leave a core dump file when crashed. If you want to have LSAPI PHP dump a core dump file, you should set this environment variable. If set, regardless of the value is has been set to, core dump files will be created under the directory that the PHP script is in.
lsapi_pwd_disabled
Syntax : lsapi_pwd_disabled [on/off]
Example : lsapi_pwd_disabled on;
Default : off
Context : server config
Type : Optional
Description :
To disable the addition of the PWD variable. The default value is Off. If set to On, the PWD variable will not be added to a backend environment.
lsapi_handler
Syntax : lsapi_handler [string]
Example : lsapi_handler application/x-httpd-lsphp;
Default : -
Context : server config
Type : Mandatory
Description :
Sets LSPHP handler for server (virtual host) configuration.
Connection pool mode
lsapi_use_pool
Syntax : lsapi_use_pool [on/off]
Example : lsapi_use_pool off;
Default : on
Context : main config
Type : Optional
Description :
Enable/disable LSAPI connection pool mode.
lsapi_max_idle
Syntax : lsapi_max_idle [number]
Example : lsapi_max_idle 300;
Default : 300
Context : server config
Type : Optional
Description :
It is relevant only with lsapi_use_pool option switched on. Controls how long a worker process will wait for a new request before it exits. 0 stands for infinite. Should be more or equal to 0. In the case of a wrong format the default value will be used. Optional, default value is 300.
lsapi_max_reqs
Syntax : lsapi_max_reqs [number]
Example : lsapi_max_reqs 20000;
Default : 10000
Context : server config
Type : Optional
Description :
It is relevant only with lsapi_use_pool option switched on. Controls how many requests a worker process will process before it exits. Should be more than 0. In the case of a wrong format the default value will be used. Optional, default value is 10000.
lsapi_pool_size
Syntax : lsapi_pool_size [number]
Example : lsapi_pool_size 20;
Default : 50
Context : main config
Type : Optional
Description :
The parameter sets the connection pool size for each virtual host.
CRIU support
lsapi_use_criu
Syntax : lsapi_use_criu [on/off]
Example : lsapi_use_criu on;
Default : off
Context : main config
Type : Optional
Description :
Enable/disable CRIU for lsphp freezing. Default: Off.
lsapi_criu_sock_path
Syntax : lsapi_criu_sock_path [path]
Example : lsapi_criu_socket_path /var/run/criu/criu_service.socket;
Default : /var/run/criu/criu_service.socket
Context : main config
Type : Optional
Description :
Set path to socket for communication with criu service.
lsapi_criu_imgs_path
Syntax : lsapi_criu_imgs_path [path]
Example : lsapi_criu_imgs_path /var/ngx_lsapi/criu;
Default : /var/ngx_lsapi/criu
Context : main config
Type : Optional
Description :
Path to the folder where images of frozen PHP will be stored. Should be a path.
lsapi_criu_use_shm
Syntax : lsapi_criu_use_shm [off/signals]
Example : lsapi_criu_use_shm signals;
Default : off
Context : main config
Type : Optional
Description :
The method of request counting. Off - use shared memory. Signals - use signals from child processes to parents. Default: off
lsapi_reset_criu_on_restart
Syntax : lsapi_reset_criu_on_restart [on/off]
Example : lsapi_reset_criu_on_restart off;
Default : off
Context : main config
Type : Optional
Description :
This option allows cleaning all CRIU images on NGINX restart.
Setting lsapi_reset_criu_on_restart to on means that on each NGINX restart the CRIU images, which are stored in the directory specified by lsapi_criu_imgs_path directive, will be recreated upon a new request to domain (only after restart).
lsapi_criu_debug
Syntax: lsapi_criu_debug [on/off]
Example: lsapi_criu_debug off;
Default : off
Context : main config
Type : Optional
Description :
Enable/disable CRIU related debug logging.
lsapi_backend_initial_start
Syntax : lsapi_backend_initial_start [number]
Example : lsapi_backend_initial_start 15;
Default : 0
Context : main config
Type : Optional
Description :
Number of requests to virtualhost, when lsphp will be freezed. Default: 0 - means disable freezing.
PHP configuration management
lsapi_process_phpini
Syntax : lsapi_process_phpini [on/off]
Example : lsapi_process_phpini on;
Default : off
Context : server config, location config Type : Optional
Description :
Enable or disable phpini_* directive processing. Default value is off.
lsapi_phpini
Syntax : lsapi_phpini [value]
Example: lsapi_phpini /usr/home/lsapiuser/public_html/php.ini;
Default : -
Context : server config, location
Type : Optional
Description :
Sets custom php.ini within server or location configuration. Absolute file path is required.
When lsapi_process_phpini configuration directive is switched to Off, the value for the lsapi_phpini will be silently ignored.
lsapi_phprc
Syntax : lsapi_phprc [No | Env | Auto | DocRoot]
Example : lsapi_phprc No;
Default : No
Context : server config
Type : Optional
Description :
The value of PHPRC env variable.
Special values are "No", "Env", "Auto" and "DocRoot".
Default value is "No" - without PHPRC at all.
The "Auto" value stands for php.ini from DocumentRoot of the corresponding VirtualHost if it is present, or from the user's home directory otherwise "DocRoot" value stands for php.ini from DocumentRoot of the corresponding VirtualHost.
"Env" value for using PHPRC from the environment, to set it with SetEnv config option, for example:
lsapi_phprc No;
lsapi_phprc Auto;
lsapi_phprc DocRoot;
lsapi_phprc Env;
lsapi_phprc /etc/;
lsapi_tmpdir
Syntax : lsapi_tmpdir [path]
Example : lsapi_tmpdir /usr/tmp;
Default : /tmp
Context : server config
Type : Optional
Description :
Set an alternate request body temporary files directory.
lsapi_enable_user_ini
Syntax : lsapi_enable_user_ini [on/off]
Example : lsapi_enable_user_ini off;
Default : off
Context : server config
Type : Optional
Description :
Enable .user.ini files for backend. Same as suphp, php-fpm and fcgid mechanism of .user.ini. Default value is off.
lsapi_user_ini_homedir
Syntax : lsapi_user_ini_homedir [on/off]
Example : lsapi_user_ini_homedir on;
Default : off
Context : server config
Type : Optional
Description :
If the lsapi_enable_user_ini option is set to On, then enable/disable processing .user.ini file in the home directory also. The default value is Off.
lsapi_mod_php_behaviour
Syntax : lsapi_mod_php_behaviour [on/off]
Example : lsapi_mod_php_behaviour off;
Default : on
Context : server config, location config
Type : Optional
Description :
on/off - disable php_* directives, default On.
lsapi_param
Syntax : lsapi_param [var] [value]
Example: lsapi_param PHP_ADMIN_VALUE "memory_limit=1024M";
Default : -
Context : server config, location config
Type : Optional
Description :
Sets a parameter that should be passed to the LSPHP handler. The value can contain text, variables, and their combinations.
Supported directives:
PHP_ADMIN_VALUE
PHP_VALUE
PHP_ADMIN_FLAG
PHP_FLAG
Examples:
lsapi_param PHP_ADMIN_VALUE "memory_limit=1024M \n max_execution_time=600";
lsapi_param PHP_FLAG "display_startup_errors=on";
lsapi_param PHP_ADMIN_FLAG "html_errors=on";
lsapi_param PHP_VALUE "max_file_uploads=20";
lsapi_param QUERY_STRING $query_string;
lsapi_param REQUEST_METHOD $request_method;
lsapi_param CONTENT_TYPE $content_type;
lsapi_param CONTENT_LENGTH $content_length;
Security
lsapi_suexec
Syntax : lsapi_suexec [on/off]
Example : lsapi_suexec on;
Default : on
Context : server config
Type : Optional
Description :
Enable or disable suexec usage with a target user.
lsapi_user
Syntax : lsapi_user [username] [group]
Example : lsapi_user testlsapi testlsapi;
Default : -
Context : server config, local config
Type : Mandatory
Description :
Set user & group for requests.
This parameter can take only one argument for username or two arguments for username and group.
lsapi_paranoid
Syntax : lsapi_paranoid [on/off]
Example : lsapi_paranoid on;
Default : off
Context : server config
Type : Optional
Description :
Enable or disable permission checking for the target php scripts.
lsapi_check_owner
Syntax : lsapi_check_owner [on/off]
Example : lsapi_check_owner on;
Default : off
Context : server config
Type : Optional
Description :
Enable or disable checking the owner of the target PHP scripts.
lsapi_check_doc_root
Syntax : lsapi_check_doc_root [on/off]
Example : lsapi_check_doc_root on;
Default : off
Context : server config
Type : Optional
Description :
Enable or disable checking the owner of DOCUMENT_ROOT.
lsapi_check_script
Syntax : lsapi_check_script [on/off]
Example : lsapi_check_script on;
Default : off
Context : server config
Type : Optional
Description :
Enable or disable checking the owner of target php scripts before sending the request to the lsphp backend. Optional, the default value is On.
lsapi_uid_gid
Syntax : lsapi_uid_gid [uid] [gid]
Example : lsapi_uid_gid 1001 1001;
Default : -
Context : local config
Type : Optional
Description :
Set user & group for requests.
Troubleshooting
Debugging NGINX LSAPI Module issues: error.log & sulsphp.log
NGINX LSAPI Module errors will be located in error_log and sulsphp_log. Note that errors can appear in both logs at the same time, and you might need to refer to both of them to solve the issue.
See the following table for more details:
error_log | sulsphp_log | Solution |
Could not connect to lsphp backend: connect to lsphp failed: 111 Connection refused. Increase memory limit for LVE ID | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase pmem or vmem limits for the user uid. |
Error sending request: ReceiveLSHeader: nothing to read from backend socket | No need to check this log. | lsphp was killed. It can be due to nginx restart or lfd. If you see this message too often - change lsapi_terminate_backends_ex to off in lsapi.conf or add to /etc/csf/csf.pignore the following lines: exe:/usr/local/bin/lsphp pexe:/opt/alt/php.*/usr/bin/lsphp |
Error sending request (lsphp is killed?): ReceiveLSHeader: nothing to read from backend socket, referer: http://XXXXXXX Child process with pid: XXXXX was killed by signal: 11, core dump: 0 | No need to check this log. | lsphp has crashed. Next slide will explain what to do (core dump creating). Also, check configuration options for apc and suhosin in php.ini. Once you have a core file generated at DocumentRoot contact https://cloudlinux.zendesk.com/ so we can investigate the cause. |
Could not connect to lsphp backend: connect to lsphp failed: 111 Connection refused | file is writable by others: (///usr/local/bin/lsphp) | Incorrect lsphp file permissions. For fixing: chmod 755 /usr/local/bin/lsphp cagefsctl --force-update. |
Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: backend process reset connection: errno 104 (possibly memory limit for LVE ID XXXX too small) | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase PMEM limits for the user UID. |
Reached max children process limit: XX, extra: 0, current: XX, please increase LSAPI_CHILDREN. Backend error on sending request(GET /XXXX HTTP/1.1); uri(/XXXX) content-length(0) (lsphp is killed?): ReceiveAckHdr: backend process reset connection: errno 104 (possibly memory limit for LVE ID XXXX too small) | uid: (xxx/xxxxxxxx) gid: (xxx/xxxxxxxxxx) cmd: /usr/local/bin/lsphp | Increase value of lsapi_backend_children for UID in vhost.conf or globally in lsapi.conf. |
Connect to backend rejected on sending request(POST /XXXXX HTTP/1.1); uri(/XXXXX) | No need to check this log. | Set lsapi_disable_reject on in your lsapi.conf and reload NGINX. This way LSPHP daemon will put requests that cannot be served by LSPHP daemon right away into infinite queue, until one or more LSPHP daemon becomes free. Visit Configuration Reference for more info. |
CRIU Support
Note
CloudLinux OS 7, CloudLinux OS 7 Hybrid, and CloudLinux OS 8 only
CRIU is Checkpoint/Restore In Userspace , (pronounced kree-oo ), is a software tool for the Linux operating system. Using this tool, you can freeze a running application (or part of it) and checkpoint it as a collection of files on disk. You can then use the files to restore the application and run it exactly as it was at the time of freeze (more information on the link https://criu.org/Main_Page ).
NGINX LSAPI Module now supports the following parameters:
Option name | Description | Values | Default |
lsapi_use_criu | Enable/disable CRIU for lsphp freezing. | on/off | off |
lsapi_criu_sock_path | Set path to socket for communication with criu service. | [path to socket] | /var/run/criu/criu_service.socket |
lsapi_backend_initial_start | Number of request when lsphp should be freezed. | [number] 0 - no freezing | 0 |
lsapi_criu_use_shm | Method of requests counting. off - use shared memory. Signals - use signals from child processes to parent. | off/signals | off |
lsapi_criu_imgs_path | Path to folder where imgs of freezed PHP will be stored. | [path] | /var/nginx-mod-lsapi/ |
lsapi_criu_debug | Enable/Disable CRIU related debug logging. | on/off | off |
Example:
lsapi_criu on;
lsapi_criu_socket_path /var/run/criu/criu_service.socket;
lsapi_backend_initial_start 15;
lsapi_criu_use_shm off;
lsapi_criu_debug off;
When NGINX module NGINX LSAPI Module detects CRIU enabled (lsapi_criu On), it prepares a directory for images (on the first request of virtualhost) to store ( lsapi_criu_img_path /var/ngx_lsapi/criu/[dir_name] ), and starts the lsphp process. Lsphp increases a counter ( lsapi_criu_use_shm off|Signals ) via shared memory or signals, and when counter reaches the limit ( lsapi_backend_initial_start 15 ), lsphp sends the freezing request to CRIU. The CRIU service makes images of requested processes. Lsphp will not be frozen if counter does not reach the limit. The next time when lsphp will be stopped, it will be unfrozen from the images.
The images of the processes will be saved even if NGINX is restarted. However, all images will be deleted after a server restart by default. This can be modified by setting the new path lsapi_criu_imgs_path .
Important!
If php.ini or the configuration file from php.d is changed, the images must be deleted manually.
Note
CRIU (version lower than criu-lve-3.6-1) can't correctly freeze lsphp with PrivateTmp enabled. For correct functionality, PrivateTmp must be disabled in nginx.service file .
To disable it, copy nginx.service to /etc/systemd/system and change there PrivateTmp:
cat nginx.service
............
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=false
[Install]
WantedBy=multi-user.target
http://www.freedesktop.org/software/systemd/man/systemd.unit.html
mkdir /etc/systemd/system/nginx.service.d
echo "[Service]" > /etc/systemd/system/nginx.service.d/nopt.conf
echo "PrivateTmp=false" >> /etc/systemd/system/nginx.service.d/nopt.conf
and
systemctl daemon-reload
CRIU Installation
CRIU is installed as a dependency to the NGINX LSAPI Module package. To activate it:
- Enable service and start it:
systemctl enable criu
systemctl start criu
- Edit lsapi.conf file, turn CRIU On and set some defaults:
lsapi_criu on;
lsapi_criu_socket_path /var/run/criu/criu_service.socket;
lsapi_backend_initial_start 15;
lsapi_criu_use_shm off;
lsapi_criu_debug off;
- Restart NGINX:
service nginx restart
CRIU Image Cleanup
- An option added to the NGINX configuration for cleaning all the images earlier saved by CRIU.
Option name | Description | Value | Default |
lsapi_reset_criu_on_restart | This option allows cleaning all CRIU images on NGINX restart. | on/off | Off |
On the next restart of NGINX all of the images will be cleaned.
It can be enabled by writing lsapi_reset_criu_on_restart on; in lsapi.conf
Note that this option works only if lsapi_terminate_backends_ex is on (default value is On , it is set in lsapi.conf too).
If you need to clean CRIU images for one user you can simply add file to the user's directory with CRIU images (default /var/ngx_lsapi/criu/lsapi * criu_imgs ). On the next restart of lsphp the images will be cleaned.
Global reset flag for cleaning all earlier saved images by CRIU.
The current NGINX LSAPI Module allows cleaning all images only with one flag file.
Create /usr/share/criu/mod_lsapi/lsphp.criu.reset file. Also don't forget to set permissions as follows: [nobody:nobody] (or [nginx:nginx] for non cPanel) and access mode [700] to the /usr/share/criu/mod_lsapi directory.
Steps to do :
mkdir /usr/share/criumkdir /usr/share/criu/mod_lsapi
chown nobody:nobody /usr/share/criu/mod_lsapi
touch /usr/share/criu/mod_lsapi/lsphp.criu.reset
Upon the next incoming request to all virtual hosts, images will be recreated (deleted first and created again later - it depends on lsapi_backend_initial_start value).
- Аdded possibility to clean CRIU images from user space.
If a user needs to clean CRIU images for lsphp, he should create a file: ~/mod_lsapi_reset_me_[server_name] . Where [server_name] is a server_name from the server block in the configuration file. On the next restart of lsphp, the images will be cleaned.
Example:
cd; touch mod_lsapi_reset_me_criu.test.com
where vhost.conf contains:server_name criu.test.com;
This mode is enabled by default and creates a separate lsphp process for each virtual host.
mod_lsapi_reset_me[server_name]
flag will not work for a user when lsapi_per_user option is on
.
- There is an (default
off
) option in NGINX LSAPI Module that creates only one lsphp process for a user, regardless of the number of his virtual hosts. We don't recommend to use this option with CRIU, but if you use it, make sure that your virtual hosts (under the same user) have the same environment configurations. If they are not the same, this may cause undesirable lsphp process operations.
Additional integration components
CloudLinux OS uses various ways to integrate with existing system.
LVE PAM module
pam_lve.so is a PAM module that sets up LVE environment. It provides easy way to setup LVE for SSH sessions, as well as other PAM enabled applications, such as crontab, su, etc.
pam_lve.so is installed by default when you convert existing server.
Installation:
yum install pam_lve
After you install RPM , add the following line to the PAM config file for the required application:
session required pam_lve.so 500 1 wheel,other
In this line:
- 500 stands for minimum UID for which LVE will be setup. For any user with UID < 500, LVE will not be setup. If CageFS is installed, use:
cagefsctl --set-min-uid UID
to setup minimum UID. The parameter in PAM files will be ignored in that case. - 1 stands for CageFS enabled (0 – CageFS disabled)
- 3rd optional argument defines group of users that will not be placed into LVE or CageFS. Starting with pam_lve 0.3-7 you can specify multiple groups, comma separated.
Warning
It is crucial to place all users that su or sudo to root into that group. Otherwise, once such user gains root, user will be inside LVE, and all applications restarted by that user will be inside that user LVE as well.
Warning
Please do not add the pam_lve.so
in the PAM configuration for sudo. It can affect user’s work with the resource usage plugin, and Python/Node.js/PHP selector plugins.
For example, to enable LVE for SSH access, add that line to the /etc/pam.d/sshd
. To enable LVE for SU, add that line to the /etc/pam.d/su
.
By default, module will not place users with group wheel into lve. If you want to use different group to define users that will not be placed into LVE by pam_lve - pass it as the 3rd argument.
Warning
Be careful when you test it, as if you incorrectly add this line to the /etc/pam.d/sshd
, it will lock you out ssh. Don't log out of your current SSH session, until you sure it works.
For preventing cases when user enters under usual user (using ssh) and then tries to enter as super user (via sudo or su) - pam_sulve was created, which tries to enter to LVE=1 and leaves it right away. If action fails, user gets message:
!!!! WARNING: YOU ARE INSIDE LVE !!!!
To check if pam_sulve is enabled on the server:
grep pam_sulve.so /etc/pam.d/*
should not be empty.
LVE wrappers
LVE wrappers are the set of tools that allow system administrator to run various users, programs & daemons within Lightweight Virtual Environment. This allows system administrator to have control over system resources such program can have. Additionally it prevents misbehaving programs running within LVE to drain system resources and slow down or take down the whole system. The tools are provided by lve-wrappers RPM.
You can install them by running:
yum install lve-wrappers
Placing programs inside LVE
LVE Wrappers provide two tools for placing programs inside LVE: lve_wrapper
and lve_suwrapper
.
/bin/lve_wrapper
can be used by any non-root user, as long as that user is in group lve (see /etc/groups
file).
Syntax
lve_wrapper <command_to_run>
Example
lve_wrapper make install
The program will be executed within LVE with ID matching user's id.
/bin/lve_suwrapper
can be used by root user or any user in group lve (see /etc/groups
file) to execute command within specified LVE.
Syntax
lve_suwrapper LVE_ID <command_to_run>
Example
lve_suwrapper 10000 /etc/init.d/postgresql start
Switches
-f
- force namespace-n
- without namespace-c
- remove CPU limits (requireslve_wrapper
>= 2.1.2)
MPM ITK
CloudLinux OS httpd RPM comes with MPM ITK built in. Yet, if you would like to build your own Apache, you need to apply our patch for MPM ITK
- Download file: https://repo.cloudlinux.com/cloudlinux/sources/da/cl-apache-patches.tar.gz
- Extract: apache2.2-mpm-itk-seculrelve12.patch
- And apply this patch to your Apache source code.
When running MPM ITK , you should disable mod_hostinglimits. All the functionality needed by MPM ITK is already built into the patch.
Directives which can be used by Apache with ITK patch:
AssignUserID
- uses ID as LVE IDLVEErrorCodeITK
- error code to display on LVE error (508 by default)LVERetryAfterITK
- same asLVERetryAfter
- respond withRetry-After
header when LVE error 508 occursLVEId
- ovverides id used for LVE ID instead ofAssignUserID
LVEUser
- overrides user to use to retrieve LVE ID, instead of AssignUserID
HostingLimits module for Apache
mod_hostinglimits works with existing CGI/PHP modules, to put them into LVE context. In most cases the CGI/PHP process will be placed into LVE with the ID of the user that sites belongs to. mod_hostinglimits detects the user from SuexecUserGroup
(suexec module), SuPHP_UserGroup
(from mod_suphp), AssignUserID
(MPM ITK), RUidGid
(mod_ruid2 ) directives.
This can be overwritten via LVEId or LVEUser parameter on the Directory level.
Note
Those parameters will not work with mod_fcgid and mod_cgid.
The order of detection looks as follows:
- LVEId
- LVEUser
- SuexecUserGroup
- suPHP_UserGroup
- RUidGid
- AssignUserID
Note
LVE doesn't work for mod_include #include due to its "filter" nature.
Example:
LoadModule hostinglimits_module modules/mod_hostinglimits.so
<IfModule mod_hostinglimits.c>
AllowedHandlers cgi-script php5-script php4-script
SecureLinks On
</IfModule>
Additional notes
mod_hostinglimits (since version 1.0-22) supports min-uid - cagefsctl --set-min-uid=600
.
Min UID is read on Apache start/restart and stored in the memory during apache runtime.
If the min UID has changed, you should restart Apache for mod_hostinglimits applying new min UID value. Full min UID is supported only with APR.
The following message should appear:
[notice] mod_hostinglimits: found apr extention version 3.
This means that the correct APR is installed with mod_hostinglimits.
mod_hostinglimist has variable for Apache CustomLog format string %{LVE_ID}y
.
How to use:
LogFormat
"%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i" req for lve "%{LVE_ID}y"
combined
shows in access_log the following info:
*.*.*.* - - [09/Apr/2015:07:17:06 -0400] "GET /1.php HTTP/1.1" 200 43435 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0" req for lve 500
*.*.*.* - - [09/Apr/2015:07:17:06 -0400] "GET /1.php?=PHPE9568F34-D428-11d2-A769-00AA001ACF42 HTTP/1.1" 200 2524 "************/1.php""Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0" req for lve 500
*.*.*.* - - [09/Apr/2015:07:17:06 -0400] "GET /1.php?=PHPE9568F35-D428-11d2-A769-00AA001ACF42 HTTP/1.1" 200 2146 "************/1.php""Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Firefox/24.0" req for lve 500
Installation
cPanel
Installed by default during EasyApache build. Requires lve-stats
& lve-utils
packages to be installed.
DirectAdmin
Can be built using custombuild:
yum install liblve-devel
cd /usr/local/directadmin/custombuild
./build update
./build set cloudlinux yes
./build apache
./build rewrite_confs
If you run suphp
, then run the following:
./build suphp
Plesk
yum install mod_hostinglimits
ISPmanager
yum install mod_hostinglimits
InterWorx
yum install mod_hostinglimits
H-Sphere
Included by default in H-Sphere 3.5+
Standard Apache from RPM
yum install mod_hostinglimits
Custom Apache installation
Compile from the source: https://repo.cloudlinux.com/cloudlinux/sources/mod_hostinglimits.tar.gz
wget https://repo.cloudlinux.com/cloudlinux/sources/mod_hostinglimits.tar.gz
yum install cmake
tar -zxvf mod_hostinglimits*.tar.gz
cd mod_hostinglimits*
cmake .
make
make install
- Apache Module Identifier:
hostinglimits_module
- Source Files:
mod_hostinglimits.c
- Compatibility: MPM prefork, worker, event, ITK
Directives
SecureLinks
Description | Makes sure that for any virtual hosts, only files owned by user specified via SuexecUserGroup or other ways as described above are served. For files owned by any other user apache will return Access Denied error. The directive will not affect VirtualHost without user id specified, or with uid < 100 |
Syntax | SecureLinks On |
Default | SecureLinks Off |
Context | server config |
Prevents apache from serving files not owned by user, stopping symlink attacks against php config files.
Example
SecureLinks On
SkipErrors
Description | Allow apache to continue if LVE is not available |
Syntax | SkipErrors On |
Default | SkipErrors On |
Context | server config |
Prevents Apache from exiting if LVE is not available.
Example
SkipErrors Off
AllowedHandlers
Description | List of handlers that should be placed into LVE, support regexp |
Syntax | AllowedHandlers cgi-script %^php% my-script |
Default | cgi-script %php% fcgid-script application/x-miva-compiled |
Context | server config |
This directive allows to list handlers which will be intercepted and placed into LVE.
Examples
Match requests handled by cgi-script handler:
AllowedHandlers cgi-script
Match all requests:
AllowedHandlers *
Match all requests that handled by handler that contains PHP:
AllowedHandlers %php%
Match all requests handled by handler that starts with PHP:
AllowedHandlers %^php%
The default modhostinglimits module configuration only handles cgi scripts and ignores static content like html files and images. With the default configuration, an Apache server denial of service situation can occur when there are many requests for large html files and images. But on the other hand, processing all static files is unprofitable, since when processing many small files, the load average will increase significantly due to the overhead of entering/exiting lve. Therefore, it is better to enable processing only for a subset of static files based on criteria such as file location or file name extension using Apache directives as Location, Directory and Files.
This functionality is available since version 1.0-40.
In the following example, the module hostinglimits will process files for a URLs starting with weightcontent, for files with an .avi extension, and for files from the video subdirectory.
<IfModule mod_hostinglimits.c>
SkipErrors Off
AllowedHandlers cgi-script %php% fcgid-script application/x-miva-compiled
<LocationMatch "^/weigthcontent/">
AllowedHandlers *
</LocationMatch>
<Files "*.avi">
AllowedHandlers *
</Files>
<DirectoryMatch "/home/user[0-5]/public_html/video/">
AllowedHandlers *
</DirectoryMatch>
</IfModule>
DenyHandlers
Description | List of handlers that should not be placed into LVE, support regexp |
Syntax | DenyHandlers text/html |
Default | none |
Context | server config |
This directive works together with AllowHandlers, to exclude some handlers from being allowed in LVE.
Example:
Match all requests, but text/*
AllowedHandlers *DenyHandlers %text/*%
LVEErrorCode
Description | Error code to display once entry is rejected due to maxEntryProcs |
Syntax | values from 500 to 510 |
Default | 508 |
Context | directory config |
Specifies ErrorCode to use on LVE error (like too many concurrent processes running).
The message that will be displayed by default is:
Resource Limit Is Reached.
The website is temporarily unable to serve your request as it exceeded resource limit.
Please try again later.
You can redefine error message using ErrorDocument
directive
Example:
LVEErrorCode 508ErrorDocument 508 508.html
LVEid
Description | Allows to setup separate LVE ID on per directory level. If not set, user ID of a corresponding user is used. |
Syntax | LVEId number |
Default | User Id is used |
Context | directory config |
Specifies LVE id for particular directory
Example:
<Directory "/home/user1/domain.com/forums">
LVEId 10001
</Directory>
LVEUser
Description | Allows to setup separate LVE ID on per directory level. |
Syntax | LVEUser username |
Default | none |
Context | directory config |
Specifies LVE ID for particular directory.
Example:
<Directory "/home/user1/domain.com/forums">
LVEUser user1
</Directory>
LVEUserGroupID
Description | Use group ID instead of user ID for LVE container number. |
Syntax | LVEUserGroupID On/Off |
Default | User Id is used |
Context | global config only |
- If the option enabled, group ID will be used instead of a user ID. Apache will display the following string in error logs:
mod_hostinglimits: use GroupID instead of UID
mod_hostinglimits: found apr extension version 2
mod_hostinglimits: apr_lve_environment_init_group check ok
- If a compatible apr library is not found, the following error message will be display in error logs.
mod_hostinglimits: apr_lve_* not found!!!
Example:
<Directory "/home/user1/domain.com/forums">
LVEUserGroupID On
</Directory>
LVERetryAfter
Description | Returns Retry-After header when LVE error 508 occurs. |
Syntax | LERetryAfter MINUTES |
Default | 240 minutes |
Context | directory config |
Specifies interval for Retry-After
header. The Retry-After
response-header field can be used to indicate how long the service is expected to be unavailable to the requesting client.
Example:
LVERetryAfter 180
LVESitesDebug
Description | Provides extended debug info for listed sites. |
Syntax | LVESitesDebug test.com test2.com |
Default | none |
Context | directory config |
Specifies virtual hosts to provide extra debugging information.
Example:
<Directory "/home/user1/domain.com/forums">
LVESitesDebug abc.com yx.cnet
</Directory>
LVEParseMode
Description | Determines the way LVE ID will be extraced. In Conf |
Syntax | LVEParseMode CONF PATH OWNER REDIS |
Default: | CONF |
Context: | directory config |
In
CONF
mode, standard way to extract LVE ID is used (SuexecUserGroup, LVEId, or similar directives).In
PATH
mode, username is extracted from the home directory path. The default way to match username is via the following regexp:/home/([^/]*)/
. Custom regexp can be specified in LVEPathRegexp.In
OWNER
mode, the owner of the file is used as an LVE ID.In
REDIS
mode, LVE ID is retrieved from Redis database.
Example:
LVEParseMode CONF
LVEPathRegexp
Description | Regexp used to extract username from the path. Used in conjuction with LVEParseMode PATH |
Syntax | LVEPathRegexp regexp |
Default | /home/([^/]*)/ |
Context | directory config |
Used to extract usersname via path.
Example:
LVEPathRegexp /home/([^/]*)/
LVELimitRecheckTimeout
Description | Timeout in milliseconds, a site will return EP without lve_enter for LA decreasing after this time |
Syntax | LVELimitRecheckTimeout number |
Default | 0 |
Context | httpd.conf, virtualhost |
Example:
LVELimitRecheckTimeout 1000
LVEUse429
Description | Use 429 error code as code returned on max entry limits ( on/off ). |
Syntax | LVEUse429 on |
Default | off |
Context | httpd.conf, virtualhost |
Example:
LVEUse429 on
Available for RPM based panels, EasyApache 4 and DirectAdmin.
cPanel/WHM JSON API
- Parameters
- Manage reseller limits/users/packages via cPanel/WHM JSON API - JSONHandler
- Using a WHM API token
CloudLinux OS offers JSON API for lvectl and cloudlinux-limits via WHM. You can access it using the following URL:
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=lvectl&handler=list
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=cloudlinux-limits&handler=get
The output will look as follows:
{"data":[{"ID":"default","CPU":"30","NCPU":"1","PMEM":"1024M","VMEM":"1024M","EP":"28","NPROC":"0","IO":"2048"}]}
Parameters
cgiaction | always jsonhandler |
command | lvectl or cloudlinux-limits (default lvectl ) |
handler | should match lvectl or cloudlinux-limits command |
For commands like set
, destroy
& delete
, where you need to specify LVE (user) ID, like lveid=500
(matches user ID 500).
Example:
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=lvectl&handler=set&lveid=500&speed=30%&io=2048
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=lvectl&handler=set&lveid=500&speed=300Mhz&io=2048
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=lvectl&handler=set&lveid=500&speed=3Ghz&io=2048
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=cloudlinux-limits&handler=set&lveid=500&inodes=9090,8989
Note
Speed limit can be specified in several units of measure - %, MHz, GHz . The figures will be different according to the unit of measure.
Output:
{"status":"OK"}
To do set default
, use lveid=0
, like:
https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=set&lveid=0&speed=30%&io=2048
For commands like apply all
, destroy all
, use:
handler=apply-all
handler=destroy-all
You can use the following commands that allow to specify user name instead of user ID:
set-user | Set parameters for a LVE and/or create a LVE using username instead of ID. |
list-user | List loaded LVEs, display username instead of user ID. |
delete-user | Delete LVE and set configuration for that user to defaults. |
If the limits for users are set with cPanel LVE Extension, then turnkey billing solutions can be applied (e.g. WHMCS).
Manage reseller limits/users/packages via cPanel/WHM JSON API (JSONHandler)
Action | lvectl command | JSONHandler |
enable reseller limits | lvectl set-reseller res1 --speed=35% | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=set-reseller&lveid=res1&speed=30%&io=2048 |
disable reseller limits | lvectl remove-reseller res1 | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=remove-reseller&lveid=res1 |
set default limits for reseller | lvectl set-reseller-default res1 --speed=91% | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=set-reseller-default&lveid=res1&speed=30% |
set limits for package, created by reseller | lvectl package-set res1_pack1 --reseller res1 --speed=88% | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=package-set&lveid=res1_pack1&reseller=res1&speed=30% |
set limits for user, created by reseller | lvectl set-user r1user1 --reseller res1 --speed=77% | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=set-user&lveid=r1user1&reseller=res1&speed=30% |
set unlimited for user, created by reseller | lvectl set-user r1user1 --reseller res1 --unlimited | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=set-user&lveid=r1user1&reseller=res1&unlimited |
set inodes limit | cloudlinux-limits set --username=r1user1 --inodes=9090,8989 | https://IP:2087/cpsess_YOURTOKEN/cgi/CloudLinux.cgi?cgiaction=jsonhandler&command=cloudlinux-limits&handler=set&username=r1user1&inodes=9090,8989 |
Using a WHM API token
You can use a WHM API token with curl as follows:
curl -X POST -k -s -H "Authorization: whm root:WHM_TOKEN" "https://SERVER_IP:2087/cgi/CloudLinux.cgi?cgiaction=jsonhandler&handler=LVE_METHOD&PARAMETERS
Where:
WHM_TOKEN
– a generated WHM API token (see: Creating an API token)LVE_METHOD
– lvectl method (for example:list
. See also: lvectl)PARAMETERS
– all other parametrs and options for a method according to the documentation
mod_proctitle
mod_proctitle is a module for gathering URL information per request. It is available only for Apache 2.4 now.
For installation:
cPanel EasyApache 3 and non cPanel ( CloudLinux 7 only for non cPanel ):
yum install mod_proctitle --enablerepo=cloudlinux-updates-testing
service httpd restart
cPanel EasyApache 4:
yum install ea-apache24-mod_proctitle
service httpd restart
cd /usr/local/directadmin/custombuild
./build update
./build mod_procticle
How to read mod_proctitle information
How to read information gathered by the module
For reading information saved by module use the following script (the script is not in the package):
#!/bin/bash
httpd=httpd
for pid in `/usr/bin/pgrep $httpd`; do
for tid in `ls /proc/$pid/task`; do
found=no
for shm in `ls /dev/shm/apache_title_shm_${pid}_${tid}_* 2>/dev/null`; do
found=yes
title=`/usr/bin/tr -d '\0' < $shm`
thread_id=`/bin/basename "${shm}" | sed "s/apache_title_shm_${pid}_${tid}_//"`
echo "$pid.$tid - $thread_id - $title"
break
done
if [ "$found" = "no" ]; then
echo "$pid.$tid not found"
fi
done
done
# sh proctitles_info.sh
571258.571258 NOT FOUND
571300.571300 NOT FOUND
571303.571303 - 000000000000000 - 1466513333.6 test.cloudlinux.com GET /1.php HTTP/1.1
571304.571304 - 000000000000000 - 1466513335.3 test.cloudlinux.com GET /1.php HTTP/1.1
571305.571305 - 000000000000000 - httpd
571306.571306 - 000000000000000 - httpd
571307.571307 - 000000000000000 - httpd
571372.571372 - 000000000000000 - httpd
571374.571374 - 000000000000000 - httpd
Item info:
[pid].[tid] - [posix thread id] - [request info]
Request information can contain:
NOT FOUND - means that process of Apache doesn't handle requests.
httpd - request is active and waiting for new connection.
[seconds].[tenths of second] [host] [METHOD] [URL] [PROTOCOL]
Tuning parameters
Module parameters for tuning
WatchHandlers | List of handlers for monitoring (httpd.conf, virtualhost). |
ProctitleUseFilter On/Off | Use old method of cleaning information or new via filter (for prefork better to use Off ) |
alt-suexec
What is alt-suexec package needed for?
If you use standard httpd from our repository, but your users' sites do not match standard Apache location of /var/www
, then you should use alt-suexec. alt-suexec package brings suEXEC binaries pre-compiled for specific locations, like /home .
How to switch suEXEC with alt-suexec
Based on httpd 2.2.16 basic for Cloudlinux OS 6, httpd 2.4.6 basic for CloudLinux OS 7 and httpd 2.4.37 basic for CloudLinux OS 8, the package brings to a server a set of suEXECs with different DOCUMENT ROOTs and MIN_UID/MIN_GID parameters. The first set of suEXECs is listed by such modes:
switch_suexec -h
............
USE_BIZ - DOCUMENT ROOT /biz/ MIN_UID 500 MIN_GID 100 CALLER apache
USE_HOSTING - DOCUMENT ROOT /hosting/ MIN_UID 500 MIN_GID 100 CALLER apache
USE_HSPHERE - DOCUMENT ROOT /hsphere/local MIN_UID 100 MIN_GID 100 CALLER httpd
USE_HOME - DOCUMENT ROOT /home/ MIN_UID 500 MIN_GID 100 CALLER apache
USE_WWW - DOCUMENT ROOT /var/www/ MIN_UID 500 MIN_GID 100 CALLER apache
USE_FSROOT - DOCUMENT ROOT / MIN_UID 500 MIN_GID 100 CALLER apache
USE_STORAGE - DOCUMENT ROOT /storage/content/ MIN_UID 500 MIN_GID 100 CALLER apache
USE_DATAS - DOCUMENT ROOT /datas/ MIN_UID 500 MIN_GID 100 CALLER apache
-l | list of available suexec |
-u | update suexec according to /etc/sysconfig/alt-suexec |
-s | set new suexec and install it |
-p | set new suexec path and install it |
-o | set new suexec owners and install it |
-r | restore native apache suexec |
There are two ways to set up new suEXEC binary:
- via config file /etc/sysconfig/alt-suexec
- via utility switch_suexec
Here are the examples of how to set up suEXEC with DOC_ROOT = "/home":
1.
- add string "USE_HOME" to /etc/sysconfig/alt-suexec
- run the command switch_suexec -u
2.
- switch_suexec -sUSE_HOME
Result of both methods:
cat /etc/sysconfig/alt-suexec
............
USE_HOME
Here is standard suEXEC for CloudLinux OS 6 clean server:
/usr/sbin/suexec -V
............
-D AP_DOC_ROOT="/var/www"
-D AP_GID_MIN=100
-D AP_HTTPD_USER="apache"
-D AP_LOG_EXEC="/var/log/httpd/suexec.log"
-D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
-D AP_UID_MIN=500
-D AP_USERDIR_SUFFIX="public_html"
-D AP_SAFE_DIRECTORY="/usr/local/safe-bin"
Here is output of new suEXEC after USE_HOME installtion:
/usr/sbin/suexec -V
............
-D AP_DOC_ROOT="/home/"
-D AP_GID_MIN=100
-D AP_HTTPD_USER="apache"
-D AP_LOG_EXEC="/var/log/httpd/suexec.log"
-D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin"
-D AP_UID_MIN=500
-D AP_USERDIR_SUFFIX="public_html"
-D AP_SAFE_DIRECTORY="/usr/local/safe-bin"
Description of other switch_suexec parameters:
-p | if suexec binary file will be placed not in standard way /usr/sbin - specify this new path with p-option |
-o | if suexec binary file not owned by root:apache - specify new owner with o-option |
For most cases -p and -o options for standard Apache are useless.
Correct suEXEC will be restored even after httpd update or reinstall.
List of pre-built suEXEC binary files stored without suid bit and not executable.
How to install alt-suexec?
For installation run the command:
yum install alt-suexec
New suexec with custom parameters
If you need suEXEC with custom parameters absent in current set of alt-suexec, please submit a ticket on https://cloudlinux.zendesk.com and we will add new suEXEC with needed parameters.
cPanel Nginx and application selectors
Recently, cPanel added support for the Nginx web server and for Python and Node.js applications.
We have checked the compatibility of ea-nginx and cPanel application Selectors with CloudLinux OS LVE and CageFS. All tests passed successfully and all processes started by ea-nginx and cPanel selectors are launched inside LVE and CageFS.
Don’t forget, you can use Ruby/Python/Node.js Selectors from CloudLinux OS. Here you can find a large number of supported versions for Ruby/Python/Node.js applications.
Note
Nginx support is currently experimental.
How to use Certbot with alt-python36
To run Certbot with alt-python36
, follow the next steps:
- Add a path to the
alt-python36
in the environment variablePATH
as the first element:/opt/alt/python36/bin/
. - Run Certbot with the
--no-bootstrap
parameter.
Example:
The old command to run Certbot on CentOS 6/Cloudlinux OS 6:
certbot-auto --nginx
The new command to run Certbot on CentOS 6/CloudLinux OS 6:
PATH="/opt/alt/python36/bin/:$PATH" certbot-auto --no-bootstrap --nginx
Apache suexec module
General information and requirements
This module is used by the Apache HTTP Server to switch to another user before executing CGI programs. The suEXEC feature provides users of the Apache HTTP Server with the ability to run CGI and SSI programs under user IDs different from the user ID of the calling web server (apache/nobody). Normally, when a CGI or SSI program executes, it runs as the same user who is running the web server.
If we are talking about shared hosting where different accounts are launched on the same server, the installation of this module is necessary to ensure security.
How does it work with CloudLinux OS?
The DirectAdmin and CloudLinux OS (for httpd, httpd24-httpd and cPanel EasyApache 4) both provide a patched version of suexec. For other distributions you can use patches available here: https://repo.cloudlinux.com/cloudlinux/sources/da/cl-apache-patches.tar.gz
- Besides the ability to run CGI programs under user IDs, suexec with CloudLinux OS patch adds the ability to run that script under CageFS.
NOTE
Therefore, this module is necessary for the proper work of PHP Selector.
- This module is also necessary for the proper work of mod_hostinglimits. The
SuexecUserGroup
directive indicates formod_hostinglimits
in which LVE the user process should be put in.
Configuration
SuexecUserGroup Directive
Syntax: SuexecUserGroup User Group
Context: httpd.conf
, virtualhost
Description: The SuexecUserGroup directive allows you to specify a user and a group for CGI programs to run as. Startup will fail if this directive is specified but the suEXEC feature is disabled.
Note
Control panels such as cPanel, Plesk, and DirectAdmin add this directive to the Apache configuration automatically when creating a domain. If you use the server without a control panel, make sure this directive is added for each virtual host.
Installation
The mod_suexec
installation process varies depending on the control panel and Apache.
- Installing on cPanel servers with EasyApache 4
- Installing on Plesk servers
- Installing on DirectAdmin servers
- Installing on servers with no control panel
Installing on cPanel servers with EasyApache 4
Via command line
- Install
mod_suexec
through YUM package manager as follows:
yum install ea-apache24-mod_suexec
NOTE
ea-apache24-mod_suexec
conflicts with the mod_ruid2
therefore, before installing the module, remove ea-apache24-mod_ruid2
as follows: $ yum remove ea-apache24-mod_ruid2
- Now, when the module is installed, restart Apache:
service httpd restart
Note
If you use CageFS + PHP Selector, you should run the cagefsctl --force-update
command.
Via administrator interface
- Open EasyApache4 page.
- Click Customize for Currently installed Packages.
- Click Apache Modules. Find
mod_suexec
and click Yes to install it.
- Select Review and Provision.
Wait while Provision will be finished.
Note
If you use CageFS + PHP Selector, you should run the
cagefsctl --force-update
command.
Installing on Plesk servers
This module is integrated into Apache for Plesk control panel by default.
Installing on DirectAdmin servers
This module is integrated into Apache for DirectAdmin control panel by default.
Installing on servers with no control panel
This module is integrated into httpd Apache rpm provided by Cloudlinux OS by default.
If you are using an alternative Apache - httpd24, nothing has to be done as this module is also integrated into httpd24-httpd Apache rpm provided by Cloudlinux by default.