sidebar hamburger menu

Generic panels and no-panel installation and integration

Introduction

Imunify360 can be installed directly on the server, independent of any panel, regardless of the administrative interface. It is also called stand-alone, non-panel, generic panel integration.

Limitations

Requirements

Supported Operating Systems

  • The same list as here.

Web Servers

  • Apache >= 2.4.30
  • LiteSpeed
  • Nginx

There are four main steps in general required for having Imunify360 Stand-alone running on your server:

  1. Install and configure the prerequisites such as ModSecurity, PHP with JSON support, and other common WEB server packages.
  2. Download and edit integration.conf file to configure Imunify360 required integrations BEFORE running the installation script.
  3. Install Imunify360 using the deploy script
  4. Check the installed modules work and change the Imunify360 settings to reflect your needs.

CageFS Warning

If Imunify360 runs in CageFS, you'll need to configure it accordingly. It is required to make sure Imunify Web-UI PHP code can be executed under a non-root user and grant access to /var/run/defence360agent/non_root_simple_rpc.sock.

To allow non-root user in CageFS access to the socket, this workaround should be applied:

# Ensure the existence of the related cagefs directory for the user
# and write necessary configuration for setting up virtual mp.
# For more information, see docs:
# https://docs.cloudlinux.com/shared/cloudlinux_os_components/#per-user-virtual-mount-points
#
export prefix=$(id -u {{ imunify_ui_user }} | tail -c 3)
export cagefs_namespace_dir=/var/cagefs/${prefix}/{{ imunify_ui_user }}/
mkdir -p ${cagefs_namespace_dir}
#
# The lines starting with @ mean they are subdirectories.
# If we do not wanna mask everything else in /var/run,
# we should not omit that line but make it an empty subdir under defence360agent, like shown
#
cat << EOF > ${cagefs_namespace_dir}/virt.mp
/var/run/defence360agent
@
EOF
cagefsctl --remount-all

1. Install and configure the prerequisites

Imunify360 Stand-alone version requires the following components installed or enabled at the server:

  • ModSecurity 2.9.x for Apache or ModSecurity 3.0.x for Nginx
  • Apache module mod_remoteip or nginx module ngx_http_realip_module
  • PHP with json extension loaded and proc_open function enabled (remove it from the disable_functions list in php.ini)

Warning

We recommend using the stable versions of ModSecurity3 (i.e. 3.0.4), because developing versions (i.e. master) can have stability issues (see https://github.com/SpiderLabs/ModSecurity/issues/2381 for example).

2. Download and edit integration.conf file to set required integrations

The Imunify360 Stand-alone version requires the following integrations before installation:

  • 2.1 Specifying panel information
  • 2.2 Integration with WEB server for serving UI
  • 2.3 Interaction with ModSecurity
  • 2.4 Integration with Authentication Service
  • 2.5 Integration with Malware Scanner

All integrations set in the integration config file like /etc/sysconfig/imunify360/integration.conf. You can find more details on the config file here, get a template or check the Knoledgebase article.

2.1 Specifying panel information

To specify information about your hosting panel in Imunify360/ImunifyAV, use the panel_info option in the [integration_scripts] section of integration.conf file.

This is a mandatory field and must be specified prior to the start of the installation.

[integration_scripts]
panel_info = /etc/sysconfig/imunify360/get-panel-info.sh

The option should contain a full path to the executable that prints JSON data in the following format:

{
    "data": {
        "name": "MyHostingPanel",
        "version": "1.23.4"
    },
    "metadata": {
        "result": "ok"
    }
}

The script can echo or print this information in JSON format, or you could configure the file in order to receive the actual information about the hosting panel in use. In case you don’t have a hosting panel at all, use the following stub file: get-panel-info.sh

2.2 Integration with web server for serving UI

Imunify360 UI is implemented as a single-page application (SPA) and requires a web server to serve it. It’s required to specify a path to the web server directory, where the Imunify360 UI SPA application will be installed and served.

Example:

[paths]
ui_path = /var/www/vhosts/imunify360/imunify360.hosting.example.com/html/im360

Ensure that the domain you are going to use for the Imunify360 web-based UI refers to this path and that there are no other scripts or files under ui_path, to avoid overwriting the files Imunify360 installation will abort.

2.3 Web engine and Interaction with ModSecurity

It is required to set the web server graceful restart script ang paths in the integration.conf

  • graceful_restart_script – a script that restarts the web server to be called after any changes in web server config or ModSecurity rules
  • config_test_script – a script that checks the web server's config to be called after any changes in the web server config or ModSecurity rules (optional)
  • modsec_audit_log – a path to ModSecurity audit log file
  • modsec_audit_logdir – a path to ModSecurity audit log directory (only required when the SecAuditLogType set to the Concurrent)

Example:

[web_server]
server_type = apache
graceful_restart_script = /usr/sbin/apachectl restart
config_test_script = /usr/sbin/apachectl -t
modsec_audit_log = /var/log/httpd/modsec_audit.log
modsec_audit_logdir = /var/log/modsec_audit

Apache and LiteSpeed

Configure ModSecurity configuration directives (so that it can block):

SecAuditEngine RelevantOnly
SecConnEngine Off
SecRuleEngine On

Create the empty file /etc/sysconfig/imunify360/generic/modsec.conf and include it into the web server config as IncludeOptional. To do this you need to find your web server config file, like /etc/httpd/conf/httpd.conf and add a line to it:

IncludeOptional /etc/sysconfig/imunify360/generic/modsec.conf

The file would be replaced with the actual config during the first Imunify360 installation or you can fill it via calling the Imunify360 ModSec ruleset installation imunify360-agent install-vendors.

Nginx

Note

ModSecurity has different syntax comparing to Nginx configuration, thus ModSecurity directives can not be directly included to the Nginx config files.

Create a separate file (i.e. /etc/nginx/modsec.conf) and set the following ModSecurity directives in it:

SecAuditEngine RelevantOnly
SecConnEngine Off
SecRuleEngine On
SecAuditLogFormat JSON
# should match modsec_audit_log option in integration.conf (see below)
SecAuditLog /var/log/nginx/modsec_audit_log

Warning

ModSecurity on Nginx does not properly re-opens audit log on SIGHUP/SIGUSR1, which can cause logrotate to break integration with Imunify360. See https://github.com/SpiderLabs/ModSecurity-nginx/issues/121 for details.

Create an empty file /etc/sysconfig/imunify360/generic/modsec.conf. The file would be replaced with the actual config during the first Imunify360 installation or you can fill it via calling the Imunify360 ModSec ruleset installation imunify360-agent install-vendors.

Then enable ModSecurity and include both files into Nginx configuration using the modsecurity_rules_file directive:

modsecurity on;
modsecurity_rules_file /etc/nginx/modsec.conf;
modsecurity_rules_file /etc/sysconfig/imunify360/generic/modsec.conf;

2.4 Integration with authentication service

Imunify360 Stand-alone version can use PAM service to authenticate users for the Imunify360 UI application.

You can specify which PAM service Imunify360 should use with the service_name option:

[pam]
service_name = system-auth

You can get a token which can be used for authentication using the login command. The administrators have full access to Imunify360 UI and its settings.

By default, root is considered to be the only admin user.

2.5 Integration with Malware Scanner

To scan files for changes (to detect malware) using inotify, configure which directories to watch and which to ignore in the integration.conf file:

  • configure [malware].basedir – a root directory to watch (recursively)
  • configure [malware].pattern_to_watch – only directories that match this (Python) regex in the basedir are actually going to be watched

Example:

[malware]
basedir = /home
pattern_to_watch = ^/home/.+?/(public_html|public_ftp|private_html)(/.*)?$

3. Install Imunify360

3.1. Get your license key: Visit https://www.imunify360.com/. You can purchase it or get a trial key from a received email. 3.2. Log in with root privileges: Access the server where Imunify360 should be installed with root privileges. 3.3. Run the installation commands: Navigate to your home directory and execute the following commands:

wget https://repo.imunify360.cloudlinux.com/defence360/i360deploy.sh -O i360deploy.sh
bash i360deploy.sh --key YOUR_KEY

Where YOUR_KEY is your license key. Replace YOUR_KEY with the actual key - trial or purchased one. The installation instructions are the same as for cPanel/Plesk/DirectAdmin version and can be found in the Imunify360 documentation.

After the successful installation, you can reach the Imunify360 UI at the URL specified by the ui_path parameter of the configuration file.

4. Set up modules and integrations and change other Imunify360 settings to reflect your needs

4.1 Define list of administrators for Imunify360

The administrators have full access to Imunify360 UI and its settings. To grant non-root users full access add more administrators by listing them in the them in the /etc/sysconfig/imunify360/auth.admin file or specify the integration scripts admin scetion.

Admin users will be merged from three sources:

  • /etc/sysconfig/imunify360/auth.admin list
  • scripts defined in the /etc/sysconfig/imunify360/integration.conf
  • /opt/cpvendor/etc/integration.ini that return user lists.
JSON data sample admin script should return
[integration_scripts]
admins = /etc/sysconfig/imunify360/get-admins-script.sh

It should point to an executable file that generates a JSON file similar to the following:

{
  "data": [
    {
      "name": "admin1",
      "unix_user": "admin",
      "locale_code": "EN_us",
      "email": "admin1@domain.zone",
      "is_main": true
    },
	{
      "name": "admin2",
      "unix_user": "admin",
      "locale_code": "Ru_ru",
      "email": "admin2@domain.zone",
      "is_main": false
    },
  ],
  "metadata": {
    "result": "ok"
  }
}

4.2 FTP uploads scan

To scan files uploaded via FTP, configure PureFTPd. Write in the pure-ftp.conf:

CallUploadScript             yes

4.3 Per-domain rules constrol

To enable domain-specific ModSecurity configuration, specify the modsec_domain_config_script in the integration.conf.

[integration_scripts]
modsec_domain_config_script = /path/to/inject/domain/specific/config/script.sh

It should point to an executable file that accepts as an input a list of domain-specific web server settings and injects them into the server config. The standard input (stdin) is given in the JSON Lines format similar to the following:

{"user": "username", "domain": "example.com", "content": "modsec config text"}
{"user": "another", "domain": "another.example.com", "content": "..."}

Each line contains config for a single domain e.g., it may contain rule tags excluded for the domain. The script should also restart the web server to apply the configuration. This should be done so that the script could implement the check that web server comes up after config change, and reset configuration if it doesn't.

If configuration change failed, the script should return 1, and in the standard error stream (stderr) it should return the reason for failure. On success, the script should return 0. In a single run of the script, we might update a single domain/user, as well as multiple users (all users) on the system.

4.4 Integration with WebShield

WebShield consists of four services:

  • WebShield itself
  • Shared memory daemon makes it easier to deal with certain aspects of Nginx configuration without reloading
  • SSL-caching daemon watches changes to host SSL certificate sets (for known hosting panels only: cPanel, Plesk, DirectAdmin) and updates the WebShield SSL cache when a certificate is added, updated or removed
  • Sentrylogs daemon watches WebShield log files to detect errors

The configuration of WebShield is done by an agent, and direct editing of WebShield configuration files is generally not recommended. This is mainly because after the next reconfiguration all custom changes would be lost. However, a host administrator is allowed to set a certificate as the default one for WebShield to return.

How to enable WebShield in the Imunify360 config file and start the service

When Imunify360 stand-alone is installed, WebShield is disabled by default.

You can enable it only via CLI. To do so, run the following commands:

  1.  imunify360-agent config update '{"WEBSHIELD": {"enable": true, "known_proxies_support": true}}'
    
  2.  systemctl enable imunify360-webshield
    
  3.  systemctl restart imunify360-webshield
    

Set default SSL certificate explicitly

  1. Place a certificate and a key into the /etc/imunify360-webshield/ssl_certs folder
  2. If required, in the /etc/imunify360-webshield/ssl.conf file, change the following directives according to your changes:
ssl_certificate             ssl_certs/dummy.pem;

ssl_certificate_key         ssl_certs/dummy.pem;

If you want to provide intermediate certificates, they are to be appended to the certificate file.

These settings require WebShield to be restarted/reloaded.

Manage WebShield SSL cache manually

To manually manage the certificate cache, use the /usr/sbin/im360-ssl-cache utility.

To add certificates to the cache, a user would run the command:

im360-ssl-cache --add /path/to/certs.json

The --add parameter accepts exactly one value. If the parameter value is not -, it is taken as a path to a file in JSON format with a list of certificates and private keys to be added. Otherwise, if the parameter value is -, data is expected to be sent in JSON format to STDIN as in the following example:

cat certs.json | im360-ssl-cache --add -
Format of JSON file:
[
  {
      "domain": "john.example.com",
      "key": "-----BEGIN PRIVATE KEY-----\nM...O\n-----END PRIVATE KEY-----\n",
      "certificate": "-----BEGIN CERTIFICATE-----\nMI...Y=\n-----END CERTIFICATE-----\n",
      "chain": "-----BEGIN CERTIFICATE-----\nM...I=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nM...U=\n-----END CERTIFICATE-----\n"
    },
    {
      "domain": "bob.example.com",
      "key": "...",
      "certificate": "...",
      "chain": "..."
    }
]

Note

As JSON text is not allowed to have line breaks, all newline symbols must be escaped as in the example above.

To remove certificate(s) from the cache, a user is expected to run the command:

im360-ssl-cache --remove example.org example.com …

The --remove parameter expects one or more space-separated domain names, for which certificates are to be removed from the cache.

When no parameters are passed, the im360-ssl-cache simply lists all domain names of certificates in the cache.

Note

Passing certificates data in JSON format is done to put data flow in good order, to avoid excessive checks of data. No certificate checks are made.

Non-SNI requests

When a request without Server Name Indication (SNI) comes, WebShield has to guess what certificate from the cache to serve.

To allow WebShield to handle non-SNI requests properly, include an ip field in the JSON that you pass to the im360-ssl-cache.

[
    {
        "domain": "...",
        "key": "...",
        "certificate": "...",
        "chain": "...",
        "ip": "..."  // NEW, optional, NOT UNIQUE
    },..
]

WebShield will use this data to decide which certificate to serve if a request without Server Name Indication (SNI) arrives. If there are several domains with the specified IPs, WebShield will use the first one alphabetically.

How to test SSL configuration

Administrators should see a warning in Settings in UI if no certificates are added: WebShield SSL-Cache is not configured. Although, even if a certificate is added, it doesn’t guarantee that the website is working correctly. The certificate may be outdated, invalid, or not applicable to that domain name.

The worst scenario when SSL certificate is not cached or recognised by the WebShield is that the SSL certificate of the Anti-Bot Challenge page redirect will not match the initial site the user was visiting. The WebShield will serve it's default that not likely to match with the domain name, or an outdated certificate and this may not be trusted. Thus SSL certificate waning will appear.

To make sure WebShield can serve the Anti-Bot Challenge page smoothly the relevant domain name (certificates cache) should be in the output of thec cache tool, e.g.:

im360-ssl-cache
bob.example.com
john.example.com
If the domain name is presented, its certificate content with it's key should be written in cache, WebShield's pick up algorithm will find this match to serve with domain's Anti-Bot Challenge page.

To attest this mechanisms, it is required:

  1. While using non-whitelisted IP (ideally an another machine that is not used to login), get the Graylist verdict.
  2. Visit the site and validate that no SSL errors occurred while Anti-Bot Challenge is shown.

The first step can be achieved in various ways, the one that is also checks the ModSecurity layer is to send specific test tags, as per link describes. The approach is to send specific tags towards you site, trigger the test rule and get IP greylisted:

for i in {1..5} ; do curl -ks https://example.com/?i360test=88ff0adf94a190b9d1311c8b50fe2891c85af732 > /dev/null; echo $i; done

As well as without testing the ModSec layer, it is possible to add IP to the manual Greylist as per:

imunify360-agent graylist ip add 1.1.1.3 --comment "Greylisting my test IP" --expiration $(($(date "+%s")+3600))

Subsequently, the curl results should return WebShield have no errors:

curl -iv --ssl-reqd https://example.com

Required web server configuration to correctly detect client IP addresses from headers

To ensure WebShield and Graylist are working correctly (e.g. a correct IP is passed to ModSecurity), the server must recognize WebShield as an internal proxy. For example, for Apache, mod_remoteip must be installed and configured like this:

<IfModule remoteip_module>
    RemoteIPInternalProxy 127.0.0.1
    RemoteIPInternalProxy ::1
    RemoteIPHeader X-Forwarded-For
</IfModule>

For Nginx, the ngx_http_realip_module module should be configured in the following way:

real_ip_header X-Forwarded-For;
set_real_ip_from 127.0.0.1;
set_real_ip_from ::1;

WebShield passes the real client IP in the X-Forwarded-For header.

Note

In the Apache LogFormat configuration strings for correct representation of a remote host IP address it is required using:

%a	Client IP address of the request

instead of

%h	Remote hostname

You can find more details at http://httpd.apache.org/docs/current/mod/mod_log_config.html.

Cloudflare: Preserving the original visitor IP addresses

For cases when server logs indicate IP addresses that differ from actual ones when the domain is hosted within the CloudFlare network.

Suitable for all supported control panels and OS working on Apache/Nginx.

When simulated IPv4 is configured to "Overwrite Headers" mode in Cloudflare settings, Cloudflare replaces the existing Cf-Connecting-IP and X-Forwarded-For headers with a pseudo IPv4 address. At the same time, it retains the real IPv6 address by placing it in the CF-Connecting-IPv6 header.

In a nutshell, when a website's traffic flows through the CloudFlare network, CloudFlare acts as a reverse proxy. This setup optimises page load times by efficiently routing packets and caching static resources such as images, JavaScript, and CSS. Consequently, when the origin server responds to requests and logs them, it records a CloudFlare IP address.

CloudFlare provides the original IP in an appended HTTP header named CF-Connecting-IP for applications that rely on the original visitor's IP address.

To log the original visitor IP address at the origin server level, the following instructions should be followed:

Apache

  1. We need to ensure that Apache has a mod_remoteip module enabled.
[root@server ~]# apachectl -t -D DUMP_MODULES |grep 'rem'
remoteip_module (shared)
  1. The combined LogFormat should be changed as follows:
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
  1. At this point, defining the trust between CloudFlare and the Origin Server is crucial:
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 192.0.2.1 (example IP address)
RemoteIPTrustedProxy 192.0.2.2 (example IP address)

The current IPs are:

173.245.48.0/20
103.21.244.0/22
103.22.200.0/22
103.31.4.0/22
141.101.64.0/18
108.162.192.0/18
190.93.240.0/20
188.114.96.0/20
197.234.240.0/22
198.41.128.0/17
162.158.0.0/15
104.16.0.0/13
104.24.0.0/14
172.64.0.0/13
131.0.72.0/22

2400:cb00::/32
2606:4700::/32
2803:f800::/32
2405:b500::/32
2405:8100::/32
2a06:98c0::/29
2c0f:f248::/32

The updated list is residing here.

Nginx

For Nginx , we use its respective module called ngx_http_realip_module. You can check if that is enabled in the following way:

[root@server ~]# nginx -V
nginx version: nginx/1.26.1
built with OpenSSL 1.1.1k FIPS 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/share --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --modules-path=/usr/share/nginx/modules --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --user=nginx --group=nginx --with-file-aio --with-compat --with-ld-opt=-L/var/jenkins/workspace/PLESK/plesk-aws-bootstrap/buck-out/gen/unix/plesk/packages/brotli/brotli.files/usr/lib64 --with-http_ssl_module --with-http_realip_module --with-http_sub_module --with-http_dav_module --with-http_gzip_static_module --with-http_stub_status_module --with-http_v2_module --with-http_v3_module --add-dynamic-module=mod_brotli --add-dynamic-module=mod_passenger/src/nginx_module --add-dynamic-module=mod_pagespeed --add-dynamic-module=mod_security --add-dynamic-module=mod_geoip2

If we get that confirmation, the steps of declaring the trust are mentioned here.

The IPs should be set here:

set_real_ip_from 192.0.2.1 (example IP address)
real_ip_header CF-Connecting-IP;

Use a specific list of users in Imunify360

By default, Imunify360 will use Linux system users, limited by uid_min and uid_max from the /etc/login.defs.

Data description

KeyNullableDescription
idFalseID of the UNIX account in the system.
usernameFalseThe name of the UNIX account in the system.
ownerTrueThe name of the account owner. The owner can be an administrator (in this case he should be included in the admins() output) or a reseller (in this case he should be included in the resellers() output).
locale_codeTrueThe locale selected by a user.
emailTrueEmail of the account user. If there is no email, it should return null.
domainTrueThe main domain of a user.
packageTrueInformation about the package to which a user belongs to. If the user doesn’t belong to any package, it should return null.
package.nameFalseThe name of the package to which a user belongs to.
package.ownerTrueThe owner of the package to which a user belongs to (reseller or administrator).
[integration_sctipts]
domains = /path/to/get-domains-script.sh

It should point to an executable file that generates a JSON file similar to the following

{
  "data": {
    "example.com": {
      "document_root": "/home/username/public_html/",
      "is_main": true,
      "owner": "username"
    },
    "subdomain.example.com": {
      "document_root": "/home/username/public_html/subdomain/",
      "is_main": false,
      "owner": "username"
    }
  },
  "metadata": {
    "result": "ok"
  }
}

web_server_config_path should point to a path that is added as IncludeOptional in this domain's virtual host e.g., /path/to/example.com/specific/config/to/include path should be added for the example.com domain.