Control panel 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

Operating system

  • CentOS 6/7/8
  • RHEL 6/7
  • CloudLinux OS
  • Ubuntu 16.04/18.04/20.04/22
  • Debian 9/10
  • Rocky Linux 8

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 like web servers modules or so
  2. Configure Imunify360 integrations like authentication or mod_security configuration
  3. Install Imunify360
  4. Change default Imunify360 settings to reflect your needs

Warning

Imunify Web-UI PHP code has to be executed under a non-root user which has access to /var/run/defence360agent/non_root_simple_rpc.sock. If it runs in CageFS, you'll need to configure it accordingly.

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

# create directory for moun-point
mkdir /imunify-ui-shared
# add symlink for user which belong to UI backend `imunify-web` in this example)
ln -s /var/run/defence360agent /imunify-ui-shared/imunify-web
# add symlink to cagefs skeleton
rm -f /usr/share/cagefs-skeleton/var/run/defence360agent
ln -s /imunify-ui-shared/imunify-web /usr/share/cagefs-skeleton/var/run/defence360agent
# add mount point to cagefs
echo "%/imunify-ui-shared" >> /etc/cagefs/cagefs.mp
# remount all
cagefsctl --remount-all

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).

Configure Imunify360 integrations

Imunify360 Stand-alone version require the following integrations before installation:

  • Integration with web server for serving UI
  • Interaction with ModSecurity
  • Integration with WebShield
  • Integration with Malware Scanner
  • Integration with authentication service
  • Define administrators for Imunify360

All integrations set in the integration config file like /etc/sysconfig/imunify360/integration.conf. You can find more details on config file here.

Integration with web server

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, as they might be overridden by Imunify360 installation.

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. 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;

Imunify360 integration configuration

Set the path and graceful restart script in the integration.conf

  • [web_server].graceful_restart_script – a script that restarts the web server to be called after any changes in web server config or ModSecurity rules
  • [web_server].modsec_audit_log – a path to ModSecurity audit log file
  • [web_server].modsec_audit_logdir – a path to ModSecurity audit log directory (required when the SecAuditLogType set to the Concurrent)

Example

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

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.

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.

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.

Integration with Malware Scanner

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

CallUploadScript             yes

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)(/.*)?$

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.

Define administrators for Imunify360

The administrators have full access to Imunify360 UI and its settings.

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

To add more administrators, list them in the /etc/sysconfig/imunify360/auth.admin file or specify the admins option in the /etc/sysconfig/imunify360/integration.conf

Admin users will be merged from three sources: /etc/sysconfig/imunify360/auth.admin list and scripts defined in the /etc/sysconfig/imunify360/integration.conf or /opt/cpvendor/etc/integration.ini that return user lists.

[integration_scripts]
admins = /path/to/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"
  }
}

Install Imunify360

The installation instructions are the same as for cPanel/Plesk/DirectAdmin version and can be found in the Imunify360 documentation.

The web-based UI is available via the domain configured in the ui_path.

Note

No files should be located in the folder configured with ui_path. We do not recommend using a directory in which any files are stored as a directory for Imunify UI files.

For example, if /var/www/vhosts/imunify360/imunify360.hosting.example.com/html/im360 is the document root folder for the imunify360.hosting.example.com domain, then you could open Imunify360 with the following URL:

  • https://imunify360.hosting.example.com/ (when you have TLS certificate configured for the domain) or
  • http://imunify360.hosting.example.com/

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.

If you want to see a specific list of users (note, that all of them must be real Linux users accessible via PAM), you can specify the users option in the /etc/sysconfig/imunify360/integration.conf:

[integration_scripts]
users = /path/to/get-users-script.sh

It should point to an executable file that generates a JSON file similar to the following (see details here):

{
  "data": [
    {
      "id": 1000,
      "username": "ins5yo3",
      "owner": "root",
      "domain": "ins5yo3.com",
      "package": {
        "name": "package",
        "owner": "root"
      },
      "email": "ins5yo3@ins5yo3.com",
      "locale_code": "EN_us"
    },
    {
      "id": 1001,
      "username": "ins5yo4",
      "owner": "root",
      "domain": "ins5yo4.com",
      "package": {
        "name": "package",
        "owner": "root"
      },
      "email": "ins5yo4@ins5yo4.com",
      "locale_code": "EN_us"
    }
  ],
  "metadata": {
    "result": "ok"
  }
}

Use server domains

To provide a list of domains for Imunify360, specify the script that generates a JSON file in the /etc/sysconfig/imunify360/integration.conf:

[integration_scripts]
domains = /path/to/get-domains-script.sh

A JSON file should be 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.

Integration config file

The documentation for the Imunify360 Stand-alone version integration configuration file format.

Location /etc/sysconfig/imunify360/integration.conf

Parameters

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

The path to the web server directory, where Imunify360 will be installed and served by web server. Need to be defined before Imunify360 installation.

[paths]
ui_path_owner = panel_user:web_server_group

Allows executing chown to that owner for files after installation. The parameter is optional, if it is absent, chown doesn't execute.

[pam]
service_name = system-auth

The PAM service is used for user authentication in the Imunify360 UI application. By default the system-auth service is used.

[integration_scripts]
admins = /path/to/get-admins-script.sh

The path to the executable script that generates a JSON file with the list of admin accounts.

{
  "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"
  }
}
[integration_scripts]
users = /path/to/get-users-script.sh

The script to provide the specific list of users used by Imunify360.

It should point to an executable file that generates a JSON file similar to the following (domains are optional):

{
  "data": [
    {
      "id": 1000,
      "username": "ins5yo3",
      "owner": "root",
      "domain": "ins5yo3.com",
      "package": {
        "name": "package",
        "owner": "root"
      },
      "email": "ins5yo3@ins5yo3.com",
      "locale_code": "EN_us"
    },
    {
      "id": 1001,
      "username": "ins5yo4",
      "owner": "root",
      "domain": "ins5yo4.com",
      "package": {
        "name": "package",
        "owner": "root"
      },
      "email": "ins5yo4@ins5yo4.com",
      "locale_code": "EN_us"
    }
  ],
  "metadata": {
    "result": "ok"
  }
}

Data description

Key Nullable Description
id False ID of the UNIX account in the system.
username False The name of the UNIX account in the system.
owner True The 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_code True The locale selected by a user.
email True Email of the account user. If there is no email, it should return null.
domain True The main domain of a user.
package True Information about the package to which a user belongs to. If the user doesn’t belong to any package, it should return null.
package.name False The name of the package to which a user belongs to.
package.owner True The 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.