Legacy Server Configuration

Parent Previous Next

Legacy Server Configuration

Note: this material is included for more advanced deployments.  It is no longer the suggested mechanism for launching a server.  The content is included for users who might be going things like integrating Nexus into their own http server or load balancing solution. The information has stopping being updated and does not reflect recent changes (e.g. the move away from gunicorn as the load balancing solution).

The Nexus server runs as a stand-alone Python application based on the Django web framework. It can be used as both a REST server and a file server, or it can be configured to run behind an existing web server via WSGI (Web Server Gateway Interface), relying on the web server itself to act as the primary REST interface and the file server.

The rest of this document describes and demonstrates how to set up and launch a Nexus server in different configurations. First, we document the environment variables that affect the configuration of any server. We then describe how Nexus is currently licensed. As Nexus moves from beta into full product support in the future, licensing may change. We describe how to configure and run a local Nexus server. Finally, we document how to configure and run a network-capable Nexus server with full capabilities for your organization. In all of the interactive sequences, we show the text that you type in bold face.

Environmental Variables

The intent of the default Nexus configuration scripts is to allow the install to be reconfigured primarily via environmental variables. There are several variables that can be useful in Nexus server configurations.

General variables:

If using a local SQLite database (Local Server Configuration) to store data item metadata (note the media directory will be the 'media' directory in the same directory as the SQLite database file):

If using an external database (Remote Server Configuration, e.g. CEI_NEXUS_LOCAL_DB_DIR is not set) such as PostgreSQL to store data item metadata:

Licensing-related environmental variables:


Every instance of the Nexus server framework is licensed using the CEI SLiM licensing system. When the Nexus server is launched, it will ascertain if the server is local or remote (see below). Each local server may be launched without consuming any tokens. Each instance of a remote server uses 50 'LICENSE_NEXUS_SERVER' tokens.

The environmental variables CEI_NEXUS_LICENSE_FILE_DIRECTORY and SLIMD8_SERVERS can be used to select the instance of the SLiM service to use for licensing. Nexus will also check for the {CEI_HOME}/license8/slim8.key file and the ~/.ensightXXX/slim8.key file if the preceding variables are not set, where XXX is the version of EnSight corresponding to the version of Nexus.  Presently it is 102. Setting the environmental variable CEI_NEXUS_DEBUG to 1 will enable lower-level debugging of licensing issues.

Running a Local Nexus Server

In most cases, a local server is launched from the nexus_template_editor application. That application can generate a new, empty database as well as launch a Nexus server that serves up that database. On a local system, a Nexus database consists of two files ('db.sqlite3' and 'manage.py') and a directory ('media'). One can manually launch a local Nexus server by setting up the necessary environmental variables, changing the current directory into the Nexus installation, and launching the server. These tasks can be automated with a simple script file.  For example, on Windows with a database located in C:\Users\rjfrank\test_db, the following commands in a .bat file will start a local Nexus server instance:

set CEI_NEXUS_LOCAL_DB_DIR=C:\Users\rjfrank\test_db


cd "C:\Program Files (x86)\CEI\nexus193\django"

call cpython manage.py migrate

call cpython update_geometry.py

cpython manage.py runserver --insecure localhost:8000

The same thing can be done on a similar Linux setup (with Nexus installed in /usr/local/CEI) using a Bash script:

export CEI_NEXUS_LOCAL_DB_DIR=/home/rjfrank/test_db


cd /usr/local/CEI/nexus193/django

../../bin/cpython manage.py migrate

../../bin/cpython update_geometry.py

../../bin/cpython manage.py runserver –-insecure localhost:8000

In the above scripts, the 'migrate' command to Django’s manage.py will update the database to the most recent version, and the 'runserver' command starts a new Nexus server on localhost, listening on port 8000 (accepting connections only from the local machine). The update_geometry.py script will update the representation of any 3D geometry that has been uploaded into the server. The meaning of the environmental variables aredescribed above.

Running a Remote Nexus Server

There are several unique features of a remote server configuration.  Most of these features are related to increased single query performance or the capacity to handle multiple requests simultaneously (increased scalability). A remote Nexus server may use:

There are several steps required to set up a remote server, but many of them can be automated with the remote configuration script.

Directory Configuration

An instance of a Nexus remote server exists in a single directory on the server system. The directory contains all the bits necessary to run a server. Minimally, these include a startup script (start_server.sh), a Gunicorn configuration file (gunicorn_cfg.py), and a 'media' directory (media) where the image, movie, and 3D geometry files will be placed. These configuration files can be generated by hand or by running a Nexus-provided configuration script (nexus_remotedb_config10).

Remote Database Setup

Though a remote Nexus server may use an SQLite database, for performance reasons we recommend the use of a scalable database engine like PostgreSQL. In this example, we demonstrate the use of a PostgreSQL database instance that is already running on the same system (named rjflinux) that the NGINX and Nexus instances will run on. (If you do not already have PostgreSQL running, please consult the documentation for your distribution. Nexus supports PostgreSQL versions 9.4 and greater. The rest of this documentation presumes that PostgreSQL is running and there is a postgresql user configured.)

(Note: PostgreSQL by default is set to be able to store arbitrary string data. Problems can crop up if this is misconfigured. Be sure your database is configured to be able to store arbitrary string data. Normally, this means giving it an encoding of UTF-8 or UTF-16 (UTF-8 is highly recommended). If you use a more restrictive encoding – for example, latin1 (iso8859-1) – you won't be able to store certain characters in the database, and information will be lost. PostgreSQL users, refer to the PostgreSQL manual (section 22.3.2 in PostgreSQL 9) for details on creating databases with the correct encoding.)

The first step is to create a database in the PostgreSQL instance. The PostgreSQL command 'createdb' is used for this purpose: 

rjflinux% sudo -u postgres createdb nexus_database

Once the database has been created, we need to add a PostgreSQL username that enables access to the newly created database. Note: this is NOT the username in the Nexus system, rather this is the username/password that Nexus will use to interact with the PostgreSQL database. This is done through a few SQL commands.

rjflinux% sudo -u postgres psql

psql (9.2.18)

Type "help" for help.

postgres=# CREATE ROLE nexus WITH LOGIN PASSWORD 'cei';


postgres=# GRANT ALL PRIVILEGES ON DATABASE nexus_database TO nexus;


postgres=# ALTER USER nexus CREATEDB;


postgres=# \l

                                    List of databases

      Name      |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges


 nexus_database | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =Tc/postgres         +

                |          |          |             |             | postgres=CTc/postgres+

                |          |          |             |             | nexus=CTc/postgres

 postgres       | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 |

 template0      | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +

                |          |          |             |             | postgres=CTc/postgres

 template1      | postgres | UTF8     | en_US.UTF-8 | en_US.UTF-8 | =c/postgres          +

                |          |          |             |             | postgres=CTc/postgres

Remote Configuration Script (nexus_remotedb_config10)

The configuration script can be run once the database has been set up, as documented above. The script will generate the necessary configuration files, initialize the database, and set up an administrative user for the Nexus database. The script is largely interactive, prompting the user for the necessary inputs. You will input the directory to build the configuration in along with all the parameters needed to set up the configuration. Once the script is run, you will have configuration files you can use in the next setup steps. An example is shown here:

rjflinux% nexus_remotedb_config
Create new Nexus remote database tool.  Version: 1.0

This tool will create a new Nexus remote database directory along
with the necessary startup scripts and configuration files.  The
server will be configured as a WSGI gateway designed to be hosted
under an NGINX instance.


Please provide the name of a new directory in which to create the
configuration in. This directory should not exist.
New directory [/home/rjfrank/new_nexus_server]:

The WSGI Nexus instance can run in parallel and will be available
to the webserver (e.g. NGINX) at a specific hostname and port.
It can be configured to run as any user on the system. Please
enter the settings for the WSGI instance (gunicorn):
Number of parallel servers [3]:
WSGI hostname []:
WSGI port number [8001]:
WSGI username [rjfrank]:

The NGINX server that hosts the Nexus WSGI instance and provides
static file serving maps a specific external hostname to the WSGI
instance.  Please provide the hostname that will be routed to the
WSGI instance.
NGINX external Nexus hostname: rjflinux.ceintl.com

Select the source for CEI licensing information.  This can be
the name of a directory containing a value slim8.key file or
the URL of a SLIM server (slim_server.somedomain.com:7790).
SLIM license manager: /home/rjfrank/.ensight193/slim8.key

The new remote database can use SQLite or PostgreSQL as the
back-end database server.
Use an SQLite database ([Y/n]): n

The new database will uses a PostgreSQL back-end. Additional
information about that database will need to be collected.

Each Nexus server instance uses a unique database in the PostgreSQL
PostgreSQL database name [nexus_database]:

Please provide the PostgreSQL server hostname and port number.
PostgreSQL server hostname []:
PostgreSQL server port number [5432]:

Please provide the PostgreSQL username and password needed to
access the database:
PostgreSQL server username [nexus]:
PostgreSQL server password [cei]:

Testing PostgreSQL connection...

The Nexus instance itself will need an administrative user.
Please provide the username and password to use:
Nexus instance admin username [nexus]: rjfrank
Nexus instance admin password [cei]: junk_password
Nexus instance admin email address: rjfrank@ceintl.com

Nexus can support embedded remote rendering sessions. This

feature requires external configuration files.

Do you want to enable remote session support ([y/N]):

Building the database...

Setting up the super user...
Python 2.7.11 (default, May 19 2016, 17:08:11)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.


Note, for specifics on configuring remote render sessions, see this section.

The new database directory will have a 'media' directory along with the files 'gunicorn_cfg.py', 'nexus.conf' and 'start_server.sh'.  The contents are listed here:


# Gunicorn configuration file

# Generated 2017-04-10 by /opt/CEI/nexus193/remotedb_config/remotedb_config10.py








# NGINX configuration file for Nexus WSGI server

# Generated 2017-04-10 by /opt/CEI/nexus193/remotedb_config/remotedb_config10.py


# Potential NGINX configuration changes (NGINX.conf)

# Allow large POST requests

#client_max_body_size 500M;

# Add to the core NGINX.conf

#include /etc/NGINX/sites-enabled/nexus.conf;

###### Begin nexus.conf #######

server {

    server_name rjflinux.ceintl.com;

    access_log off;

    location /static/admin/ {

        root /opt/CEI/apex32/machines/linux_2.6_64/Python-2.7.11/lib/python2.7/site-packages/django/contrib/admin/;


    location /static/rest_framework/ {

        root /opt/CEI/apex32/machines/linux_2.6_64/Python-2.7.11/lib/python2.7/site-packages/rest_framework/;


    location /static/ {

        root /opt/CEI/nexus193/django/website/;


    location /media/ {

        root /home/rjfrank/new_nexus_server/;


    location / {


        proxy_set_header X-Forwarded-Host $server_name;

        proxy_set_header X-Real-IP $remote_addr;

        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';





# Nexus server startup file

# Generated 2017-04-10 by /opt/CEI/nexus193/remotedb_config/remotedb_config10.py


cd "/home/rjfrank/new_nexus_server"

# Basic path information

export CEI_HOME="/opt/CEI"

export NEXUS_HOME="/opt/CEI/nexus193"

export PATH="$CEI_HOME/bin:$PATH"

export PATH="$CEI_HOME/apex32/machines/linux_2.6_64/Python-2.7.11/bin:$PATH"

# Licensing information

export CEI_NEXUS_LICENSE_FILE_DIRECTORY="/home/rjfrank/.ensight193"

# Database environment

export CEI_NEXUS_DB_DATABASE_NAME=nexus_database

export CEI_NEXUS_DB_USER=nexus



export CEI_NEXUS_DB_PORT=5432

export CEI_NEXUS_LOCAL_MEDIA_DIR="/home/rjfrank/new_nexus_server"

# Update schema

cpython "/opt/CEI/nexus193/django/manage.py" migrate

cpython "/opt/CEI/nexus193/django/update_geometry.py"

# Start the WSGI server

gunicorn -c gunicorn_cfg.py ceireports.wsgi

In this configuration, there will be a Gunicorn server with 3 parallel workers (each checking out 50 cei tokens using the slim8.key file in /home/rjfrank/.ensight193) that will run as a WSGI server on localhost (, port 8001. If the nexus.conf file is integrated into the NGINX configuration, it will map access to rjflinux.ceintl.com:80 to the Gunicorn server. On the physical machine, one can access the server as http://localhost:8001, although the image/css/etc. static files will not be served, as these are normally served by the NGINX server (static location sections).

Hosting Nexus Servers Under Sub-URLs

In the previous examples, every Nexus server instance was being accessed using a unique hostname. It can be useful to set up multiple Nexus servers under the same hostname using a sub-URL. For example, one might desire to have servers with the URLs http://nexusdemo.ensight.com/cei_basic and http://nexusdemo.ensight.com/cei_advanced, which differ only by the sub-URL names, hosted through the same NGINX server.

For this example, we start by creating cei_basic and cei_advanced directories.  We use the remote database setup script to set up new servers in each of these directories. Note that each server will have its own media directory. Make sure that both servers use different WSGI port numbers (if running on the same host), that their media directories are in different locations, and that they use different PostgreSQL database names. They can share the same PostgreSQL database instance (hostname:portnumber), but the database names must be different. In our example, we will configure the WSGI ports for cei_basic and cei_advanced to be 9000 and 9100 respectively.

The media directories need to be accessible from NGINX, as we will use NGINX to serve up the files. They also need to be accessible from the Nexus instance using different names. To do this, we set up symbolic links to the two media directories. Start with cei_basic and issue the following commands

cd cei_basic

mkdir cei_basic

cd cei_basic

ln -s ../media .

This makes the media directory accessible as both 'cei_basic/media' (for Nexus) and 'cei_basic/cei_basic/media' (for NGINX). The same operation should be repeated for cei_advanced. In the start_server.sh file, one needs to tell Nexus that the URLs it should generate for files in the media directory should use the NGINX names. Add the environmental variable:

export CEI_NEXUS_MEDIA_URL_PREFIX="/cei_basic/media/"

for the cei_basic start_server.sh script. Take care to include the '/' at the start and end of the variable.

The remaining configuration changes are applied to the NGINX configuration file. In this case, we can use a combined cei.conf file that supports both the cei_basic and cei_advanced servers. The file would look something like this:

server {

    server_name nexusdemo.ensight.com;

    proxy_read_timeout 300;

    client_max_body_size 500M;

    access_log off;

    # Common locations for both sites that point to an installed nexus distribution

    location /static/admin/ {

        root /usr/local/CEI/apex32/machines/linux_2.6_64/Python-2.7.11/lib/python2.7/site-packages/django/contrib/admin/;


    location /static/rest_framework/ {

        root /usr/local/CEI/apex32/machines/linux_2.6_64/Python-2.7.11/lib/python2.7/site-packages/rest_framework/;


    location /static/ {

        root /usr/local/CEI/nexus193/django/website/;


    # This is the cei_basic "media" location

    location /cei_basic/media/ {

        root /home/nexus/cei_basic/;


    # This is the cei_advanced "media" location

    location /cei_advanced/media/ {

        root /home/nexus/cei_advanced/;


    # map the sub-url cei_basic to the WSGI instance running on localhost on port 9000

    location /cei_basic {


        proxy_set_header SCRIPT_NAME /cei_basic;

        proxy_set_header X-Forwarded-Host $server_name;

        proxy_set_header X-Real-IP $remote_addr;

        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';


    # map the sub-url cei_advanced to the WSGI instance running on localhost on port 9100

    location /cei_advanced {


        proxy_set_header SCRIPT_NAME /cei_advanced;

        proxy_set_header X-Forwarded-Host $server_name;

        proxy_set_header X-Real-IP $remote_addr;

        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';



The key points are the prefix handling for the location blocks for both the media directories and the WSGI instances themselves. The proxy_set_header SCRIPT_NAME clause tells Nexus that the URLs it generates need to have a URL prefix added.

Running the two start_server.sh scripts and restarting NGINX with that config enabled will allow two instances of Nexus to run on the same system, using the same instance of NGINX, but served under different sub-URLs. Note that each instance of Nexus will check out separate licenses from the SLiM license server.

Common Issues

There are a few common issues that crop up in initial installations. Some of their solutions are noted here.

PostgreSQL Authentication Problems

PostgreSQL uses “Ident” authentication by default for many types of connections. If Nexus generates an error saying that “Ident authentication failed” for your configured user, you will have to configure the authentication. Either properly ‘ident’ mapping to the OS user or switch PostgreSQL authentication methods. We have found that “md5” authentication works well for PostgreSQL.


One very common issue is that complex Nexus reports can take some time to generate. The default timeouts in web servers and Gunicorn are often set too low for use with complex Nexus reports. These errors often look like pages that take a long time to load and then result in HTTP 500 or 503 errors. When the same example is run with a local server, the report can take some time to run, but generates just fine. If you are running into timeouts, there will be two places where the timeouts should be extended.

1. In the webserver: For NGINX, one can add a line like:

     proxy_read_timeout 300;

    in the location block of the configuration file and then restart the server.

2. in the gunicorn configuration file: In the 'gunicorn_config.py' file, add a line like:

    timeout = 300

    and restart the Nexus server.

The above examples will set the timeout to 300 seconds (often the defaults are 30 or 60 seconds).

Linux psycopg2 module error

On some Linux installs, the PostgreSQL runtime libraries may not be installed.  When launching a PostgreSQL configured server on such machines one may encounter an error like:

django.core.exceptions.ImproperlyConfigured: Error loading psycopg2 module: libpq.so.5: cannot open shared object file: No such file or directory

The fix is to install the prerequisite libraries:

sudo yum install postgresql-libs.x86_64

HTML is displayed, but no files (images, css, etc)

It is not uncommon for the userid under which NGINX runs to not be the same userid that installed Nexus or is running the Nexus instance. Nexus is configured via the NGINX configuration files to serve static files directly, while generating the dynamic HTML using a WSGI gateway (e.g., Gunicorn or the direct Nexus instance). If the userid under which NGINX is running does not have read access to the static files, one may see only the HTML portion of the Nexus web pages. If one checks the NGINX log files, one might see errors like this:

2017/03/14 14:35:20 [error] 2610#0: *3 open() "/home/nexus/cei_home/CEI/nexus193/django/website/static/website/scripts/respond.js" failed (13: Permission denied), client:, server: webserver02.ceintl.com, request: "GET /static/website/scripts/respond.js HTTP/1.1", host: "webserver02.ceintl.com", referrer: "http://webserver02.ceintl.com/about"

This error can be fixed by adding the NGINX user to the group under which Nexus is running.  For a system where NGINX is running under 'nginx' and Nexus is running under 'nexus':

sudo gpasswd -a NGINX nexus

Note: one might also have to give group read permissions to the nexus home directory if the files are located in the nexus home directory:

sudo chmod g+rx /home/nexus