Howto:PHP based Update Server V2

From innovaphone wiki
Jump to navigation Jump to search

Applies To

This information applies to

  • all innovaphone devices
  • web server running PHP 5 (e.g. Linux Application Platform)

All Versions prior to 13r1 (for 13r1 and later, see Reference13r1:Concept App Service Devices instead).

By default, the Update Manager mechanism reads a file that corresponds to the device type (e.g. update-ip222.htm). While this makes sense (update scripts may vary by device type), it is sometimes tedious, as you have to edit a huge amount of files which typically are (at least partly) identical.

Here is a PHP script that can be used as an Update Server that allows you to simplify the handling of update scripts. It also includes a mechanism that makes sure that all devices always have the same firmware installed as a given master device has. Finally, it implements a straight forward configuration backup scheme.

This article describes version 2 of this update server (build 2006 and up). The previous version is described in Howto:PHP_based_Update_Server. The enhancements are

  • Status user interface showing all known devices
  • Ability to roll out custom device certificates
  • Ability to provide configuration files to MTLS-authenticated devices only (e.g. in order to keep certain configuration settings secure)
  • Hide configuration files from public read access

More Information


The update server script requires a web server with working PHP 5.3 or higher platform. It has been tested with Apache and ligHTTPD (on a Linux Application Platform). On IIS, neither the certificate roll-out nor the MTLS authentication or configuration backup works with IIS.

The platform running the PHP scripts must have a valid time setting!

PHP 8 is supported from build 2023.


The update server can

  • update all your devices with boot code and firmware that corresponds to the versions running on a reference device of your choice
  • save backups of your devices configuration. Backups are saved only if the configuration changed since the last backup
  • invoke your own update scripts depending on
    • various phases (e.g. you can have staging scripts which are only executed once and normal scripts which are executed in normal operation later on)
    • devices classes (e.g. you can have different scripts for phones and gateways)
    • environments (e.g. you can have scripts for your internal devices and others for devices in home offices)
    • the device serial number
  • roll out customer specific device certificates
  • roll out update scripts to devices only that have identified themselves with a valid device certificate (MTLS)
  • maintain a list of devices in your installation along with some vital information about each individual device


On the Linux Application Platform

Here is how you would install it on the LAP. Some of the steps may not be necessary if you don't want to use all features.

On the Linux Application Platform, you would

  • open the LAP's file system using a SFTP client such as e.g. WinSCP (if you have not yet changed it, the default credentials will be root/iplinux, see Concept Linux Application Platform). Note that you must use SFTP rather than WebDAV, as WebDAV will not give access to the executable web server files
  • create a new root directory underneath /var/www/innovaphone/mtls, e.g. /var/www/innovaphone/mtls/update
  • download the complete file package of scripts and files here
  • copy all files and directories in to this new directory
    • create your local config files. We will never overwrite these in further updates.
      • Rename config/user-config-sample.xml to config/user-config.xml
      • Rename scripts/all-all-all-sample.txt to scripts/all-all-all.txt
  • change owner and group of all files and directories to www-data, change mode to 0600 for all files and 0700 for all directories (see below for how to do this with WinSCP)
  • log in to the LAP's admin UI (if you have not yet changed it, the default credentials will be admin/linux, see Concept Linux Application Platform) and open its Administration/Web Server/Change web server properties and public access to the web/webdav configuration UI. Add the following paths to Public Web Paths (assuming your base directory is called update):
    • /mtls/update
    • /mtls/update/web
    • /mtls/update/admin
    • /mtls/update/fw/ (note the trailing slash!)
make sure that no other sub-directories of update are listed
make sure you have no trailing '/' in any of these paths (except fw/')
this will make sure the update server's admin user interface is not accessible to the public

At this point, you should be able to access the update server's admin user interface, e.g. However, the only thing you see is a login page. Please note that your browser should ask you for a password for this page (unless you already entered it before). Cookies must be enabled for the login page to work properly.

If you want to provide HTTPS Acess to the Update Server

For HTTPS access to the update server, you may want to install your own server certificate under Administration/Certificates/Current server certificate. However, this is not strictly required (you will experience some warning messages when using your browser to access the update server, however, calling devices will work just fine).

If you want to setup MTLS-restricted Delivery of Update Scripts

If you think you have sensitive information in your update scripts, you should make sure to deliver such scripts to your own verified devices only. This can be done by authenticating calling devices with mutual TLS (MTLS). In this case, the calling device must use HTTPS to retrieve the update script and present a trusted client certificate that identifies itself as the calling device (that is, has the device serial as the certificate's common name (CN)).

For this feature, you need to Configure mutual TLS in the LAP's Administration/Web Server panel. Simply tick the Active check-mark and select an appropriate MTLS Port. The port must not conflict with any other TCP port used on the LAP, so neither 80 nor 443 is a good choice. 444 is a good choice. Although it is assigned to the snpp protocol by IANA, it is not used by the LAP (and probably rarely used anyway).

If MTLS is already activated on your LAP, simply take note of the currently configured MTLS Port.

Please note that MTLS access is not possible through a reverse proxy (RP). This is because the RP always will terminate the incoming TLS connection and establish its own to the target. Therefore, the client certificate presented to the target server is the RP's certificate, not the original clients certificate. In our context - where MTLS is used to verify the identity of the original caller - clients must not access the update server through an RP.

You can either expose your update server directly to the internet (and carefully think through the security implications) or create specific TCP port forwarding towards the update server in your NAT-router/firewall. In this case, we recommend to use non-standard HTTP and HTTPS ports on the NAT router (cause this will already keep most of the HTTP port scanners out there in the internet from functioning).

Also, you will need the public key of all the CAs you will trust. These must be configured in to the web server so it can trust the certificates your devices will present to it. See #Enforcing_Trust for details.

On an Apache Server running on the Windows Operating System

The update server will run on Apache too. However, as we did not test this setup thoroughly, we recommend to use the LAP's LigHTTPD instead.

On Microsoft's IIS

We do not recommend to use IIS as

  • it does not support PUT easily
  • it is not compatible with the innovaphone device's MTLS implementation

Update existing installation

  • download the new sources
  • copy all files and directories to your existing installation folder (overwrite existing files)
  • change owner and group of all files and directories to www-data, change mode to 0600 for all files and 0700 for all directories


If you intend to deliver your update scripts with MTLS (that is, with HTTPS and mutual certificate check)

  • you will need to have the full name of your certificate Authority (CA) as it is noted as Common Name (CN) in your CA's certificate
  • also, you will need a PEM version of your CA's public key (a PEM version of a certificate is a text file that begins with a line like -----BEGIN CERTIFICATE-----)

Also, you need to know the MTLS Port configured in your LAP (see If you want to setup MTLS-restricted Delivery of Update Scripts above).

All tweakable parameters are set in user-config.xml. You may want to use an XML-capable editor such as notepad++, netbeans or Visual-Studio for editing. if your editor supports it, you benefit from the document type description (DTD) provided in full-config.dtd.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
<config debugmerge="false" debugcerts="false" debugscript="false">

The attributes of the config tag control some aspects of debugging. For now, simply set all 3 to "true" instead of "false". Do not forget to revert them back to "false" when everything runs smoothly, large log files will result if not.

Securing Access

To control access to the update server's data, you should set a login. This can be done in the master tag by specifying both user and password:

    <master ...  user="myadmin" password="mysecret"/>

Default username and password are admin/password.

Delivering Firmware and Boot Code

At this point, you can simulate a device by requesting an update script using an URL like in your browser (please note that this URL should not ask you for a password). Most likely, your browser will wait a little while and then say something like:

# failed to use cached data (cache not current), retrieving info online
# cannot get PBX info: cannot access http://yourmasterdevice.youdomain.tld/CMD0/box_info.xml, reading cache
# cannot get cached PBX info: cannot access cache/master-info.xml - exit

This is because you did not yet specify the master device which always runs the reference firmware.

The idea here is that you have one innovaphone device in your system where the firmware is always manually updated. All other devices shall follow this reference firmware. The update server will deliver the firmware that runs on the master device to calling devices. For this to work, you need to set the info attribute of the master tag and leave everything else as is.

Remember that you do all your local configuration changes in user-config.xml.

As master is a first level tag, you can add it directly underneath the opening <config> tag. The only thing we need to define right now is the path to read the firmware information from your master device. Let's say your reference device has the IP address, you end up with

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
<config debugmerge="true" debugcerts="true" debugscript="true">
	<master info=""  user="myadmin" password="mysecret"/>

(you could use a DNS name instead of the IP address of course). The info URL is used by the update server itself only, it is never used by devices requesting an update script.

When you refresh the page that simulates a device requesting an update script, the output should now change to something like

# failed to use cached data (cache not current), retrieving info online
# current firmware (unknown) does not match required firmware (130178)

This is to say that your master device runs firmware 130178 and the calling device does not (actually, as the calling client is simulated by your browser, it does not transmit its current firmware to the update server so it is (unknown)).

In order to actually update the clients with firmware and boot code, the files must be made available to the calling client somehow. This is done by specifying an URL in the prot and boot commands sent to the calling device:

# current firmware (unknown) does not match required firmware (130178)
mod cmd UP0 prot ser 130178
# current boot code (unknown) does not match required boot code (130112)
mod cmd UP0 boot ser 130112

By default, the URL generated points to a sub-directory of your update server called fw: Note that this default URL expects sub-directories underneath the fw directory which correspond to the firmware and boot code build number. The file structure thus would be like


Note that the URL ends with a slash (/). This instructs the calling device to append the appropriate file name itself when retrieving the file (see the prot command for details).

However, you can also specify any other URL by setting the url attribute in the fwstorage tag of your user-config.xml. In this attribute, certain meta words will be replaced (see the fwstorage tag for details). The default setting for example is fw/{build}/.

You can disable firmware and boot code updates altogether by setting the info attribute in the master tag to an empty value.

Your own Update Script Files

The update server will deliver update scripts to calling devices which are synthesized from a number of update script snippets which you define yourself. The idea is that many devices share parts of their configuration while other parts are different. This depends on

  • the device class (e.g. a phone or a gateway)
the device class is automatically derived from its model. In fact, a single device may be in multiple classes. For example, an IP232 is in these classes: phone, pre_opus_phone, phone_newui which basically says that its a phone and has no OPUS codec yet but a "new" user interface (as opposed to the old one found e.g. on an IP110). A number of useful classes are pre-defined, but you can add your own in user-config.xml.
  • the device's environment (e.g. home-office, branch-office)
These reflect the fact that devices may need different configuration if they are in different locations (or environments). The update server does not know about a device's environment, which is why you need to configure it in to the devices update URL if you need this. By default, there is a single environment defined called default, but of course, you can add your own
  • phase
configuring devices may need multiple phases to go through. If more than one phase is defined, the device will go through all phases sequentially, which is why a phase has a numerical seq attribute. Phases are went through in order of this attribute. When the device has reached the last phase, it will stay there. By default, there is only one phase called update

You can define update script snippets for any combination of device, environment and phase. You do so simply by placing appropriate files in to the scripts directory on your update server.

Let's have a closer look at the web page we used to simulate a device calling for an update script before ( It will show you all the possible files it would deliver to the device:

# possible files (from scripts):
# scripts/update-all-00_90_33_00_00_00.txt does not exist
# scripts/update-all-default.txt does not exist
# scripts/update-phone-00_90_33_00_00_00.txt does not exist
# scripts/update-phone-default.txt does not exist
# scripts/update-pre_opus_phone-00_90_33_00_00_00.txt does not exist
# scripts/update-pre_opus_phone-default.txt does not exist
# scripts/update-phone_newui-00_90_33_00_00_00.txt does not exist
# scripts/update-phone_newui-default.txt does not exist

The update script snippet files need to have proper names to define when they should be delivered. As you can see, they all start with update- which means that they apply to devices which are in the update phase. As by default there is only a single phase defined, all possible file names start with update-.

The next part here is either phone-, pre_opus_phone-, phone_newui- or all-. This is because the calling IP232 is in three classes, so all respective snippets will be delivered to it. all however is a wild-card. That is, such files will be delivered to all devices, no matter what class they are in. You may wonder why there was no all for the phase. This is because there is only a single phase defined. If there would be more, the all-variation of the phase-part of the file name would be appear.

The third part finally is either default or 00_90_33_00_00_00 in our case. default is the name of the only environment that is defined by default. 00_90_33_00_00_00 is the device's serial number which is treated as an implicitly defined environment name. This allows you to deliver certain snippets to a single device only.

Now let's create an update script snippet that is delivered to all phones in the default environment when they are in the update phase. The file name (which looks like phase-class-environment.txt) has to be update-phone-default.txt therefore. Just for an exercise, let us set the device name (as shown in the browser's title bar) to This is a Phone!. The command to do so is config add CMD0 /name This+is+a+Phone%21, so your file may look like this

# set the device name
config add CMD0 /name This+is+a+Phone%21

(btw: did you observe that config line arguments need to be url-encoded?). Now create the file and upload it in to the scripts directory of you update server. When you now refresh the page which simulates the device calling for an update script, you will see something like this:

# newest script (scripts/update-phone-default.txt) 11s old
# files being updated (scripts/update-phone-default.txt 11s old, waiting for at least 90s to expire)

When you update multiple script snippets, it is often undesirable that a device retrieves an inconsistent state of the scripts you are working on (e.g. if you already have saved one but not yet the other). To avoid this, the update server will look at the files modification dates and if one of those that needs to be delivered to the device is younger than 90 seconds, it will not send any of them at all.

So when you wait for the 90 seconds to pass and refresh the page again, you will see something like this:

# firmware build info cache is current
# phase: update, nextphase: , environment: default, type: IP232, classes: phone+pre_opus_phone+phone_newui
# possible files (from scripts):
# scripts/update-phone-default.txt 4.1 mins
#     scripts/update-phone-default.txt
# { begin script 'scripts/update-phone-default.txt' 
# set the device name
config add CMD0 /name This+is+a+Phone%21

# end script 'scripts/update-phone-default.txt' }

# trigger reset if required
config write
config activate

As you can see, your snippet has been delivered by the update script. However, the update server has also added some trailing commands which write back the config to the devices flash memory (config write), activate it (config activate) and trigger a reset if needed (iresetn).

If there are multiple snippets available for a calling device, all of them are concatenated in the sequence shown in the header of the returned script (where the possible file names are listed)

Device Status

When you have a lot of devices which are served by the update server, you may want to have a list of these devices along with some useful information regarding each devices.

You can enable this by defining the status tag in your user-config.xml. So open the file and add the tag right next to the master tag you added before:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
    <master info=""/>

When you have done so, please refresh the page that simulates your calling device and then open You will now see a device list (well, a list with a single device, the one you simulated using your browser). The list will show some information regarding the devices that requested an update script lately. For more options, see #status.

Device Backup

It is generally useful to have recent backups of all of your device configurations. The update server supports that if you enable it by defining the backup tag in your user-config.xml. Simply put it right next to the master or status tag you added before:


If you have done so and then refresh the page that simulates your calling device, you will now see

# scripts/update-phone_newui-default.txt does not exist

mod cmd UP0 scfg

instead of

# scripts/update-phone_newui-default.txt does not exist

# Backups not enabled in config

When a client requests an update script the next time, this will initiate a configuration backup which is stored underneath the backup directory. For each device, a sub-directory is created and all backup files are stored therein. By default, the last 10 differing configuration backups are kept.

Controlling the Time-frames when Snippets are delivered

The update client built-in to innovaphone devices allows to restrict updates to certain time frames (e.g. only during the night). This can be controlled using the times command.

You can configure the update server to use the time commands by setting the allow and initial attributes in the times tag in your user-config.xml.


If either the allow or initial attribute is present, the update script will contain a line like

# Restricted times
mod cmd UP1 times  /allow 22,23,0,1,2,3,4 /initial 1

In the example above, all update script activity will occur only between 10pm and 5am (local device time). For more details, see Concept Update Server

Using and Enforcing HTTPS

Your devices can either use HTTP or HTTPS to access the update server. In normal operation, the update server will generate URLs (e.g. the URLs used to retrieve firmware or to backup configurations) for the same protocol.

However, you can enforce use of HTTPS by setting the forcehttps attribute in the times tag to true. If so, a device calling in with HTTP will be re-configured to use HTTPS:

# using HTTP and 'forcehttps' is set -> need to switch to HTTPS

# changed state query args: polling, phase
# new url=

(note that if you are using a non-standard port for HTTPS, you must define it using the httpsport attribute).

Delivering Custom Certificates

innovaphone devices come with pre-defined, trustworthy device certificates. However, all soft devices (such as the softwarephone, myPBX for Android/iOS or the IPVA) do not. Also, in many scenarios customers run their own public key infrastructure (PKI) and request their own certificates to be used instead of the pre-defined. This is why there is a need to roll-out custom certificates to devices.

The update server supports this task to an extend. It can

  • check if a calling device has a proper certificate
  • instruct a calling device without proper certificate to create a certificate signing request (CSR)
  • download the CSR to the update server for easy access by the administrator
  • upload a signed CSR to the device
  • upload the public key(s) of the CA in to the device's trust list

In order to roll-out custom certificates with the update server, the administrator needs to

  • run his own PKI (a.k.a. certificate authority (CA))
  • monitor CSRs that appear in the update server's device list
  • approve the request by manually submitting it to his own CA
  • upload the signed CSR to the update server

Also, all devices must run V12r1 SR8 or newer before the new certificate can be uploaded. Devices with older firmware will be updated automatically (see #Delivering_Firmware_and_Boot_Code above). However, the new firmware must be V12r1 SR8 or later.

To learn how you can create proper device certificates with your own windows CA, see Howto:Creating custom Certificates using a Windows Certificate Authority.

By default, custom certificates are turned off and you will see a note like

# certificates: either certificate handling or state tracking not enabled - not doing any certificate checking

in the delivered update script.

Custom certificates are turned on by adding a customcerts tag to your user-config.xml:


The page that simulates your calling device will now include a line saying:

# certificates: we dont know anything about the current certificate state - not doing any certificate checking 

In order to decide if or if not a calling device has a valid certificate, the device needs to send its current public key to the update server. This is done by enabling queries in your user-config.xml. Queries is a means to have the device submit certain information to the update server. In the update server's default configuration, two queries are defined but not enabled:

  • the query certificates sends the current certificate state
  • the query admin sends the current device name (as set in General/Admin)

To enable a query, you must specify the class a calling device must be in in order to execute the query. This is done by adding an applies tag for the respective query in your configuration:

        <query id="admin">
        <query id="certificates">

This basically says that both queries should be executed by devices of just any class. Unless you enable queries, your update script will include lines such as:

# no queries defined for any of callers classes: phone+pre_opus_phone+phone_newui

Once you have enabled them, you will see something like

# query 'certificates'
mod cmd UP0 scfg ser nop /always mod%20cmd%20X509%20xml-info
# query 'admin'
mod cmd UP0 scfg ser nop /always mod%20cmd%20CMD0%20xml-info

You can display the data sent by a query in the device status display. To do so, you need to define one or more show tags as part of the respective query tag:

        <query id="certificates">
            <!-- show device certificate CNs and Issuer CNs in status page -->
            <show title="Subject">/state/queries/certificates/info/servercert/certificate/@subject_cn</show>
            <show title="Issuer">/state/queries/certificates/info/servercert/certificate/@issuer_cn</show>

Two steps however are still missing:

  • a) you need to tell the update server the names of all the CAs you consider trustworthy. This is done by listing their names in the CAname attribute of the customcerts tag:
        CAname="innovaphone Device Certification Authority,innovaphone Device Certification Authority 2,innovaphone-INNO-DC-W2K8-Zertifizierungsserver"
The example shown defines that you will accept both of innovaphone's device certificate authorities and also your own CA called innovaphone-INNO-DC-W2K8-Zertifizierungsserver. Devices with device certificates issued by one of these CAs will be left untouched. For all other devices (for example, any myPBX for Android/iOS device that has a self-signed certificate), the generation of a custom certificate will be initiated.
  • And b) you need to provide the public key of your CA (so it can be uploaded to the calling device's trust list). You need to place the DER (not PEM) encoded public key in to a file called certs/CAkey-01.cer on your update server (if you want to upload the whole certificate chain, put all of the public keys in the chain in to separate additional files called certs/CAkey-02.cer and so forth.

For more details on how to approve certificate signing requests, see #Approving Certificate Signing Requests below.

Enforcing Trust

Update script snippets may include sensitive information which you do not want to disclose to the public. Even though you can force the use of HTTPS (see above), this still does not keep your data secure. After all, an attacker could simply request an update script from your update server using HTTPS. To secure your data, you need to make sure that snippets are only sent to devices which identify themselves using a trusted certificate with a correct common name (CN). This is done using mutual transport layer security (MTLS). Therefore, you need to configure MTLS in the LAP (see If you want to setup MTLS-restricted Delivery of Update Scripts above).

You can enable this by setting forcetrust to true and httpsport to the port configured as MTLS Port in your web server. This is done in the times tag of your user-config.xml.


Please note that forcetrust does nothing unless forcehttps is also set!

If so, the update server will deliver update script snippets only to clients which identify themselves with a proper certificate. For this to work, you will need to add the public key of your certificate authority to your web server's list of trusted certificates.

When using the Linux Application Platform (LAP), you need to add the PEM-encoded public key of your certificate authority to the innovaphone-ca.pem file in /home/root/ssl_cert. When you have installed the LAP, this file will contain the PEM-encoded public keys of the 2 innovaphone device certificate authorities. You can simply add the public key of your CA to the end of this file:

...inno-ca public key...
...inno-ca2 public key...
...your-ca public key...

You will need to restart the LigHTTPD then (most easily done by restarting the entire LAP (Diagnose/Reset) or by issuing the command /etc/rc2.d/S02lighttpd restart from the linux root command prompt). Finally, you must set the forcetrust attribute. (Note that the innovaphone-ca.pem file may be overwritten when a new LAP version is installed. It is thus a good idea to keep a copy and check it after an upgrade).

When forcetrust is effective and the calling device does not use HTTPS, it will be reconfigured to do so:

# using HTTP and 'forcehttps' is set -> need to switch to HTTPS
# new url=

If the calling device uses HTTPS but sends no certificate, you will see a message like

# cannot verify CN with HTTPS: SSL_CLIENT_S_DN_CN not present - fix web server configuration or use MTLS-enabled port!

This is probably because it is using a non-MTLS enabled port for HTTPS (e.g. the standard port 443) although MTLS is configured for a different port.

If the calling device uses HTTPS and sends a certificate but the CN does not match the serial number of the device, you will see a message such as

# Device claims to be 'IP232-30-00-af' but identifies as 'CKL-CELSIUS-W10.innovaphone.sifi' by TLS

If the calling device uses HTTPS and sends a certificate but the certificate is not trusted because its issuer is not listed in innovaphone-ca.pem (see above), the connection will be refused

In all such cases, no snippet will be delivered. If the certificate is good, you will see a message like

# good certificate(CN='IP232-30-00-af')

followed by the appropriate snippets.

Using multiple Phases

When you configure multiple phases, all phases up to the final phase are stepped through and when all associated update script snippets for all phases are done, the device will ultimately stay in the final phase. This can be used e.g. to implement update script snippets which are executed once only when the device is initialized. Settings made in all but the last phase can later be overridden by the user or an administrator. The settings done in the update script settings for the final phase however are re-executed whenever one of your update script files for this phase changes. The process of deploying some initial settings is often called staging.

To enable staging, you therefore create a new phase that comes before the default phase (which is update). Phases are sorted numerical by an attribute called seq. As the default phase update is defined with seq=200, your new staging phase must be defined with a lower seq value:

	    <phase id="staging" seq="100"/>

When you define such a phase, there will be new possible update script snippet file names:

# phase: staging, nextphase: update, environment: default, type: IP232, classes: phone+pre_opus_phone+phone_newui
# possible files (from scripts):
# scripts/all-all-00_90_33_30_00_af.txt does not exist
# scripts/all-all-default.txt does not exist
# scripts/all-phone-00_90_33_30_00_af.txt does not exist
# scripts/all-phone-default.txt does not exist
# scripts/all-pre_opus_phone-00_90_33_30_00_af.txt does not exist
# scripts/all-pre_opus_phone-default.txt does not exist
# scripts/all-phone_newui-00_90_33_30_00_af.txt does not exist
# scripts/all-phone_newui-default.txt does not exist
# scripts/staging-all-00_90_33_30_00_af.txt does not exist
# scripts/staging-all-default.txt does not exist
# scripts/staging-phone-00_90_33_30_00_af.txt does not exist
# scripts/staging-phone-default.txt does not exist
# scripts/staging-pre_opus_phone-00_90_33_30_00_af.txt does not exist
# scripts/staging-pre_opus_phone-default.txt does not exist
# scripts/staging-phone_newui-00_90_33_30_00_af.txt does not exist
# scripts/staging-phone_newui-default.txt does not exist

First of all, there are new names for this particular phase. Furthermore, as we now have multiple phases, the new wild-card name all is possible.

An example for a staging script snippet might be a file called staging-all-all.txt:

# change admin password
config add CMD0 /user admin,my-admin-password
config activate
config rem CMD0 /user

This will set the admin password to my-admin-password during staging (it should be obvious that such staging should only be done in combination with Enforcing Trust, see above).

A complete user-config.xml Sample

Here is a complete sample of a configuration file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
<config debugmerge="true">
    <master info=""/>
	CAname="innovaphone Device Certification Authority,innovaphone Device Certification Authority 2"
	    <phase id="staging" seq="100"/>
        <environment id="intranet"/>
        <environment id='sifi'>
        <environment id='berlin'>
        <environment id='verona'>
        <environment id='homeoffice'/>
        <environment id='mobile'/>
        <query id="admin">
        <query id="certificates">
            <show title="Subject">/state/queries/certificates/info/servercert/certificate/@subject_cn</show>
            <show title="Issuer">/state/queries/certificates/info/servercert/certificate/@issuer_cn</show>


Configuring and Debugging a real Device

To configure your device for use with the update server, you simply set as Command File URL in Services/Update (you can optionally add a ?env=envname1,envname2 query argument if you want to set one or more specific environments for your device). The update server will re-configure the device later on so that it uses all the required query arguments.

Generally, there are the following methods to set the Command File URL

  • configure it manually using the admin GUI
  • provide it to the device using DHCP (this will however not work for the softwarephone or myPBX for Android/iOS)
  • use the innovaphone provisioning service (see Reference10:Concept Provisioning for details)

Once the Command File URL is set on the device, you can debug what the update client in the device does, using the normal trace mechanism. For this, you will want to open the Debug page (http://x.x.x.x/debug.xml) and set the Update/Polling and Update/Execution check-marks. When the update client queries the update server, you will see lines like

0:0826:465:5 - upd_poll: state IDLE -> RECV
0:0826:465:7 - IP.0 -> UPD-POLL.0 : SOCKET_GET_LOCAL_ADDR_RESULT(,,0,,ANY)
0:0826:466:0 - IP.0 -> UPD-POLL.0 : SOCKET_GET_LOCAL_ADDR_RESULT(,,0,,ANY)
0:0826:695:0 - upd_poll: state=RECV sent()
0:0826:752:0 - upd_poll: status 200 headercomplete=1 contentlength=0
0:0826:754:0 - upd_poll: recv_data(2199)
0:0826:754:1 - upd_poll: recv_data(0) EOF
0:0826:754:1 - upd_poll: GET EOF - state=RECV http-status=200 length=2199
0:0826:754:1 - upd_poll: do commands
0:0826:754:1 - upd_poll: state RECV -> EXEC

in the trace. Commands included in the update script will look like

0:0826:754:5 - script::get_line: >line(mod cmd UP0 scfg
0:0826:754:5 - upd_poll: pass 'mod cmd UP0 /sync scfg')

Finally, you do not need to wait for the next time the device decides to contact the update server. Instead, you can force this by sending an http://your-device-ip/!mod cmd UP1 poll to the device.

The Device Status Update Page

If status tracking is enabled (see Device Status above), the update server will keep a list of devices it knows of. You can see this list by calling

By default, the list will not be updated unless you refresh the page. However, if you set the refresh attribute in the status tag in your user-config.xml file to 60, all entries in this list will be refreshed every 60 seconds (however, the list itself will not be reloaded, so to see new devices, you need to refresh the entire page). Devices that have not been seen for more than 7 days are shown in a different colour. Devices that have not been seen for longer than 90 days will be silently removed from the list.


From build 2011, you can filter the devices shown using the device filter field in the Device column header. The filter string is matched against ip-address, serial number, type, name, phase, class, environment, firmware and bootcode. Also, you can filter by using the keywords present and missing (based on the missing attribute of the status tag in your configuration file). If one of these attributes match your filter expression, the device is shown.

A filter expression must match a complete word. For example, if you filter by 16 this would match the ip-address but it would not match

If you specify multiple filter expressions (separated by white space), only devices which match all of the expressions will be shown. For example, if you filter by 172.16. ip222 this might match all IP222 in your 172.16.*.* network. Filter expressions are case insensitive.

Approving Certificate Signing Requests

When you use custom certificate roll-out, you will see a column Certificates in the device status list, showing the devices certificate status.

PHP based Update Server V2 Device Status.png

If a CSR has been created on the device, this will be available for download in the Files section of the Info column. You can submit the CSR to your CA and then upload the signed request (using the Upload button in the Files section of the Info column). The signed request will eventually be uploaded to the device then. On the device itself, the CSR is shown in General/Certificates.

PHP based Update Server V2 CSR.png

Certificate Errors

When a signed certificate request uploaded to the device can not be installed on the device, you will see a message like Certificate upload error - certificate handling stopped in the Certificates columns for the device. In this case, any further processing will be stopped. Most likely, the reason is that you uploaded the wrong file as signed certificate request (either not a signed certificate at all or a signed request for another device).

In this case

  • remove any certificate request from the device
  • remove the X509/REQUESTERROR from the device configuration (i.e. vars del X509/REQUESTERROR)
these 2 steps can be easily done by resetting the device to factory defaults and then set the Update URL again
  • remove any stored files for the device on the update server (shown in the Certificates column)

The normal process will start all over again then.

Migrating old PHP Update Server Installations

Migrating from build 2000 and newer

  • Copy all files and folders, except the scripts and config folder, from the source to your destination
  • make sure all files and directories have correct owner (www-data), group (www-data) and mode (read/write plus execute for directories)
for example, in WinSCP you can use the Properties (F9) dialogue on the installations root folder:
PHP based Update Server V2-WinSCP-Properties.png
  • open the StatusPage and make sure you refresh all cached files in your browser (depending on your browser, this may happen with Ctrl-R or Ctrl-F5)

Migrating from build 1011 and older

To upgrade from the old version (builds up to 1011) of the PHP based update server (as described in Howto:PHP based Update Server), do the following

take note of all the changes you made to it
  • install the new version of the update server to a different URL
  • configure it according to your needs by modifying user-config.xml. Do not modify the new config.xml!
  • copy all your update script snippet files from the old server (these are all the .txt files in the old server's root directory) to the scripts directory of your new server
  • copy the complete fw tree from the old server to the fw directory of your new server
  • thoroughly test your new installation with some test devices
  • when satisfied, edit update-migrate.php and change the code as described in the comment inside the file
  • copy update-migrate.php from the new installation to the old installation
  • on one of the devices which are currently served by the old update server, change the Command File URL so that it points to update-migrate.php instead of update.php. Do not change anything else in the URL. So if it currently is set to e.g., change it to
  • verify that this device properly switches to your new installation
    • the Command File URL is changed so that it points to the new installation
    • the device shows up in the device status page of your new server
  • rename update.php to update-old.php in your old update server
  • rename update-migrate.php to update.php in your old update server
  • verify that all of your devices start showing up in the new server's status page

Complete Parameter Reference

Note: attributes are marked with an at (@) prefix. So master/@info refers to the info attribute in the master tag.

The following tags and attributes are available in the user-config.xml file, their default values are configured in config.xml (which you should not modify):


Defines the reference device where the firmware and boot code information is taken from.

the URL to the device info data. Set it to an URL like http://your-reference-device/CMD0/box_info.xml. Please note that this device must not have the Password protect all HTTP pages set in Services/HTTP/Server. If you use the literal none, the master device will not be queried
the firmware info cache lifetime. The firmware information is cached in a file (to make sure this information is present even if the reference device is off-line). The cache will not be refreshed before the expire time (in seconds) is expired
the cache file name. The web server must be able to write this file (see Installation above)
if non-empty, this is the user name required to access the update server's web ui
the password

From build 2009, you can control the firmware and bootcode version to use on update:

if set, it may be one of
master (default if not set) : the firmware version is derived from the master device
none : the firmware update is generally disabled
build-number : the firmware is set to a certain build-number regardless of the firmware running on the master device
if set, it may be one of
master (default if not set) : the bootcode version is derived from the master device
firmware : the bootcode version is set to the firmware version. This may be useful if the master device has no bootcode (e.g. the ipva)
none : the bootcode update is generally disabled
build-number : the bootcode is set to a certain build-number regardless of the bootcode running on the master device


Available from build 2009.

Boot code and firmware updates are only executed by devices which match all of the given <applies> conditions. A condition is met if the device belongs to the class that is given as tag content. If the env attribute is set, the tag content is interpreted as an environment name which has to match.

if this attribute exists, the tag content is compared with the environments the device is in. Otherwise, it is compared with the classes it is in
    <!-- applied to phones in berlin only -->
    <applies env="">berlin</applies>


Defines from where the device will retrieve the firmware files for updates.

defines the URL to retrieve the files from. In this URL, the following meta words will be replaced as follows:
  • {build} - the requested firmware or boot-code
  • {model} - the devices type (e.g. IP232). This is derived from the type query argument used in the update URL which is set to the value #t which in turn is expanded to the device type of the device requesting the update script
  • {filetype} - the type of the required file, either boot or prot
  • {filename} - (from build 2014) the boot code or firmware filename for the device in lower case. Required if you use the LAP as firmware storage and firmware files are falsely requested in uppercase letters (as URLs on the LAP are case sensitive and if the files are requested with upper case names, the original files with lowercase name are not found). This also allows you to use alternate firmware file names (such as e.g. ip110-sip.bin). See the filenames tag

Note that if the url ends with a slash (/), the calling device will automatically append the name of the requested file. In this case, the file system the URL points to must therefore contain sub-directories for each firmware build which contain the corresponding firmware builds (e.g, fw/12345/ip232.bin). If url is not an URL (as is the case for the default value fw/{build}/), it is treated as a sub-directory underneath the update server's root directory

    <fwstorage url="fw/{build}/"/>
Loading firmware files from

You can also load firmware from the web site. To do so, set url like so:

    <fwstorage url="{build}/"/>

Please note that this is a voluntary service, no guarantee of availability, no service level agreement.

ckl 15:40, 21 February 2023 (CET) This service has been discontinued. You may consider using{build}/ instead.


Defines where backup files are kept.

the directory underneath the script directory where backups are stored
the number of different backup files kept
the target URL for the scfg command. If this is not an url, it is interpreted relative to the script directory URL. You can add more options for the scfg command, like in scfg="update.php?mode=backup&hwid=#h&sn=#m ser hourly /force 1" (this example will make sure backups are attempted only once per hour, so as to reduce load on the server).


Defines details regarding the state kept for a device requesting an update script.

the directory the status files are kept in (e.g. status). Used as the name for a sub-directory underneath your install directory on your web server. You must make sure that files in this directory cannot be read by anyone without proper authentication, as such files may contain sensitive information.
if set and not empty, devices which have not requested an update script will be removed from the inventory after n seconds. For example, expire="7776000" will forget about devices after 90 days with no contact
devices are shown in a different colour (indicating that they are missing) after n seconds. For example, missing="604800" will flag devices as missing after 7 days with no contact
if set and not empty and larger than zero, the admin user interface showing the known devices will refresh the status of all shown devices each n seconds
number of seconds log messages for individual devices will be kept
if set to true, links to devices in the status page are created using the https:// scheme


Defines details regarding the delivery of update scripts to requesting devices.

the directory the update scripts are stored in. For security reasons, you may want to make sure that files in this directory cannot be read without proper authentication.

These attributes define the arguments of the times command. If neither allow nor initial is set, no times command is used (that is, the update scripts will be processed at all times).

the hours to be used in the times command (as in mod cmd UP1 times /allow hours)
the minutes to be used in the times command (as in mod cmd UP1 times /initial minutes). If you want to use initial staging of virgin devices forcestaging must be true.

Delivered update scripts can include a check command if the check attribute is set to true. . In this case, the devices will executed the scripts again only when you have edited/changed them.

if set to true, update scripts will be executed once only (unless their contents change)

When editing a number of update scripts, it is often not desirable if one changed script is already executed before another is changed too. When the grace attribute is set to a positive value, no script at all is delivered to requesting devices unless n seconds have expired since the last edit. For example, setting grace to 90 gives you one and a half minute to finish all your edits.

defines the number of seconds that must expire before update script changes take effect

The update server works in either fast or normal mode. In fast mode, update scripts have to be requested more frequently, for example to step through multiple staging phases faster. This is enforced by modifying the calling device's Interval setting in Services/Update and setting it to 1 in fast mode.

polling interval in minutes for normal operation (that is, when all staging is done)
when you are using multiple phases (e.g. staging and update), this defines the number of seconds to wait before the device reads the scripts for the next phase (see provision command) (please do not modify the default value)

In some installations it may be desired to deliver update scripts with HTTPS only or even only to calling devices which have identified themselves with a proper TLS certificate.

if set to true, update scripts will only be delivered if the device call in with HTTPS. If the device is ready to receive an update script and still calls in with HTTP only, its Command File URL will be re-configured to use HTTPS automatically.
if you use a non-standard port for HTTPS access to update scripts, it can be defined here
if your HTTPS URL differs from the HTTP URL, you can specifiy a modifier. It has the form !pattern!replacement! where pattern is a PHP PCRE pattern. For example, !mtls/!!i will remove the string mtls/ from the URL used by the device to create the HTTPS URL to use. The delimiter (in this case "!") can be changed according to your own wishes, the first character defines the delimiter. The "i" at the end ignores uppercase.

Note: If you want to change the hostname of your URL, you have to add the Port 444 to your hostname. The code should then look like this: !hostname1:444/mtls/!hostname2:444/!i.

if set to true, update scripts will only be delivered if the device call in with HTTPS and a valid and trusted client certificate that identifies itself as the devices it claims to be
before build 2009, the restrictions imposed by the times/@allow settings affected all update phases. This however makes staging cumbersome, as you usually want to restrict normal configuration changes to off-working-hours. If it is true, the restriction will be applied only to the last phase (that is, the staging phases will execute immediately). Also, the final phase will be executed once by staged devices.
Since build 2021 the standard value was changed to true.


Defines the scripting phases. In many installations, there are initializations which should be performed once only. This is known as the staging phase. Once this is done, the devices continue with the execution of the normal update scripts (this phase is known as update by default). In the (unlikely) event that you want more or less phases, you can add/remove phase tags.


the name for the phase
the sequential number for the phase. Phases are stepped-through in the numeric order defined by their seq attribute.

By virtue of the seq attribute, you can insert phases in to the set of phases defined by default, which is

        <!-- sequence is important! -->
        <phase id="staging" seq="100"/>
        <phase id="update" seq="200"/>

For example,

        <phase id="phase" seq="150"></phase>

will insert a custom phase myphase as second phase.


Defines the distinguished environments. Devices can have zero or more environments associated. The environments a device is considered to be in must be passed as ?env=name1,name2,.. URL query arg in the update url.

Update scripts for all environments listed will be applied. First the environment scripts itself, then all implied environments in the same order as the implies tags are listed in the config.

The default config file defines the environments intern and homeoffice but you can define your own if you like.


the name for the environment


Each environment may have a number of sub-tags of type implies. It contains the id of another environment. If a device is in an environment with an implies sub-tag, it is assumed that it is in the implied environment also.

        <environment id='hq'>
        <environment id='intranet'/>
        <environment id='homeoffice'/>

The implies tag handles no recursion (therefore, in the above example, if intranet would have an implies, a device in environment hq would not inherit this implication. Instead, you must list it explicitly for the hq environment).

If multiple environments will be used they will be applied also in the same order as the environment tags are listed in the config.

There are some special things to keep in mind when adding multiple environments in the env attribute and they use the implies tag in the config.
- The first environment specified in the arg env will be processed as expected with all children.
- Recursive implies from an environment added via implies is not performed. (No children's children)
- Only the first environment which is specified in the env arg with implies is processed, all additional values in the arg env will be ignored.
- If the environment in the arg env it is not the first value, then it must also use the implies config to implies itself. Otherwise only child are processed.


Defines the available device classes. Devices of different classes (e.g. phones and gateways) can have different update scripts. The device class is derived from the #t (device type) query arg of the update script URL (which is why you must configure it in the update URL). By default, the classes phone, opus_phone, pre_opus_phone, phone_oldui, phone_newui, mobile, gw, fxogw, fxsgw, brigw, prigw are recognized (newer versions may include more and/or updated class definitions). Also, any device is considered to be member of a class that has the device type as class-name. For example, an IP112 is in a class called ip112.

A given device can be in multiple classes and will execute all update scripts available for these classes.


Each class has a number of sub-tags of type model. It contains the value replaced for the #t query arg. The models listed belong to the class.

the name of the class
        <class id="gw">
        <class id="phone">
        <class id="phone_oldui">
        <class id="phone_newui">


Device types listed here do not receive boot code updates.


Each model tag defines a device type that shall not receive boot code updates.



Device types listed here do not receive firmware updates.


Each model tag defines a device type that shall not receive firmware updates.



Available from build 2014. Allows you to define alternate firmware and boocode names for use with the {filename} replacement (see the fwstorage tag), if required.


Each model defines a set of alternative file names for a certain device type.

the (lowercase) device type identfier (e.g. ip112). If this matches the device type of the calling device, the alternate file names are replaced
the alternate firmware file name
the alternate boot file name
        <model id="mypbxa" prot="mypbx.apk"/>

defines the firmware file name mypbx.apk for the device type mypbxa.


Better don't touch :-)


innovaphone hardware devices come with a device specific, trust-able device certificate. However, in many situations it is desirable to roll-out customer-created custom certificates to all devices. The update server can do this. This will replace the shipped devices certificates both on hardware devices (where all such certificates are derived from innovaphone's certificate authority) as well as on soft devices which run with a self.-signed certificate by default (such as the software-phone or myPBX for Android/iOS).

the name of the directory underneath your installation directory which stores device certificates. you should make sure that this directory cannot be accessed without proper authentication
a file name pattern (e.g. CAkey*). All files in customcerts/@dir which match the pattern must contain DER or PEM encoded public keys which form the certificate chain of your CA (usually it is only one and the public key of your CA). One key per file. The files, when sorted by name, must contain the CA key itself in the last file (any intermediate certificates, if any, in the other files in correct order)
must be manual currently
a comma-separated list of CA names. Devices presenting a certificate signed by one of these CAs will be considered as having a valid certificate. Otherwise, they wil be instructed to create a certificate signing request (CSR) for subsequent submission to your CA
defines the name separator for customcerts/@CAname. The default is ',' and you must change it to a different value if one of your CAs includes a comma in its name
if set and not 0, certificates are replaced by new ones n days before they expire
normally, the update server will accept a certificate only if its CN matches the device's serial number. However, sometimes, so-called wildcard certificates such as * are used on a device (e.g. on a PBX or on a reverse proxy). If set, the update server will also accept a certificate that contains a CN which equals the value of customcerts/@CAwildcard. Note that the CN must match literally. For example, if ''customcerts/@CAwildcard is set to * a CN like is not accepted

When the update server determines that a device calls in with an un-trusted or expired certificate, it will have it create a signing-request for a new certificate. The requested certificate properties can be defined:

the key size, e.g. 2048-bit. Note that we do not recommend keys larger than 2048 bit (see Reference7:Certificate_management#Certificate_Key_Length_and_CPU_Usage for details)
the signature algorithm, e.g. SH256
the CN (common name) part used for the DN
the OU (organizational unit) part used for the DN
the O (organization) part used for the DN
the L (locality) part used for the DN
the ST (state or province) part used for the DN
the C (country) part used for the DN (note: CSRdn for many CAs, must be a 2-letter ISO country code)
the first of up to three DNS names
the first of up to two IP addresses

Within the set of CSR attributes, the following meta-words will be replaced:

  • {realip} : the real IP address of the device as reported in the ip=#i query argument
  • {ip} : the IP address of the device as seen by the update server
  • {proxy} : the IP address of the reverse proxy the device used to reach the update server
  • {sn} : the serial number of the device as reported in the sn=#m query argument (e.g. 009033030df0)
  • {hwid} : the hardware-id of the device as reported in the sn=#m query argument (e.g. IP1200-03-0d-f0)
  • {name} : the Device Name (set in General/Admin) of the device
  • {rdns} : the DNS name found in a reverse DNS lookup for the real-ip address reported by the device (see {realip}) above
        renew="90" />


If queries are defined and applicable for the calling device, it will be instructed to send certain information to the update server which will be stored in the device status file kept on the server. Each piece of such information is defined using a separate query tag.

defines the URL used by the device to send the information. Normally not changed from the default


Defines one piece of information to be submitted to the update server.

a unique name for the query
a title for this piece of information shown in the device status
        <!-- retrieve and show some details from IP4/General/STUN page -->
        <query id="media" title="Media">
            <cmd>mod cmd MEDIA xml-info</cmd>
            <show title="NAT">concat(/state/queries/media/info/nat/@result, ' (', /state/queries/media/info/nat/@public-addr, ')')</show>
            <show title="Server">concat('STUN: ', /state/queries/media/info/@stun, ' TURN: ', /state/queries/media/info/@turn, ' (', /state/queries/media/info/@turn-user, ')')</show>

        <!-- show primary phone registration -->
        <query id="registration" title="Registration">
            <cmd>mod cmd PHONE/USER phone-regs /cmd phone-regs</cmd>
            <show title="State: User/Number">concat(/state/queries/registration/info/reg[@id = "0"]/@state, ': ' , /state/queries/registration/info/reg[@id = "0"]/@h323, '/', /state/queries/registration/info/reg[@id = "0"]/@e164)</show>
            <show title="PBX/ID">concat(/state/queries/registration/info/reg[@id = "0"]/@gk-addr, '/', /state/queries/registration/info/reg[@id = "0"]/@gk-id)</show>


The content of this tag defines the command to be executed on the device which outputs the requested information. These are mod cmds typically.

            <!-- get info for custom certificates -->
            <cmd>mod cmd X509 xml-info</cmd>

See Howto:Effect_arbitrary_Configuration_Changes_using_a_HTTP_Command_Line_Client_or_from_an_Update#Using_the_Mechanism_for_Device_Status_Queries for details on how to find out which commands to use.


Defined queries are only executed by devices which belong to the class that is given as tag content. If the env atribute is set, the tag content is interpreted as an environment name which has to match.

if this attribute exists, the tag content is compared with the environments the device is in. Otherwise, it is compared with the classes it is in (unfortunately, you can not combine both)
<!-- applied to phones only -->


If one or more show tags are defined for the query tag, the data will be shown in the device status page. The values shown are defined by the tag content which is an XPath expression selecting the data from the device state. The XPath expression always begins with /state/queries/query-id (as defined by the id attribute in the query tag).

used as title when the values are displayed in the status page
<show title="NAT">concat(/state/queries/media/info/nat/@result, ' (', /state/queries/media/info/nat/@public-addr, ')')</show>

Hints for writing your update snippets

Writing update scripts is largely undocumented and sometimes tricky. Here are some general guidelines.

Using config add/del

Many setting are done using config change commands. So these are very useful in update scripts too.

The straight forward method to find out which commands you need is as follows:

  • get a device of the type in question and do factory reset
  • save the configuration to a file
  • do the desired settings using the normal web admin UI
  • save the resulting configuration to another file
  • compare the saved files

Usually, you want to set only specific parts of the configuration line. For example, assume you want to set the default coder to OPUS-WB. Your saved configuration line might look like

config change PHONE SIG /prot SH323 /gk-addr /gk-id /tones 0 /lcoder OPUS-WB,20, /coder OPUS-WB,20,k1

To set only the coder settings, you would set the relevant options with the config add command as follows:

config add PHONE SIG /lcoder OPUS-WB,20,
config add PHONE SIG /coder OPUS-WB,20,k1

You can also remove specific options, as in

config rem PHONE SIG /tones

which would remove the /tones 0 from the configuration line for PHONE SIG.

Note that the PHP update server will add the

config write
config activate 

at the end of the delivered script automatically, so you do not need to do it yourself. In fact, it is not recommended to have any reset command in your snippets.

config change Lines with associated Passwords

Sometimes, there is a password associated with certain configurations. Consider the STUN/TURN configuration:

config change MEDIA /stun /turn /turn-user innovaphone /turn-pwd 2 /nat-detect 61

The TURN password, being sensitive, needs to be encrypted in your configuration. This is why it is stored as a VAR, which provides encryption support (see below):

vars create MEDIA/TURN-PWD pc ....

Unfortunately, the relationship between an option and an associated VAR needs to be guessed. You can be sure that the module name in the config change matches the modules name in the vars create command. However, the variable name must be guessed.

You can also set the password in your script using the vars create, however, you may also consider using a mod cmd (see below) such as e.g.

mod cmd MEDIA form /cmd form /del %2Fstun-slow /stun /turn /turn-user innovaphone /turn-pwd my-turn-pw /nat-detect 61

Using vars create

Sometimes it makes sense to use vars create commands. The syntax is

vars create <name> <flags> <value>

A <name> is a module name followed by a variable name, optionally followed by an index. For example, a phone will store the currently selected main registration as vars create PHONE/ACTIVE-USER p <index>. So the module is PHONE and the variable name is ACTIVE-USER. When the variable is multi-valued, an index is added to the name. For example, the registration settings for all but the first registration are stored as indexed variable, as in vars create PHONE/USER-REG/00001 p <settings>, where 00001 is the index (registrations count from 0 in this case).

There are a number of flags which can be combined, the most prominent used in update scripts are:

permanent. The var is stored in flash memory (you will almost always use this flag in update scripts)
crypted. The var value needs to be encrypted and the <value> given is crypted
crypted, plain value. The var needs to be encrypted but the <value> is given as plain (that is, un-encrypted) text. This allows you to set an encrypted variable without encrypting the desired value
binary. The var value is binary. Its <value> is given as a bin2hex string

Please note that using vars create will always set the internal reset needed condition in the device (regardless which <value> is set). This means that a subsequent resetn or iresetn will always trigger a reset. So if you use it, make sure that you use the times/@check ( see above) to protect your script from re-executing the snippet (and thus rebooting the device) all the time.

Using mod cmd

See Howto:Effect arbitrary Configuration Changes using a HTTP Command Line Client or from an Update for a discussion of how to use mod cmd in update scripts.

Writing your own Dynamic Scripting Code

NB: this feature is available from build 2020.

By default, the update server delivers update scripts which are composed from a number of static files (so-called snippets). Sometimes it makes sense however, to create such snippets dynamically (e.g. based on a database lookup). Here is how to do this.

Dynamic scripting is implemented by a user-supplied custom class CustomUpdateSnippet. The code for this class must be placed in to the file config/scripting.class.php. As a starter, sample class code is available in config/scripting.class-sample.php.


 * to provide your own runtime generated snippets, rename this file to 'scripting.class.php' and 
 * implement the member functions
 * $property will have one member called 

class CustomUpdateSnippet extends UpdateSnippet {

     * snippet to deliver after standard text snippets
     * @return array of string
    public function getPostSnippet() {
        return parent::getPostSnippet();

     * snippet to deliver before standard text snippets
     * @return array of strings
    public function getPreSnippet() {
        return parent::getPreSnippet();

     * do we want to suppress the standard text snippets?
     * @return boolean
    public function sendStandardSnippets() {
        return parent::sendStandardSnippets();

The sample code overrides of the classes member functions just call the base classes which do nothing at all. So if you just copy the sample code into scripting.class.php, nothing will change. However, if getPreSnippet() returns an array of strings (the parent class function returns an empty array), each array member will be sent to the calling device before the standard snippets are sent. Likewise, if getPostSnippet() returns an array of strings (the parent class function returns an empty array), each array member will be sent to the calling device after the standard snippets are sent. If sendStandardSnippets() returns false, the standard snippets will not be sent.

To determine the dynamic snippets to send, the user-provided class CustomUpdateSnippet has access to the members of its base class UpdateSnippet, namely the var $statexml member. This member contains a SimpleXMLElement object with all state information available for the calling device.

Here is a sample state found in $statexml (as output by the dump() member function):

<?xml version="1.0"?>
<state seen="1522065435" requested="130774bootcode" phase="update">
  <device sn="00-90-33-3e-0c-57" type="IP112" classes="phone, opus_phone, phone_newui, hstrace, ip112" ip="" rp="false" phase="update"
    environments="sifi, 172net" certstat="either certificate handling or state tracking not enabled - not doing any certificate checking" hwid="IP222-46-5c-77" realip="" requestDownloaded="false"/>
  <firmware requested="130986" requested-at="1522065435"/>
  <bootcode requested-at="1522065435"/>
  <config filename="scripts/all-all-all.txt" delivered="1522065426" version="1486559970"/>

The most interesting elements in this XML are probably the attributes of the state and the device tags.

Hints for using custom SSL Certificates

Using your own SSL certificates can be useful depending on the scenario.

We have two methods to accomplish this:

Standard scenario as described in this wiki article

The idea is that each certificate request is checked manually, edited and the UpdateServer is provided with the new device certificate.

Special scenario with automated certificate renewal

The idea is that every new/unknown (untrusted) device connects to the staging server. Here the device is released by manual checking/authorization by getting its first certificate. All further extensions can happen automatically afterwards.

Important: All important settings concerning file permissions, access and co must be used from the above article and are only skipped in this part!

We will create two Update-Server instances with the following configuration.

  1. Staging Server (HTTPS/443)
    • Put the sources in /var/www/innovaphone/update
    • Use your specific SSL configuration <customcerts> as described above.
    • Use the following settings in the configuration of <times>:
      force https = "true"
      httpsport = "444"
      force trust = "true"
      httpsurlmod = "!update/i!!"
    • Activate the query certificates as described above
    • Configure the firmware update via the master tag as described above
    • Important: Do not submit any further customer specific device configurations in the staging Server
  2. Final MTLS / 444 update server
    • Put the sources in /var/www/innovaphone/mts
    • Use your specific SSL configuration <customcerts> as described above with renew = "x"
    • Use the following settings in the configuration of <times>:
      force https = "true"
      httpsport = "444"
      force trust = "true"
      httpsurlmod = "!mtls/i!!"
    • Activate the query certificates as described above
    • Configure the firmware update via the master tag as described above
    • Store all customer specific device configurations

The meaning of the two different instances is:

  • The staging server https://[ip]/update/admin/admin.php will generate the provisioning URLs for new devices.
  • All new/unknown (untrusted) devices are only in the staging server.
    • Here you can check the devices and provide them a valid certificate after check/authorization.
  • With a valid certificate, the UpdateURL is automatically changed to the MTLS instance.
  • As soon as a device connects via MTLS we trust this device and we can use an automatic extension of the certificates.

Optional Configurations on the Linux Application Platform

Support for more Connections

By default the LAP's web server lighttpd allows for 512 concurrent connections with 1024 open file descriptors. When you serve a huge number of devices with the update server, then this might be too low. You will see some devices not being able to contact the update server for a while. This should not be a real issue as the devices will retry. However, updating all devices may take long due to this.

In the lighttpd log (in /var/log/lighttpd on the LAP), you will see entries like this:

2017-10-16 13:45:18: (network_linux_sendfile.c.140) open failed:  Too many open files 
2017-10-16 13:45:18: (mod_fastcgi.c.3075) write failed: Too many open files 24 
2017-10-16 13:45:18: (server.c.1434) [note] sockets disabled, out-of-fds 
2017-10-16 16:23:25: (response.c.634) file not found ... or so:  Too many open files /mtls/updatev2/web/innovaphone_logo_claim_fisch.png ->
2017-10-16 17:57:45: (server.c.1432) [note] sockets disabled, connection limit reached 

If you experience such issues, proceed as follows:

  • connect to the LAP with SFTP (e.g. using WinSCP)
  • change directory to /etc/lighttpd
  • edit lighttpd.conf
  • search for the 2 lines which set server.max-fds and server.max-connections
  • replace the standard values. We recommend to set the number of file descriptors to 4 times the number of requests when using the update server, e.g.
server.max-fds = 1024
server.max-connections = 512
server.max-fds = 8000
server.max-connections = 2000
  • save the file
  • restart linux (Diagnostics/Reset/Reboot)

Be sure to closely monitor the Diagnostics/Status page for a while after such configuration.

Also, when you update the LAP, you will have to re-do the changes (as always when you change something under the hood).

Debug files rotation based on logrotate

If you have to debug during operation and a lot of devices access the PHP Update Server V2, you have to keep track of the debug files or automatically limit them. For this you can use logrotate on the innovaphone Linux AP. With logrotate you can apply time-based or size-based rules when files are packed and when they are deleted.

  • open the LAP's file system using a SFTP client such as e.g. WinSCP (if you have not yet changed it, the default credentials will be root/iplinux, see Concept Linux Application Platform). Note that you must use SFTP rather than WebDAV, as WebDAV will not give access to the executable web server files.
  • Under the path /etc/logrotate.d create a file e.g. updateserver.


In this file now enter the following content and save it.

/var/www/innovaphone/mtls/update/debug/*.txt {
size 5M
rotate 2
create 644 www-data www-data

This will include all *.txt files from the debug directory of the PHP Update Server V2 in the logrotate process of the operating system.

size 5M
means every 5MB the file is rotated or zipped
size 5k
means every 5kB the file is rotated or zipped

Alternatively, you can also rotate the file based on time

means that every day the file is rotated or zipped
means that the file is rotated or zipped daily
if a debug file does not exist, it will be ignored
rotate n
files are removed before the last ones are deleted.
compresses the old debug files
compresses the debug data only after it has been moved once
empty log files are not rotated
create 644 www-data www-data
creates a new, empty debug file with appropriate permissions

Update Server and Reverse Proxy

It is possible to implement access to the update server through a reverse proxy (RP). However, you have to keep some issues in mind:

  • Mutual Transport Layer Security (MTLS) is not possible
MTLS requires a direct TLS connection between the two parties. An RP however would terminate the TLS connection and entertain two independent connections to the parties. This breaks MTLS. If you want to use MTLS and serve external clients, you must therefore provide a direct access to the update server (that is an external IP address either directly or through port forwarding)
see #If_you_want_to_setup_MTLS-restricted_Delivery_of_Update_Scripts for details
  • When using the RP, you can choose to forward encrypted traffic (HTTPS) arriving from external to the update server using HTTP (unencrypted). The update server however eventually rewrites the update URL in the calling devices configuration. In order to do this, it determines the type of the internal connection. So if the connection from the RP to the update server is using HTTP, it would create a http://... URL. Otherwise it would create an https://.. URL (also, it would be using the same port). This way, if the RP forwards requests to the update server with HTTP, the synthesized new URL for the calling client would use HTTP too, even though the original request was sent with HTTPS. This may or may not be what you want (as all of your clients would end up using non-encrypted traffic). Even worse, it might not work at all, if the RP does not accept HTTP for example.

Related Articles