Install Adobe Campaign on any computer locally on a VM to set up your own development environment. Plus, access to any VM feature such as snapshots and duplication. This dev setup is for testing and demo only. Configuring Apache on port 443 to receive traffic as a web server allows a more secure connection.



  1. Install Centos on VirtualBox
  2. Install Java 8 JDK
  3. Download and install Adobe Campaign .rpm package
  4. Configure ~/.profile for user neolane and start AC Application server
  5. Configure the firewall
  6. Change the default password
  7. Install postgresql
  8. Connect from your client
  • Installation guide for AC6.1
  • thirdparty6-XXXX-.rpm is now included in the main package, cf
  • Installation guide for AC7

Prerequisites: CentOS 7 x64 on Virtualbox

  1. Get virtual box from
  2. Get Centos ISO from I’ll be using CentOS-7-x86_64-DVD-1810.iso
  3. Spin up a Red Hat instance with the ISO loaded, and install it with the following settings:
    1. Software Selection:
      1. Server with a GUI > Add PostgreSQL Database Server (instructions on youtube)
    2. Connected to Ethernet
    3. user fco with sudo privileges
  4. Shutdown the machine, remove the ISO from the boot settings, set the network setting to Bridged adapter
  5. Restart the machine, accept the licence and log in
  6. Open up a terminal. You should have the following:
  7. Install Virtual Box Guest Addition to enable copy/paste
  8. Optional: Install Gnome instead of Gnome Classic, see tuto on stackexchange
  9. see for details

Java 8 JDK

The JRE is not enough, we need the JDK via the java-1.8.0-openjdk-devel package:

[fco@localhost ~]$ java -version
openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)
[fco@localhost ~]$ sudo yum install java-1.8.0-openjdk-devel
[fco@localhost ~]$ javac -version
javac 1.8.0_191

AC7 rpm package

Let’s do all of our work in ~/ac.

Download the .rpm file from the Download Center ( Then:

[fco@localhost ~]$ cd && mkdir ac && cd ac
[fco@localhost ~/ac]$ sudo yum install -y ./nlserver6-8864-x86_64_rh7.rpm
[fco@localhost ~/ac]$ sudo service nlserver6 start # quick check
Starting nlserver6 (via systemctl):                        [  OK  ]
[fco@localhost ~/ac]$ sudo service nlserver6 status # check 2
14:20:41 >   Application server for Adobe Campaign (6.1.1 build 8864) of 03/02/2018
watchdog (3956) - 4.8 MB
syslogd@default (3529) - 12.7 MB
web@default (3740) - 106.4 MB
[fco@localhost ~/ac]$ sudo service nlserver6 stop

Configure ~/.bash_profile for user neolane

[fco@localhost ~/ac]$ sudo su - neolane
-bash-4.2$ id && pwd && ll
uid=1001(neolane) gid=1001(neolane) groups=1001(neolane)
drwxrwxr-x. 14 neolane neolane 187 Feb 13 14:01 nl6
-bash-4.2$ vim ~/.bash_profile
export LD_LIBRARY_PATH=/usr/local/neolane/nl6/lib/:/usr/lib/jvm/java-1.8.0-openjdk-
export PATH=$PATH:/usr/local/neolane/nl6/bin/
alias ll="ls -alh"
PS1="[\u@\h \w]\$ "
[neolane@localhost ~]$ nlserver start web
14:01:32 >   Application server for Adobe Campaign (6.1.1 build 8864) of 03/02/2018
14:01:32 >   Launching task 'web@default' ('nlserver web -tracefile:web@default -instance:default -detach -tomcat -autorepair') in a new process
14:01:32 >   Application server for Adobe Campaign (6.1.1 build 8864) of 03/02/2018
14:01:32 >   Starting Web server module (pid=9376, tid=9376)...
14:01:32 >   Tomcat started
14:01:32 >   Server started
[neolane@localhost ~]$ nlserver pdump
14:03:23 >   Application server for Adobe Campaign (6.1.1 build 8864) of 03/02/2018
web@default (9376) - 143.4 MB

Configure the firewall

To be able to connect from our Host, we need to create new Firewall rules.

By default CentOS uses firewall-cmd to block incoming connections. We have to allow the ACC default port 8080 (Which is the Tomcat default port).

[fco@localhost ~]$ sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
[fco@localhost ~]$ sudo firewall-cmd --zone=public --add-port=8080/udp --permanent
[fco@localhost ~]$ sudo firewall-cmd --reload

Install postgresql


Init PostgreSQL with a SQL user dbuser1 (password dbpwd1), a SQL database dbuser1 and a Linux user dbuser1:

[fco@localhost ~]$ sudo yum install postgresql-server postgresql-contrib # not needed if already installed via the Centos package selection
[fco@localhost ~]$ sudo postgresql-setup initdb
[fco@localhost ~]$ sudo vim /var/lib/pgsql/data/pg_hba.conf # replace ident by md5
host    all             all               md5
host    all             all             ::1/128                 md5
[fco@localhost ~]$ sudo su - postgres
[postgres@localhost ~]$ createuser --interactive # create a PostgreSQL role (user)
[postgres@localhost ~]$ psql # open the PostgreSQL shell

[postgres@localhost ~]$ createdb dbuser1 # create a PostgreSQL database with the same name
postgres=# ALTER USER dbuser1 PASSWORD 'dbpwd1'; # set a password for the SQL user
postgres=# \q
[postgres@localhost ~]$ exit
[fco@localhost ~]$ sudo adduser dbuser1 # create a Linux user with the same name
[fco@localhost ~]$ sudo systemctl start postgresql # start PostgreSQL now
[fco@localhost ~]$ sudo systemctl enable postgresql # and at boot

You can check your PostreSQL setup by connecting to your Guest via SqlEctron (or any SQL client). To do so, some extra steps need to be taken, see Allow external PostgreSQL access at the end of this article.

Set up instance

We’ll set up an instance named instance1, with default user internal and password internal (See Adobe doc for nlserver config).

$ nlserver config -verbose -addinstance:instance1/*/eng
$ nlserver config -internalpassword
16:23:48 >   Password successfully changed for account 'internal' (authentication mode 'nl').

Note your VM IP, next to inet, here

$ ifconfig
enp0s3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet  netmask  broadcast

Connect with your client internal/internal to

You’ll be prompted to set up the database:

Set the password for the admin account to admin:

Preview of the log:

Submitting job to the server
16:02:10 - Enumerating the file entities...
16:02:11 - Generating schemas...
16:02:12 - Executing SQL script 'xtk:postgresql-functions.sql'...
16:02:12 - Starting 1 connection(s) on pool 'default instance1' (postgresql, server='localhost', login='dbuser1:dbuser1')
16:02:12 - Creating DDL procedures
16:02:12 - Creating standard date and time functions
16:02:24 - Installation of packages successful.
16:02:25 - Changing administrator password...
16:02:25 - Creation of database successfully completed.

You can now login with admin/admin:

And access any feature locally:

For the workflows to start, you need to activate the wfserver process if it doesn’t show up in nlserver pdump with

$ nlserver start wfserver@instance1

Then create and start the first worflow WKF1:

You may also access to the web based interface with the :8080 port, such as

Start multi-instance modules:

$ nlserver start web # already started, no needed
$ nlserver start syslogd
$ nlserver start trackinglogd

Start mono-instance modules:

$ nlserver start wfserver@instance1 # already started, no needed
$ nlserver start mta@instance1
$ nlserver start inMail@instance1
$ nlserver start sms@instance1
$ nlserver start stat@instance1

See ACC Modules documentation

Go to http://localhost:8080/view/supervision:


You might run into some errors while setting up the Db, the following will help:

Debug your instance config file

Each instance is defined in /usr/local/neolane/nl6/conf/conf-{instance-name}.xml. Download the example of conf-instance1.xml.

Update the Db 1/2

[neolane@localhost ~/nl6/datakit]$ psql -U dbuser1 -d dbuser1 -h localhost -f ./xtk/fra/sql/postgresql-nldb.sql

Download the example of postgresql-nldb.sql.

Update the Db 2/2

  1. First import: core schema db.sql (This file can be found in your Support Download Center)
    $ psql -U dbuser1 -d dbuser1  -h localhost -f adobe-campaign-install-db.sql
  2. Second import: public procedures update.sql (See Appendix to generate this file)
    $ psql -U dbuser1 -d dbuser1  -h localhost -f adobe-campaign-update.sql
    $ nlserver package -verbose -instance:instance1 -import:xtk/eng/package/core.xml
    $ psql -U dbuser1 -d dbuser1 -h localhost -f ./xtk/fra/sql/postgresql-nldb.sql
    $ nlserver package -verbose -instance:instance1 -import:nl/postupgrade.xml

    Note: I also had to DROP xtksessioninfo, then re-create manually with this script.

Download your PostreSQL procedures

Create a JS activity with below code:

var f = new File('/sftp/my-instance/incoming/my-ftp-folder/my-procedures.sql');'w');

var fields = "collection,pg_get_functiondef:string";
var sql = "SELECT pg_get_functiondef(f.oid) "+
  "FROM pg_catalog.pg_proc f "+
  "INNER JOIN pg_catalog.pg_namespace n ON (f.pronamespace = n.oid) "+
  "WHERE n.nspname = 'public';";

var res = sqlSelect(fields, sql)

for each(var proc in res.collection){
  logInfo('- '+proc);
  f.writeln(proc.pg_get_functiondef.toString().replace('PARALLEL SAFE ', '')+';')


Example of output for GetDate():

 RETURNS timestamp with time zone
AS $function$
  select clock_timestamp() as result

Download your PostgreSQL tables

Create a JS activity with below code:

var f = new File('/sftp/my-instance/incoming/my-ftp-folder/my-tables.sql');'w');

var table = 'nmsextaccount';

var sqlSchema = NLWS.xtkSqlSchema.BuildSqlSchema('default', table);
var sql = 'CREATE TABLE '+table+'(\n';
for each(var field in sqlSchema.getFirstElement('table').getElements('field')){
  //logInfo(field.$name, field.$type, field.$length);
  var type = field.$type.toLowerCase();
  switch(type){ // see for datatypes
    case 'short': type = 'INTEGER'; break;
    case 'long': type = 'INTEGER'; break;
    case 'double': type = 'DOUBLE PRECISION'; break;
    case 'string': type = 'VARCHAR'; break;
    case 'memo': type = 'TEXT'; break;
    case 'datetimetz': type = 'TIMESTAMP'; break;
  sql += '  '+field.$name+' '+type;
    sql += '('+field.$length+')';
  sql += ',\n';
sql = sql.substr(0, sql.length-2) // remove last ,\n
sql += '\n);'

Example of output for NmsExtAccount:

CREATE TABLE nmsextaccount(
  iactive INTEGER,
  iunicodedata INTEGER,
  mdata TEXT,
  saccount VARCHAR(80),
  sawskey VARCHAR(128),
  tscreated TIMESTAMP,
  tslastmodified TIMESTAMP

Execute JS code from the commande line with nlserver javascript

$ cat test.js
var o = NLWS.xtkOperator.load(2); loginfo(o);
$ nlserver javascript -instance:instance1 -file test.js
17:59:09 >   Application server for Adobe Campaign (6.1.1 build XXXX) of XX/XX/XXXX
17:59:09 >   Starting 1 connection(s) on pool 'default instance1' (postgresql, server='localhost', login='dbuser1:dbuser1')
17:59:09 >   Executing JavaScript from file 'test.js'...


Assign a static IP to the virtualbox VM

On the host, get the IP address, Subnet Mask and Default Gateway. I.e. on Windows with ipconfig:


IPv4 Address. . . . . . . . . . . :
Subnet Mask . . . . . . . . . . . :
Default Gateway . . . . . . . . . :

It means we can choose any IP from to for our VM. Let’s use

On the VM, get the interface name with ifconfig, here enp0s3 in order to edit it:

$ sudo vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
IPADDR= # added
NETMASK= # added
GATEWAY= # added
$ sudo service network restart

Old: don’t do BOOTPROTO="none" # updated from "dhcp", it’s going to disable the internet connection

Integrate with Apache web server

$ sudo yum install -y httpd
$ sudo systemctl start httpd # start now
$ sudo systemctl enable httpd # start at boot
$ service httpd status && curl localhost # check
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2019-02-06 16:53:12 EST; 1min 22s ago
$ sudo firewall-cmd --add-service=http --permanent # allow firewall http
$ sudo firewall-cmd --add-service=https --permanent # allow firewall https
$ sudo firewall-cmd --reload
$ sudo vim /etc/httpd/conf.modules.d/00-base.conf # comment the following modules, with a trailing #:
$ sudo mv /etc/httpd/conf.d/autoindex.conf /etc/httpd/conf.d/autoindex.conf.bak # disable autoindex configuration
$ sudo vim /etc/httpd/conf.d/CampaignApache.conf
ErrorLog "logs/error_log_neolane" # custom error file, will be in /var/log/httpd/error_log_neolane because /etc/httpd/conf/logs points to /var/log/httpd
<Directory "/usr/local/neolane/nl6"> # Allow all /nl6/
    Require all granted
LoadModule requesthandler24_module /usr/local/neolane/nl6/lib/ # load acc lib
Include /usr/local/neolane/nl6/tomcat-7/conf/apache_neolane.conf # load tomcat conf
$ sudo vim /usr/local/neolane/nl6/conf/serverConf.xml # find any allowHTTP="false" and replace with
$ sudo vim /etc/selinux/config # you might to disable SELinux as well, update:
$ sudo service httpd restart

Go ahead and connect to your VM without the :8080 port, such as

The network is now as follow:

Allow external PostgreSQL access

Allow external access to postgresql, see

$ sudo vim /var/lib/pgsql/data/postgresql.conf # replace listen_addresses = 'localhost' to
listen_addresses = '*'
$ sudo vim /var/lib/pgsql/data/pg_hba.conf # add at the end:
host    all             all                           md5
host    all             all              ::/0                            md5
$ sudo firewall-cmd --zone=public --add-port=5432/udp --permanent
$ sudo firewall-cmd --zone=public --add-port=5432/tcp --permanent
$ sudo firewall-cmd --reload