New and updated version for Debian Stretch and OCS Inventory NG server 2.5 can be found here!



In this easy tutorial we will install and configure OCS-NG Server. If you want to know what OCS-NG is, please read below and visit product site.

Table of contents:

  1. What is OCS-NG
  2. Requirements for this tutorial
  3. Installation
  4. LDAP Patch
  5. Finish!

1. What is OCS-NG

Open Computers and Software Inventory Next Generation is a technical management solution of IT assets.
Since 2001, OCS Inventory NG tries to make the automated inventory of computer hardware more efficiently .
Today, our solution not only extends to the inventory. It includes a sophisticated deployment system, interfacing with third tier applications, a network devices scans, and more…

Full description on ocs-ng project home page:


  • Lightweight bandwith usage and small OS footprint.
  • High performance: about 1 000 000 of computers inventoried per day using a server bi-Xeon 3 GHz and 4 GB RAM.
  • Based on well known products such as Apache web server, MySQL database server, PHP and PERLscripting languages.
  • Modular solution with lot of plugins and interfacing with others IT and Asset Management Software like GLPI.

 2. Requirements for this tutorial


In this tutorial we will need following peaces of software:

I strongly recommend running this install inside of virtual machine since wiping it, reformatting or restarting is much faster than on standalone server:)

I performed all steps few times inside virutal environment (Vsphere 5.5 hypervisor aka esxi) but this should apply for any other environment.

Hardware/vm requirements

Our machine should have at least:

  • 1 (v)CPU with 2 cores
  • 2Gigs of RAM
  • 1 Gigabit Ethernet
  • 16GB of storage

Once again, I assume installing it in virtual environment so things like vm-tools will not be necessary to install on standalone servers. I will not cover how to install ESXi or VMWare Player since it’a a material (especially ESXi) for complete series of guides:)

3. Installation

To be honest installation is quite simple since all packages are available for Debian 8.x (Jessie). We don’t need to compile anything from sources and manually register or install dependencies. That saves us quite a bit of work. I know that on some other Linux distros installation might go more straightforward but I’m used to Debian and feel quite comfortable in this environment.

Installation consists of three main steps:

  1. Installation of Debian OS
  2. Installation of required packages
  3. Installation of OCS-NG

Installation of Debian OS

  1. Burn Debian ISO to disk or mount is as cd/dvd in VM
  2. Boot from above
  3. Select to install Debian in 64bit version with minimum options: SSH Server, system utilities. Do not install WWW, DB or other services.
  4. Rest of the options like language or partitioning leave with their default settings.
  5. Reboot and login to shell
  6. Now, we need to install required packages in order to be able to perform rest of the steps. Of course all installs must be performed with root privileges.
  7. Lets type some commands, at last!:

Installation of required packages

Update repositories:

apt-get update -y
apt-get upgrade -y

Install Open VM Tools – they simply work better than original VM-tools from VMWARE.

apt-get install open-vm-tools -y

After above it’s good to restart the VM. Good old Windows school :)
Now, install rest of the packages (system utils):

apt-get install sudo make -y

Install Apache2:

apt-get install apache2 -y

Now, packages for it:

apt-get install -y php5-common libapache2-mod-php5 php-pear php5-cli php5-ldap

Restart Apache with the following command:

service apache2 restart

Continue with installation of packages:

apt-get install -y libxml-simple-perl libio-compress-perl libdbi-perl libdbd-mysql-perl libapache-dbi-perl libnet-ip-perl libsoap-lite-perl

Configure CPAN:

cpan -i XML::Entities

Install Zip package for perl:

apt-get install -y libphp-pclzip php5-gd

Now, install MySQL:

apt-get install -y mysql-server php5-mysql

After typing above command you will have to specify root and admin password for MySQL server. Note them somewhere.
As addition to MySQL I like to have visual representation of databases so lets install phpMyAdmin:

apt-get install -y phpmyadmin

Now, we need to link phpMyAdmin to Apache to be able to actually use it:

ln -s /etc/phpmyadmin/apache.conf /etc/apache2/mods-enabled/phpmyadmin.conf

After that restart apache or even the whole server:

service apache2 restart

Now, you should be able to access your new server at:

  • http://localhost – default apache landing page
  • http://localhost/phpmyadmin – MySQL phpMyAdmin management suite

Good idea (in case of troubleshooting and config checks) is to place a little apache info file in WWW Root. It will display all apache info in one place. This can be very useful for monitoring changes in apache config, loaded modules etc. So let’s add this file:

nano /var/www/html/info.php

New screen will appear
Paste below code into it, press CTRL+X and then confirm changes by pressing Y and then ENTER:

Now, by navigating to:
you will have a nice view at whole apache config. I personally find it very useful. Of course, after setting up everything remove this file for security reasons.

Installation of OCS-NG Server

Installation of server itself is quite simple. OCS team provided us a nice install script that does pretty much of everything for us. If all required packages are available and running user has root privileges all should go hassle free.

First of all we need to download latest build:


Then extract it somewhere. Might be your current dir if you are in for example in /home/ or /tmp/:

tar -zxf OCSNG_UNIX_SERVER-2.2RC1.tar.gz

Enter new directory and execute:


Now install script should configure pretty much for you. At one point you will have to answer non default way:

  • When script will ask about main apache conf file. If you didn’t change anything paste this:/etc/apache2/apache2.conf*
  • When script checks: Checking for Apache Include configuration directory…, paste this: /etc/apache2/sites-enabled*
  • Script will ask if you want to use SOAP extensions and more likely report that libraries are missing. Just continue.

*this might be found in info.php results :)

Script should finish with a message that apache service needs to be restarted. We will do it in few moments.

Now it’s good time to fix some permissions:

chown -R www-data:www-data /var/www/html
chown -R www-data:www-data /usr/share/ocsinventory-reports/

Now, restart apache:

service apache2 restart

After this there is OCS server is almost ready.
Navigate to:
You should get install screen for OCS. Type in:

  • root user for mySql
  • root pass for mySql
  • name of database: I use default: ocsweb
  • hostname of mySql: localhost (since it all runs on one server)

Now you will get screen, that DB needs to updated. Press Perform the update. After upgrade you will be able to login to OCS server by typing admin as user and password.

Ok, back to command line. Installer sets default user and pass for ocsweb DB as ocs/ocs. It’s ok for test environment, but in production we need to change it.

  1. Login to phpMyAdmin with DB root login and pass
  2. Find users TAB in main windows
  3. Note, that there will be two ocs users, click on ocs@localhost (or whatever the host is)
  4. Click Edit Permissions
  5. Click Change password
  6. Change password and submit changes.

Now, OCS will stop working. It’s ok. Now we need to change password in OCS config:

nano /usr/share/ocsinventory-reports/ocsreports/
replace "ocs" in line:
with password you just set

Now OCS reports should be running again.
Now, just delete install script by typing following command:

rm /usr/share/ocsinventory-reports/ocsreports/install.php

Base OCS is now installed and running:)

4. LDAP Patch

As you should know by now, ocs supports external authentication through LDAP to Active Directory. It is very useful since you do not need to define users inside ocs, manage passwords etc. LDAP configuration tutorial is provided by OCS team on their wiki page:

Above tutorial is quite simple, but I found group checking a little not working after setting all according to it. Basically all configuration is covered in it and you must follow it to enable LDAP. Just after enabling I encourge you to patch it a little to avoid:

  • every LDAP authenticated user may login to ocs (no matter if he/she has specifed LDAP group)
  • user with ldap group is added to local users DB. After removing user from group or group from user – he/she is still able to login
  • LDAP user is granted specifed rights no matter if he/she is member of a specifed group or not

I think I have managed to fix this a little by editing 2 files:

  • /usr/share/ocsinventory-reports/ocsreports/backend/AUTH/auth.php
  • /usr/share/ocsinventory-reports/ocsreports/backend/identity/identity.php

Changed sources are attached below:

// Copyleft Erwan GOALOU 2010 (erwan(at)ocsinventory-ng(pt)org)
// Web:
// This code is open source and may be copied and modified as long as the source
// code is always made freely available.
// Please refer to the General Public Licence or Licence.txt

 * LDAP custom authentication module
 * This module will check and report if a LDAP user is valid based on the configuration supplied.
 * Adapted by Erico Mendonca <> from original OCS code.
 * I'm fetching a few LDAP attributes to fill in the user record, namely sn,cn,givenname and mail.
* Small changes to clearly save user ldap groups in session instead of storing them in one big array with rest of data (like name, title cn etc).
* Miłosz Engel
$sql="select substr(NAME,7) as NAME,TVALUE from config where NAME like '%s'";
['OCS']["readServer"],$arg); while($item = mysqli_fetch_object($res)){ $config[$item->NAME]=$item->TVALUE; define ($item->NAME,$item->TVALUE); } // copies the config values to the session area $_SESSION['OCS']['config']=$config; $login_successful=verif_pw_ldap($login, $mdp); $cnx_origine="LDAP"; $user_group="LDAP"; function verif_pw_ldap($login, $pw) { $info = search_on_loginnt($login); if ($info["nbResultats"]!=1) return ("BAD LOGIN OR PASSWORD"); // login does't exist return (ldap_test_pw($info[0]["dn"], $pw) ? "OK" : "BAD LOGIN OR PASSWORD"); } function search_on_loginnt($login) { $f1_name=$_SESSION['OCS']['config']['LDAP_CHECK_FIELD1_NAME']; $f2_name=$_SESSION['OCS']['config']['LDAP_CHECK_FIELD2_NAME']; // default attributes for query $attributs = array("dn", "cn", "givenname", "sn", "mail", "title"); // search for the custom user level attributes if they're defined if ($f1_name != '') { array_push($attributs, strtolower($f1_name)); } if ($f2_name != '') { array_push($attributs, strtolower($f2_name)); } $ds = ldap_connection (); $filtre = "(".LOGIN_FIELD."={$login})"; $sr = ldap_search($ds,DN_BASE_LDAP,$filtre,$attributs); $lce = ldap_count_entries($ds,$sr); $info = ldap_get_entries($ds,$sr); ldap_close($ds); $info["nbResultats"] = $lce; $gr_output = $info[0]['memberof']; array_shift($gr_output); /*echo("TEST grup: <pre>"); print_r($gr_output); echo("</pre>");*/ // save user fields in session $_SESSION['OCS']['details']['givenname']=$info[0]['givenname'][0]; $_SESSION['OCS']['details']['sn']=$info[0]['sn'][0]; $_SESSION['OCS']['details']['cn']=$info[0]['cn'][0]; $_SESSION['OCS']['details']['mail']=$info[0]['mail'][0]; $_SESSION['OCS']['details']['title']=$info[0]['title'][0]; //save user groups in session as separate data as well. $_SESSION['OCS']['details']['groups']=$gr_output; //echo("attr: ".$attributs[0]); //echo("INFO: ".$info[0]['memberOf'][0]); // if the extra attributes are there, save them as well if ($info[0][$f1_name][0] != '') { //attribute name 'memberof' is for group searching //FIXME: casing? -> 'memberOf' if ($f1_name == "memberOf") { //this is to store the entire array instead of just the first string //may be redundant and could be simplified, but it works. $_SESSION['OCS']['details'][$f1_name]=$info[0][strtolower($f1_name)]; print_r($info); } else { $_SESSION['OCS']['details'][$f1_name]=$info[0][strtolower($f1_name)][0]; } } if ($info[0][strtolower($f2_name)][0] != '') { if ($f2_name == "memberof") { $_SESSION['OCS']['details'][$f2_name]=$info[0][strtolower($f2_name)]; } else { $_SESSION['OCS']['details'][$f2_name]=$info[0][strtolower($f2_name)][0]; } } return $info; } function ldap_test_pw($dn, $pw) { $ds = ldap_connection (); if (!$ds or !$pw) { // avec ldap 2.x.x, ldap_connect est tjrs ok. La connection n'est ouverte qu'au bind return false; } else { ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, LDAP_PROTOCOL_VERSION); $r = ldap_bind($ds, $dn, $pw); ldap_close($ds); return $r; } } function ldap_connection (){ $ds = ldap_connect(LDAP_SERVEUR,LDAP_PORT); // Set the LDAP version // add by acop ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, LDAP_PROTOCOL_VERSION); ldap_set_option($ds, LDAP_OPT_REFERRALS, 0); if (ROOT_DN != '' && defined('ROOT_DN')){ $b = ldap_bind($ds, ROOT_DN, ROOT_PW); }else //Anonymous bind $b = ldap_bind($ds); if (!$b) return false; else return $ds; } ?>


/* This module automatically inserts valid LDAP users into OCS operators table.
 * The userlevel is defined according to conditions defined in the following configuration fields:
 * If any of these attributes are defined (and found on the LDAP query), they're used to determine the correct
 * user level and role.
 * in case of success, an array is returned with the access data in the following format: 
 * array('accesslvl'=>%%,'tag_show'=>array(%,%,%,%,%...))
 * else, an error code is returned.
 * In logical terms:
 * if thisGuyIsAdmin=0 then
 *    role=user
 * else if thisGuyIsAdmin=1 then
 *    role=sadmin
 *    Note: the default user levels in OCS currently are "admin", "ladmin" and "sadmin". The above is just an example.
 * My idea is to have groups stored in separate array to be able to use in_array function. It searches for f1_value and f2_value in array usr_gr. value is found in array it assings role based on CONEX_LDAP_CHECK_FIELD1_ROLE and CONEX_LDAP_CHECK_FIELD2_ROLE
 * Additionaly for field2 condition is added to avoid rewriting higher privileges granted by field1 by condition in field2. It should be improved to be more standard. For now it checks if user was granted sadmin role in field1.
if ($_SESSION['OCS']['cnx_origine'] != "LDAP")
	return false;
require_once ('require/function_files.php');
// page name

// select the main database

// retrieve LDAP-related config values into an array
$sql="select substr(NAME,7) as NAME,TVALUE from config where NAME like '%s'";
$res=mysql2_query_secure($sql, $link_ocs,$arg);
while($item = mysqli_fetch_object($res)){
  //  define ($item->NAME,$item->TVALUE);

// checks if the user already exists 
$reqOp="SELECT new_accesslvl as accesslvl FROM operators WHERE id='%s'";
$resOp=mysql2_query_secure($reqOp, $link_ocs,$argOp);

// defines the user level according to specific LDAP attributes
// default: normal user

//echo("default role:  ".$defaultRole."<br>");
// Checks if the custom fields are valid
// store ldap user groups in separate var
/*uncomment for debug
		echo ("<pre>");
		echo ("session information:<br>");
		echo ("f1_name: ".$f1_name."<br>");
		echo ("f1_value: ".$f1_value."<br>");
		echo ("f2_name: ".$f2_name."<br>");
		echo ("f2_value: ".$f2_value."<br>");
		echo ("f2_value2: ".$f2_value2."<br>");
		echo ("</pre>");
		echo ("<pre>GROUPS:<br>");
		echo ("</pre>");
		echo ("default Role: ".$defaultRole."</br>");
	//echo("USER is a member of the following groups: <pre>");
if ($f1_value != '')
    //FIXME: casing? -> 'memberOf'
    if ($f1_name == "memberOf")
		//uncomment for debug
		//echo("<b>Field 1 is set TO</b> LDAP attribute <b>".$f1_value."</b><br>");
		// search through ldap user groups

		if (in_array($f1_value, $usr_gr))
		//uncomment for debug
		//echo ("user :<b>".$_SESSION['OCS']["loggeduser"]." is a member</b> of group: <b>".$f1_value."</b><br>");
		//echo ("and will be granted role: <b>".$config['LDAP_CHECK_FIELD1_ROLE']."</b><br>");
	} /*else {
		echo ("user :".$_SESSION['OCS']["loggeduser"]." is  NOT a member of group: ".$f1_value."<br>");
		echo ("so user will be granted standard user role:<br>");
		//echo ("LDAP_CHECK_FIELD1_VALUE: ".$config['LDAP_CHECK_FIELD1_VALUE']."<br>");
		//echo ("f1_value: ".$f1_value."<br>");
		//if ($f1_value == $config['LDAP_CHECK_FIELD1_VALUE']) {
		echo("now, default role is:  ".$defaultRole."<br>");
	} else {
		if ($f1_value2 == $config['LDAP_CHECK_FIELD1_VALUE']) {
		//uncomment for debug
		//echo ("<b>Field 1 is NOT set</b> to LDAP attribute <b>memberof</b><br>");
		//echo("<b>Now, default role is:  ".$defaultRole."</b><br>");
    //the idea here is to iterate through the groups array looking for a match
    //if we find it, unset the array and store only the match, else leave as it is
    foreach($f1_value as $group){		
        if ($group == $config['LDAP_CHECK_FIELD1_VALUE'])

    //the if below is now redundant since we already know that we have a match
    //the coding can be improved, but the logic works.
    //END NEW
if ($f2_value != '')
{	//IF below secures higher privileges from granted by field 1 to be overwritten by field2
	if ($defaultRole !="sadmin" ) {
   if ($f2_name == "memberOf")
		//uncomment for debug
		//echo("<b>Field 2 is set TO</b> LDAP attribute <b>".$f2_value."</b><br>");
		// search through ldap user groups
		if (in_array($f2_value, $usr_gr))
		//uncomment for debug
		//echo ("user :".$_SESSION['OCS']["loggeduser"]." is a member of group: ".$f2_value."<br>");
		//echo ("and will be granted role: ".$config['LDAP_CHECK_FIELD2_ROLE']."<br>");
	} else {
		if ($f2_value2 == $config['LDAP_CHECK_FIELD2_VALUE']) {
		//uncomment for debug
		//echo ("Field 2 is <b>NOT</b> set to LDAP attribute <b>memberof</b><br>");
		//echo ("Field 2 Value of: <b>".$f2_value2." </b>will be taken into account.<br>");
		//echo("<b>Now, default role is:  ".$defaultRole."</b><br>");

// uncomment this section for DEBUG
// note: cannot use the global DEBUG variable because this happens before the toggle is available.
    echo ("field1: ".$f1_name." value=".$f1_value." condition: ".$config['LDAP_CHECK_FIELD1_VALUE']." role=".$config['LDAP_CHECK_FIELD1_ROLE']." level=".$config['LDAP_CHECK_FIELD1_USERLEVEL']."<br>");
    echo ("field2: ".$item['CONEX_LDAP_CHECK_FIELD2_NAME']." value=".$f2_value." condition: ".$config['LDAP_CHECK_FIELD2_VALUE']." role=".$config['LDAP_CHECK_FIELD2_ROLE']." level=".$config['LDAP_CHECK_FIELD2_USERLEVEL']."<br>");
    echo ("user: ".$_SESSION['OCS']["loggeduser"]." will have level=".$defaultLevel." and role=".$defaultRole."<br>");
//if defaultRole is define
if (isset($defaultRole) and $defaultRole != ''){
    // if it doesn't exist, create the user record
    if (!mysqli_fetch_object($resOp)) {
        $reqInsert="INSERT INTO operators (
                VALUES ('%s','%s', '%s', '%s','%s', '%s', '%s', '%s')";
        // else update it
        $reqInsert="UPDATE operators SET 
                    WHERE ID='%s'";
    // select the main database
    // Execute the query to insert/update the user record
    // repeat the query and define the needed OCS variables
    // note: original OCS code below
    // select the main database
    $resOp=mysql2_query_secure($reqOp, $link_ocs,$argOp);
    if (isset($rowOp -> accesslvl)){
        $lvluser=$rowOp -> accesslvl;

        $profile_config = DOCUMENT_REAL_ROOT.'/config/profiles/'.$lvluser.'.xml';
		if (!file_exists($profile_config)) {
        $profile_serializer = new XMLProfileSerializer();
        $profile = $profile_serializer->unserialize($lvluser, file_get_contents($profile_config));
        $restriction = $profile->getRestriction('GUI');
        //if this user has RESTRICTION
        //search all tag for this user
        if ($restriction == 'YES'){
            $sql="select tag from tags where login='%s'";
            $res=mysql2_query_secure($sql, $link_ocs,$arg);
            while ($row=mysqli_fetch_object($res)){    
            if (!isset($list_tag))
        }elseif (($restriction != 'NO')) 


You may also download it here:
Fix permissions for /usr/share/ocsinventory-reports/, by issuing below command:

chown -R www-data:www-data /usr/share/ocsinventory-reports/

Now, one last restart of the apache (just to make sure everything is working):

service apache2 restart

It wasn’t so hard, wasn’t it :) ?

5. Finish!

That is pretty much all. One more thing is important. Users authenticated by LDAP are added to local user DB (this is by desing). In order to restrict only users who are members of specifed AD group to be able to login and get proper permissions local authentication must be switched off by setting  $list_methode=array(0=>”ldap.php”); in both, AUTH/auth.php and identity/identity.php. Otherwise users once added to local DB after successful login will still be able to login even after removing AD group membership because, they are already in local user DB. Switching local authentication ensures that only AD users with proper AD group are allowed to login. This might be little problematic if AD source is not available, but in that case just re-enable local authentication in above files and you will be able to login using local accounts like admin, etc.

Thank you for reading this tutorial as it’s my first one. I hope you enjoyed it. That being said, I encourage to leave a reply.

I will cover switching to SSL in next part allowing you to enable deployment feature which is quite powerful if used right.

Enjoy :)