User talk:Slu: Difference between revisions

From innovaphone wiki
Jump to navigation Jump to search
No edit summary
(clear)
Line 1: Line 1:
==Applies To==
This information applies to


* all innovaphone devices
* web server running PHP 5 (e.g. Linux Application Platform)
All Versions.
By default, the [[Reference10:Concept_Update_Server | Update Manager]] mechanism reads a file that corresponds to the device type (e.g. <code>update-ip222.htm</code>).  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==
=== Requirements ===
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 [[Reference10:Concept Linux Application Platform | 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!
=== Features ===
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
=== Installation ===
==== On the Linux Application Platform ====
Here is how you would install it on the [[Reference10:Concept_Linux_Application_Platform|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. [https://winscp.net/eng/index.php WinSCP] (if you have not yet changed it, the default credentials will be <code>root/iplinux</code>, see [[Reference10:Concept_Linux_Application_Platform#Default_Credentials | 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 <code>/var/www/innovaphone/mtls</code>, e.g. <code>/var/www/innovaphone/mtls/update</code>
* download the complete file package of scripts and files here: http://download.innovaphone.com/ice/wiki-src/
* copy all files and directories in to this new directory
* change owner and group of all files and directories to <code>www-data</code>, change mode to 0600 for all files and 0700 for all directories (see [[#Migrating_from_build_2000_an_newer | 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 <code>admin/linux</code>, see [[Reference10:Concept_Linux_Application_Platform#Default_Credentials | 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 <code>update</code>):
** <code>/mtls/update</code>
** <code>/mtls/update/web</code>
** <code>/mtls/update/admin</code>
** <code>/mtls/update/fw/</code> (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. <code>http://update.yourcompany.com/mtls/update/admin/admin.php</code>.  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 [http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?&page=8 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''.
<br/>
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).
<br/>
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. 
* For hints on using MTLS on an Apache Web Server, see [[Reference10:Concept_Provisioning#Enforcing_mutual_TLS_on_Apache | Enforcing mutual TLS on Apache]]
* For hints on getting the ''innovaphone device certificate authority'' public keys (which you may or may not need), see [[Reference10:Concept_Provisioning#How_to_get_inno-dev-ca-certificate.crt | How to get inno-dev-ca-certificate.crt ]]
==== 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
===Configuration===
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 <code>-----BEGIN CERTIFICATE-----</code>)
Also, you need to know the ''MTLS Port'' configured in your LAP (see [[#If_you_want_to_setup_MTLS-restricted_Delivery_of_Update_Scripts| If you want to setup MTLS-restricted Delivery of Update Scripts ]] above).
All tweakable parameters are set in <code>user-config.xml</code>.  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 <code>full-config.dtd</code>.
<code xml>
<?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">
</config>
</code>
The attributes of the <code>config</code> tag control some aspects of debugging.  For now, simply set all 3 to <code>"true"</code> instead of <code>"false"</code>.  Do not forget to revert them back to <code>"false"</code> 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'':
<code xml>
    <master ...  user="myadmin" password="mysecret"/>
</code>
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 <code>http://update.yourcompany.com/mtls/update/update.php?type=IP232&sn=00-90-33-00-00-00&hwid=IP232-00-00-00&ip=1.2.3.4</code> 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|''master'']] tag and leave everything else ''as is''. 
Remember that you do all your local configuration changes in <code>user-config.xml</code>.
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 <code>172.16.0.10</code>, you end up with
<code xml>
<?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="http://172.16.0.10/CMD0/box_info.xml"  user="myadmin" password="mysecret"/>
</config>
</code>
(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 [[Reference10:Concept_Update_Server#Prot_command | prot ]] and [[Reference10:Concept_Update_Server#Boot_command | boot ]] commands sent to the calling device:
...
# current firmware (unknown) does not match required firmware (130178)
mod cmd UP0 prot http://update.yourcompany.com/mtls/update/fw/130178/ ser 130178
# current boot code (unknown) does not match required boot code (130112)
mod cmd UP0 boot http://update.yourcompany.com/mtls/update/fw/130112/ ser 130112
...
By default, the URL generated points to a sub-directory of your update server called ''fw'': <code>http://update.yourcompany.com/mtls/update/fw/130178/</code>.  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
/var/www/innovaphone/mtls/update/fw
                                    /130178
                                          /ip232.bin
                                    /130112
                                          /boot232.bin
Note that the URL ends with a slash (<code>/</code>).  This instructs the calling device to append the appropriate file name itself when retrieving the file (see [[Reference10:Concept_Update_Server#Prot_command | the prot command ]] for details).
However, you can also specify any other URL by setting the ''url'' attribute in the ''fwstorage'' tag of your <code>user-config.xml</code>. In this attribute, certain meta words will be replaced (see [[#fwstorage | the ''fwstorage'' tag ]] for details).  The default setting for example is <code>fw/{build}/</code>.
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 <code>user-config.xml</code>.
* the device's environment (e.g. ''home-office'', ''branch-office'')
:  These reflect that 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 (<code>http://update.yourcompany.com/mtls/update/update.php?type=IP232&sn=00-90-33-00-00-00&hwid=IP232-00-00-00&ip=1.2.3.4</code>).  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 <code>update-</code> 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 <code>update-</code>. 
The next part here is either <code>phone-</code>, <code>pre_opus_phone-</code>, <code>phone_newui-</code> or <code>all-</code>.  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 <code>default</code> or <code>00_90_33_00_00_00</code> 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''<code>-</code>''class''<code>-</code>''environment''<code>.txt</code>) has to be <code>update-phone-default.txt</code> 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 <code>config add CMD0 /name This+is+a+Phone%21</code>, 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
iresetn
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 (<code>config write</code>), activate it (<code>config activate</code>) and trigger a reset if needed (<code>iresetn</code>).
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 <code>user-config.xml</code>.  So open the file and add the tag right next to the ''master'' tag you added before:
<code xml>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
<config>
    <master info="http://172.16.0.10/CMD0/box_info.xml"/>
    <status
        dir="status"
    />
</config>
</code>
When you have done so, please refresh the page that simulates your calling device and then open <code>http://update.yourcompany.com/mtls/update/admin/admin.php?mode=status</code>.  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 <code>user-config.xml</code>. Simply put it right next to the ''master'' or ''status'' tag you added before:
<code xml>
...
    <backup
        dir="backup"
    />
</code>
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 http://update.yourcompany.com/mtls/update/update.php?mode=backup&hwid=#h&sn=#m
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 [[Reference10:Concept_Update_Server#Times_command | 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 <code>user-config.xml</code>.
<code xml>
    <times
        allow="22,23,0,1,2,3,4"
        initial="1"/>
</code>
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 [[Reference10:Concept_Update_Server#Times_command | 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 [[Howto:PHP_based_Update_Server_V2#times | ''times'' ]] tag to <code>true</code>. 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=https://update.yourcompany.com/mtls/update/update.php?polling=5&phase=&type=#t&sn=#m&hwid=#h&ip=#i
...
(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 <code>user-config.xml</code>:
<code xml>
...
    <customcerts
dir="certs"
    />
...
</code>
The 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 <code>user-config.xml</code>.  ''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:
<code xml>
...
    <queries>
        <query id="admin">
            <applies>*</applies>
        </query>
        <query id="certificates">
            <applies>*</applies>
        </query>
    </queries>
...
</code>
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 https://update.yourcompany.com/mtls/update/update.php?mode=query&sn=#m&id=certificates ser nop /always mod%20cmd%20X509%20xml-info
# query 'admin'
mod cmd UP0 scfg https://update.yourcompany.com/mtls/update/update.php?mode=query&sn=#m&id=admin 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:
<code xml>
        ...
        <query id="certificates">
            <applies>*</applies>
            <!-- 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>
        </query>
        ...
</code>
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:
<code xml>
    ...
    <customcerts
        dir="certs"
        CAname="innovaphone Device Certification Authority,innovaphone Device Certification Authority 2,innovaphone-INNO-DC-W2K8-Zertifizierungsserver"
    />
    ...
</code>
: 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 <code>certs/CAkey-01.cer</code> 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 <code>certs/CAkey-02.cer</code> 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 | If you want to setup MTLS-restricted Delivery of Update Scripts]] above).
You can enable this by setting ''forcetrust'' to <code>true</code> and ''httpsport'' to the port configured as ''MTLS Port'' in your web server.  This is done in the ''times'' tag of your <code>user-config.xml</code>.
<code xml>
    <times
        ...
        forcehttps="true"
        httpsport="444"
        forcetrust="true"
    />
</code>
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 <code>/home/root/ssl_cert</code>.  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:
-----BEGIN CERTIFICATE-----
...inno-ca public key...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...inno-ca2 public key...
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...your-ca public key...
-----END CERTIFICATE-----
You will need to restart the LigHTTPD then (most easily done by restarting the entire LAP (''Diagnose/Reset'') or by issuing the command <code>/etc/rc2.d/S02lighttpd restart</code> 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=https://update.yourcompany.com:444/update/update.php?polling=5&phase=&type=#t&sn=#m&hwid=#h&ip=#i&env=default
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:
<code xml>
    ...
    <phases>
    <phase id="staging" seq="100"/>
    </phases>
    ...
</code>
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 <code>staging-all-all.txt</code>:
# change admin password
config add CMD0 /user admin,my-admin-password
config activate
config rem CMD0 /user
This will set the admin password to <code>my-admin-password</code> during staging (it should be obvious that such staging should only be done in combination with [[#Enforcing_Trust|Enforcing Trust]], see above).
=== A complete <code>user-config.xml</code> Sample ===
Here is a complete sample of a configuration file.
<code xml>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE config SYSTEM "full-config.dtd">
<!-- add your local configuration here -->
<config debugmerge="true">
    <master info="http://172.16.0.10/CMD0/box_info.xml"/>
    <status
    dir="status"
    missing="1000"
    />
    <backup
        dir="backup"
    />
    <times
        allow="22,23,0,1,2,3,4"
        initial="1"
        forcehttps="true"
httpsport="444"
        forcetrust="true"
    />
    <customcerts
        dir="certs"
CAname="innovaphone Device Certification Authority,innovaphone Device Certification Authority 2"
        CSRsan-dns-1="{name}.company.com"
        CSRsan-dns-2="{hwid}.company.com"
        CSRsan-dns-3="{rdns}"
        CSRsan-ip-1="{realip}"
/>
    <phases>
    <phase id="staging" seq="100"/>
    </phases>
    <environments>
        <environment id="intranet"/>
        <environment id='sifi'>
<implies>intranet</implies>
</environment>
        <environment id='berlin'>
<implies>intranet</implies>
</environment>
        <environment id='verona'>
<implies>intranet</implies>
</environment>
        <environment id='homeoffice'/>
        <environment id='mobile'/>
  </environments
    <queries>
        <query id="admin">
            <applies>*</applies>
        </query>
        <query id="certificates">
            <applies>*</applies>
            <show title="Subject">/state/queries/certificates/info/servercert/certificate/@subject_cn</show>
            <show title="Issuer">/state/queries/certificates/info/servercert/certificate/@issuer_cn</show>
        </query>
    </queries>
</config>
</code>
=== Operation ===
==== Configuring and Debugging a real Device ====
To configure your device for use with the update server, you simply set <code>http://update.yourcompany.com/mtls/update/update.php</code> as ''Command File URL'' in ''Services/Update'' (you can optionally add a <code>?env=envname1,envname2</code> 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|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 (<code>http://x.x.x.x/debug.xml</code>) 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(172.16.100.201,255.255.0.0,0,'',ANY)
0:0826:466:0 - IP.0 -> UPD-POLL.0 : SOCKET_GET_LOCAL_ADDR_RESULT(172.16.100.201,255.255.0.0,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 https://update.yourcompany.com/mtls/update/update.php?mode=backup&hwid=#h&sn=#m)
0:0826:754:5 - upd_poll: pass 'mod cmd UP0 /sync scfg https://update.yourcompany.com/mtls/update/update.php?mode=backup&hwid=#h&sn=#m')
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 <code>http://</code>''your-device-ip<code>/!mod cmd UP1 poll</code> to the device.
==== The Device Status Update Page ====
If status tracking is enabled (see [[#Device_Status | Device Status]] above), the update server will keep a list of devices it knows of.  You can see this list by calling <code>http://update.yourcompany.com/mtls/update/admin/admin.php?mode=status</code>.
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 ''use-config.xml'' file to <code>60</code>, all entries in this list will be refreshed every 60 seconds (however, the list itself will not be reloaded, so to see new devices, your 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.
===== Filtering =====
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 <code>16</code> this would match the ip-address <code>172.</code>16<code>.0.20</code> but it would not match <code>192.</code>16<code>8.0.1</code>.
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 <code>172.16. ip222</code> 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. 
[[Image: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''.
[[Image: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 <code>Certificate upload error - certificate handling stopped</code> 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 <code>X509/REQUESTERROR</code> from the device configuration (i.e. <code>vars del X509/REQUESTERROR</code>)
: 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:
: [[Image: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 [http://download.innovaphone.com/ice/wiki-src/index.php?urloffset=php-update-server%2F&name=php-update-server+%28all+available+builds%29&reverselevel=0&maxbuilds=999&root=c%3A%2Finetpub%2Fwwwroot%2Fdownload%2Fice%2Fdownload%2Fp%2Fwiki-src%2Fphp-update-server%2F1010+%28PHP+based+Update+Server+final%29%2F.. old version (builds up to 1011)] of the PHP based update server (as described in [[Howto:PHP based Update Server]]), do the following
* diff your <code>config.xml</code> to the one originally shipped (you can download it at [http://download.innovaphone.com/ice/download/p/wiki-src/php-update-server/1011%20(PHP%20based%20Update%20Server%20final)/php-update-server-1011.zip download.innovaphone.com/ice/wiki-src])
: 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 <code>user-config.xml</code>.  Do not modify the new <code>config.xml</code>!
** apply all modifications you did to your old <code>config.xml</code> to your new <code>user-config.xml</code>
** if you have used a custom setting for fwstorage/@url, you need to change it a bit.  Change for example <code>url="http://myfwserver.mycompany.com</code> to <code>http://myfwserver.mycompany.com/{build}/</code> (note the trailing slash!)
* 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 <code>scripts</code> directory of your new server
* copy the complete <code>fw</code> tree from the old server to the <code>fw</code> directory of your new server
* thoroughly test your new installation with some test devices
* when satisfied, edit <code>update-migrate.php</code> and change the code as described in the comment inside the file
* copy <code>update-migrate.php</code> 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 <code>update-migrate.php</code> instead of <code>update.php</code>.  Do not change anything else in the URL. So if it currently is set to e.g.
: <code>https://172.16.0.90/update/update.php?type=#t&env=sifi&polling=0&phase=update</code>, change it to
: <code>https://172.16.0.90/update/update-migrate.php?type=#t&env=sifi&polling=0&phase=update</code>
* 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 <code>update.php</code> to <code>update-old.php</code> in your old update server
* rename <code>update-migrate.php</code> to <code>update.php</code> 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'' (<code>@</code>) prefix.  So ''master/@info'' refers to the ''info'' attribute in the ''master'' tag.
The following tags and attributes are available in the <code>user-config.xml</code> file, their default values are configured in <code>config.xml</code> (which you should not modify):
==== master ====
Defines the reference device where the firmware and boot code information is taken from.
; master/@info : the URL to the device info data.  Set it to an URL like <code>http://</code>''your-reference-device''<code>/CMD0/box_info.xml</code>. Please note that this device must not have the ''Password protect all HTTP pages'' set in ''Services/HTTP/Server''.  If you use the literal <code>none</code>, the master device will not be queried
; master/@expire : 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
; master/@cache : the cache file name.  The web server must be able to write this file (see [[#Installation | ''Installation'' ]] above)
; master/@user : if non-empty, this is the user name required to access the update server's web ui
; master/@password : the password
From build 2009, you can control the firmware and bootcode version to use on update:
; master/@firmware : if set, it may be one of
:: <code>master</code> (default if not set) : the firmware version is derived from the master device
:: <code>none</code> : 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
; master/@bootcode: if set, it may be one of
:: <code>master</code> (default if not set) : the bootcode version is derived from the master device
:: <code>firmware</code> : the bootcode version is set to the firmware version. This may be useful if the master device has no bootcode (e.g. the ipva)
:: <code>none</code> : 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
<code xml>
    <master
        info="http://172.16.0.10/CMD0/box_info.xml"
        expire="3600"
        cache="cache/master-info.xml"
        user="myadmin"
        password="mysecret"
        firmware="4711"
        bootcode="firmware"
    />
</code>
==== master/applies ====
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.
; master/applies/@env : 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
<code xml>
<master
    info="http://172.16.0.10/CMD0/box_info.xml"
    expire="3600"
    cache="cache/master-info.xml"
    user="myadmin"
    password="mysecret"
    firmware="4711"
    bootcode="firmware">
    <!-- applied to phones in berlin only -->
    <applies>phone</applies>
    <applies env="">berlin</applies>
</master>
</code>
==== fwstorage ====
Defines from where the device will retrieve the firmware files for updates.
; fwstorage/@url :  defines the URL to retrieve the files from.  In this URL, the following meta words will be replaced as follows:
:* <code>{build}</code> - the requested firmware or boot-code
:* <code>{model}</code> - the devices type (e.g. <code>IP232</code>).  This is derived from the ''type'' query argument used in the update URL which is set to the value <code>#t</code> which in turn is expanded to the [[Reference10:Concept_Update_Server#Scfg_command|''device type'']] of the device requesting the update script
:* <code>{filetype}</code> - the type of the required file, either <code>boot</code> or <code>prot</code>
:* <code>{filename}</code> - (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. <code>ip110-sip.bin</code>).  See the ''filenames'' tag
Note that if the ''url'' ends with a slash (<code>/</code>), the calling device will automatically [[Reference10:Concept_Update_Server#Prot_command|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 <code>fw/{build}/</code>), it is treated as a sub-directory underneath the update server's root directory
<code xml>
    <fwstorage url="fw/{build}/"/>
</code>
===== Loading firmware files from innovaphone.com =====
You can also load firmware from the innovaphone.com web site.  To do so, set ''url'' like so:
<code xml>
    <fwstorage url="http://webbuild.innovaphone.com/{build}/"/>
</code>
Please note that ''this is a voluntary service, no guarantee of availability, no service level agreement''.
==== backup ====
Defines where backup files are kept.
; backup/@dir :  the directory underneath the script directory where backups are stored
; backup/@nbackups :  the number of different backup files kept
; backup/@scfg :  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 <code>scfg="update.php?mode=backup&amp;hwid=#h&amp;sn=#m ser hourly /force 1"</code> (this example will make sure backups are attempted only once per hour, so as to reduce load on the server).
<code xml>
    <backup
        dir="backup"
        nbackups="10"
        scfg="update.php?mode=backup&amp;hwid=#h&amp;sn=#m"
    />
</code>
==== status ====
Defines details regarding the state kept for a device requesting an update script.
; status/@dir : the directory the status files are kept in (e.g. <code>status</code>).  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.
; status/@expire : 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
; status/@missing : 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
; status/@refresh : 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
; status/@logkeep : number of seconds log messages for individual devices will be kept
; status/usehttpsdevlinks : if set to true, links to devices in the status page are created using the https:// scheme
<code xml>
    <status
        dir="status"
        expire="7776000"
        missing="200"
        refresh="10"
        logkeep="90"
        usehttpsdevlinks="true"
    />
</code>
==== times ====
Defines details regarding the delivery of update scripts to requesting devices.
; times/@dir : 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 [[Reference10:Concept_Update_Server#Times_command | 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).
; times/@allow :  the hours to be used in the ''times'' command (as in <code>mod cmd UP1 times /allow </code>''hours'')
; times/@initial :  the minutes to be used in the ''times'' command (as in <code>mod cmd UP1 times /initial </code>''minutes'')
Delivered update scripts can include a [[Reference10:Concept_Update_Server#Check_command | check command ]] if the ''check'' attribute is set to <code>true</code>.  . In this case, the devices will executed the scripts again only when you have edited/changed them.
; times/@check :  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.
; times/@grace :  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 [[Reference11r1:Services/Update | ''Services/Update '']] and setting it to 1 in ''fast'' mode.
; times/@interval :  polling interval in minutes for normal operation (that is, when all staging s done)
; times/@polling :  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 [[Reference10:Concept_Update_Server#Provision_command | 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. 
; times/@forcehttps : if set to <code>true</code>, 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.
; times/@httpsport : if you use a non-standard port for HTTPS access to update scripts, it can be defined here
; times/@httpsurlmod : if your HTTPS URL differs from the HTTP URL, you can specifiy a ''modifier''.  It has the form <code>!</code>''pattern''<code>!</code>''replacement''<code>!</code> where ''pattern'' is a [http://docs.php.net/manual/en/pcre.pattern.php PHP PCRE pattern]. For example, <code>!mtls/!!i</code> will remove the string <code>mtls/</code> 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: <code>!hostname1:444/mtls/!hostname2:444/!i</code>.
; times/@forcetrust : if set to <code>true</code>, 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
; times/@forcestaging : 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.  Now you can set the ''forcestaging'' attribute to <code>true</code>.  If so, 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.
<code xml>
    <times
        dir="scripts"
        allow=""
        initial=""
        check="true"
        polling="5"
        interval="15"
        grace="90"
        forcehttps="true"
        httpsport="444"
        forcetrust="false"
        httpsurlmod="!mtls/!!i"
        forcestaging="true"
/>
</code>
==== phases ====
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.
==== phases/phase ====
; phases/phase/@id :  the name for the phase
; phases/phase/@seq:  the sequential number for the phase. Phases are stepped-through in the numeric order defined by their ''seq'' atribute.
By virtue if the ''seq'' attribute, you can insert phases in to the set of phases defined by default, which is
<code xml>
    <phases>
        <!-- sequence is important! -->
        <phase id="staging" seq="100"/>
        <phase id="update" seq="200"/>
    </phases>
</code>
For example,
<code xml>
    <phases>
        <phase id="phase" seq="150"></phase>
    </phases>
</code>
will insert a custom phase ''myphase'' as second phase.
==== environments ====
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 <code>?env=</code>''name1,name2,..'' URL query arg in the update url.  Update scripts for all environments listed will be applied. The default config file defines the environments ''intern'' and ''homeoffice'' but you can define your own if you like.
==== environments/environment ====
; environments/environment/@id :  the name for the environment
==== environments/environment/implies ====
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.
<code xml>
    <environments>
        <environment id='hq'>
            <implies>intranet</implies>
        </environment>
        <environment id='intranet'/>
        <environment id='homeoffice'/>
    </environments>
</code>
==== classes ====
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 <code>#t</code> (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.
==== classes/class ====
Each ''class'' has a number of sub-tags of type ''model''. It contains the value replaced for the <code>#t</code> query arg.  The models listed belong to the class.
; classes/class/@id :  the name of the class
<code xml>
    <classes>
        <class id="gw">
            <model>ip0010</model>
            ...
        </class>
        <class id="phone">
            <model>ip110</model>
            <model>ip232</model>
            ...
        </class>
        <class id="phone_oldui">
            <model>ip110</model>
            ...
        </class>
        <class id="phone_newui">
            <model>ip232</model>
            ...
        </class>
    </classes>
</code>
==== nobootdev ====
Device types listed here do not receive boot code updates.
===== nobootdev/model =====
Each model tag defines a device type that shall not receive boot code updates.
<code xml>
    <nobootdev>
        <model>ipva</model>
        <model>ipvadec</model>
        <model>swphone</model>
        <model>mypbxa</model>
        <model>mypbxi</model>
    </nobootdev>
</code>
==== nofirmdev ====
Device types listed here do not receive firmware updates.
===== nobootdev/model =====
Each model tag defines a device type that shall not receive firmware updates.
<code xml>
    <nofirmdev>
        <model>swphone</model>
        <model>mypbxi</model>
    </nofirmdev>
</code>
==== filenames ====
Available from build 2014. Allows you to define alternate firmware and boocode names for use with the <code>{filename}</code> replacement (see the ''fwstorage'' tag), if required.
===== filenames/model =====
Each mode defines a set of alternative file names for a certain device type.
; filenames/model/@id : the (lowercase) device type identfier (e.g. <code>ip112</code>). If this matches the device type of the calling device, the alternate file names are replaced
; filenames/model/@prot: the alternate firmware file name
; filenames/model/@boot: the alternate boot file name
<code xml>
    <filenames>
        <model id="mypbxa" prot="mypbx.apk"/>
    </filenames>
</code>
defines the firmware file name <code>mypbx.apk</code> for the device type <code>mypbxa</code>.
==== stdargs ====
Better don't touch :-)
==== customcerts ====
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'').
; customcerts/@dir : 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
; customcerts/@CAkeys : a file name pattern (e.g. <code>CAkey*</code>).  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)
; customcerts/@CAtype : must be <code>manual</code> currently
; customcerts/@CAname : 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
; customcerts/@CAnamesep : defines the name separator for ''customcerts/@CAname''.  The default is '<code>,</code>' and you must change it to a different value if one of your CAs includes a comma in its name
; customcerts/@renew : if set and not 0, certificates are replaced by new ones ''n'' days before they expire
; customcerts/@CAwildcard : 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 <code>*.innovaphone.com</code> 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 <code>*.innovaphone.com</code> a CN like <code>host.innovaphone.com</code> 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:
; customcerts/@CSRkey : the key size, e.g. <code>2048-bit</code>. Note that we do not recommend keys larger than 2048 bit (see [[Reference7:Certificate_management#Certificate_Key_Length_and_CPU_Usage]] for details)
; customcerts/@CSRsignature : the signature algorithm, e.g. <code>SH256</code>
; customcerts/@CSRdn-cn : the CN (''common name'') part used for the DN
; customcerts/@CSRdn-ou : the OU (''organizational unit'') part used for the DN
; customcerts/@CSRdn-o : the O (''organization'') part used for the DN
; customcerts/@CSRdn-l : the L (''locality'') part used for the DN
; customcerts/@CSRdn-st : the ST (''state or province'') part used for the DN
; customcerts/@CSRdn-c : the C (''country'') part used for the DN (note: ''CSRdn'' for many CAs, must be a 2-letter ISO country code)
; customcerts/@CSRsan-dns-1 : the first of up to three DNS names
; customcerts/@CSRsan-ip-1 : the first of up to two IP addresses
Within the set of CSR attributes, the following meta-words will be replaced:
* <code>{realip}</code> : the real IP address of the device as reported in the <code>ip=#i</code> query argument
* <code>{ip}</code> : the IP address of the device as seen by the update server
* <code>{proxy}</code> : the IP address of the reverse proxy the device used to reach the update server
* <code>{sn}</code> : the serial number of the device as reported in the <code>sn=#m</code> query argument (e.g. <code>009033030df0</code>)
* <code>{hwid}</code> : the hardware-id of the device as reported in the <code>sn=#m</code> query argument (e.g. <code>IP1200-03-0d-f0</code>)
* <code>{name}</code> : the ''Device Name'' (set in ''General/Admin'') of the device
* <code>{rdns}</code> : the DNS name found in a reverse DNS lookup for the real-ip address reported by the device (see ''{realip}'') above
<code xml>
    <customcerts
        dir="certs"
        CAkeys="CAkey*"
        CAtype="manual"
        CAname="innovaphone-INNO-DC-W2K8-Zertifizierungsserver"
        CAnamesep=","
        CAwildcard="*.innovaphone.com"
        CSRkey="2048-bit"
        CSRsignature="SH256"
        CSRdn-cn="{hwid}"
        CSRdn-ou=""
        CSRdn-o=""
        CSRdn-l=""
        CSRdn-st=""
        CSRdn-c=""
        CSRsan-dns-1="{name}.company.com"
        CSRsan-dns-2="{hwid}.company.com"
        CSRsan-dns-3="{rdns}"
        CSRsan-ip-1="{realip}"
        CSRsan-ip-2=""
        renew="90" />
</code>
==== queries ====
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 usign a separate ''query'' tag.
; queries/@scfg : defines to URL used by the device to send the information.  Normally not changed from the default
==== queries/query ====
Defines one piece of information to be submitted to the update server.
; queries/query/@id : a unique name for the query
; queries/query/@title : a title for this piece of information shown in the device status
<code xml>.
        <!-- retrieve and show some details from IP4/General/STUN page -->
        <query id="media" title="Media">
            <cmd>mod cmd MEDIA xml-info</cmd>
            <applies>*</applies>
            <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>
        </query>
        <!-- show primary phone registration -->
        <query id="registration" title="Registration">
            <cmd>mod cmd PHONE/USER phone-regs /cmd phone-regs</cmd>
            <applies>phone</applies>
            <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>
        </query>
</code>
==== queries/query/cmd ====
The content of this tag defines the command to be executed on the device which outputs the requested information. These are ''mod cmd''s typically.
<code xml>
            <!-- get info for custom certificates -->
            <cmd>mod cmd X509 xml-info</cmd>
</code>
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 whicgh commands to use.
==== queries/query/applies ====
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.
; queries/query/applies/@env : 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 bith)
<code xml>
<!-- applied to phones only -->
<applies>phone</applies>
</code>
==== queries/query/show====
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 <code>/state/queries/</code>''query-id'' (as defined by the ''id'' attribute in the query tag). 
; queries/query/show/@title : used as title when the values are displayed in the status page
<code xml>
<show title="NAT">concat(/state/queries/media/info/nat/@result, ' (', /state/queries/media/info/nat/@public-addr, ')')</show>
</code>
== Download ==
*[http://download.innovaphone.com/ice/wiki-src#php-update-server http://download.innovaphone.com/ice/wiki-src/] - download the complete file package of scripts and files described in this article
: you need to use build 2000 or higher.  Older versions are described in [[Howto:PHP_based_Update_Server]]
== Hints for writing your update snippets ==
Writing update scripts is largely undocumented and sometimes tricky.  Here are some general guidelines.
=== Using <code>config add/del</code> ===
Many setting are done using <code>config change</code> 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 pbx.innovaphone.com /gk-id innovaphone.com /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 <code>config add</code> 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 <code>/tones 0</code> from the configuration line for <code>PHONE SIG</code>.
Note that the PHP update server will add the
config write
config activate
iresetn
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.
==== <code>config change</code> Lines with associated Passwords ====
Sometimes, there is a password associated with certain configurations.  Consider the STUN/TURN configuration:
config change MEDIA /stun stun.innovaphone.com /turn turn.innovaphone.com /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 <code>config changey</code> matches the modules name in the <code>vars create</code> command. However, the variable name mist be guessed.
You can also set the password in your script using the <code>vars create</code><!-- , but this does make sense only in staging (that is pre-update-phase) scripts (see below for a discussion why). If you need to do it in a script snippet for the update phase, you should -->, however, you may also consider using a <code>mod cmd</code> (see below) such as e.g.
mod cmd MEDIA form /cmd form /del %2Fstun-slow /stun stun.innovaphone.com /turn turn.innovaphone.com /turn-user innovaphone /turn-pwd my-turn-pw /nat-detect 61
=== Using <code>vars create</code> ===
Sometimes it makes sense to use <code>vars create</code> commands.  The syntax is
<code> vars create </code>''<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 <code>vars create PHONE/ACTIVE-USER p </code>''<index>''.  So the module is <code>PHONE</code> and the variable name is <code>ACTIVE-USER</code>.  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 <code>vars create PHONE/USER-REG/00001 p </code>''<settings>'', where <code>00001</code> 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:
; p : permanent.  The var is stored in flash memory (you will almost always use this flag in update scripts)
; c : crypted.  The var value needs to be encrypted and the ''<value>'' given is crypted
; x : 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
; b : binary. The var value is binary.  Its ''<value>'' is given as a bin2hex string
Please note that using <code>vars create</code> will ''always'' set the internal ''reset needed condition'' in the device (regardless which ''<value>'' is set).  This means that a subsequent <code>resetn</code> or <code>iresetn</code> will always trigger a reset.  So if you use it, make sure that you use the ''times/@check'' ([[#times | see above]]) to protect your script from re-executing the snippet (and thus rebooting the device) all the time.
<!--
When you use a <code>mod cmd UP1 check ...</code> command in your script (see times/@check [[#times | above]]), this will create an endless loop if you use <code>vars create</code> followed by one of the <code>resetn</code> commands in the code guarded by the <code>check</code> command. This code will never be fully executed, as the ''reset needed'' condition will always be set and the reset will always happen.  You can use it in ''pre-update-phase'' scripts (that is, during the staging process) as this is not protected by a <code>check</code> command.
-->
=== Using <code>mod cmd</code> ===
See [[Howto:Effect arbitrary Configuration Changes using a HTTP Command Line Client or from an Update]] for a discussion of how to use <code>mod cmd</code> 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 <code>class CustomUpdateSnippet</code>.  The code for this class must be placed in to the file <code>config/scripting.class.php</code>.  As a starter, sample class code is available in <code>config/sample.scripting.class.php</code>.
<code php>
<?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();
    }
}
?>
</code>
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 <code>scripting.class.php</code>, nothing will change.  However, if <code>getPreSnippet()</code> 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 <code>getPostSnippet()</code> 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 <code>sendStandardSnippets()</code> returns false, the standard snippets will not be sent.
To determine the dynamic snippets to send, the user-provided <code>class CustomUpdateSnippet</code> has access to the members of its base <code>class UpdateSnippet</code>, namely the <code>var $statexml</code> member. This member contains a <code>SimpleXMLElement</code> object with all state information available for the calling device.
Here is a sample state found in <code>$statexml</code> (as output by the <code>dump()</code> member function):
<code xml>
<?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="127.0.0.1" 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="172.16.80.241" requestDownloaded="false"/>
  <firmware requested="130986" requested-at="1522065435"/>
  <bootcode requested-at="1522065435"/>
  <config filename="scripts/all-all-all.txt" delivered="1522065426" version="1486559970"/>
</state>
</code>
The most interesting elements in this XML are probably the attributes of the <code>state</code> and the <code>device</code> tags.
== 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 <code>/var/log/lighttpd</code> 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 <code>/etc/lighttpd</code>
* edit <code>lighttpd.conf</code>
* search for the 2 lines which set <code>server.max-fds</code> and <code>server.max-connections</code>
* 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.
: old
:: server.max-fds            = 1024
:: server.max-connections    =  512
: new
:: 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. [https://winscp.net/eng/index.php WinSCP] (if you have not yet changed it, the default credentials will be <code>root/iplinux</code>, see [[Reference10:Concept_Linux_Application_Platform#Default_Credentials | 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 <code>/etc/logrotate.d</code> create a file e.g. <code>updateserver</code>.
<code>/etc/logrotate.d/updateserver</code>
In this file now enter the following content and save it.
<code>
/var/www/innovaphone/mtls/update/debug/*.txt {
size 5M
missingok
rotate 2
compress
delaycompress
notifempty
create 644 www-data www-data
}
</code>
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
; daily : means that every day the file is rotated or zipped
; weekly : means that the file is rotated or zipped daily
; missingok : if a debug file does not exist, it will be ignored
; rotate n : files are removed before the last ones are deleted.
; compress : compresses the old debug files
; delaycompress : compresses the debug data only after it has been moved once
; notifempty : 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 ==
* [[Reference10:Concept_Update_Server]]
* [[Reference12r1:DHCP_client]]
* [[Reference10:Concept_Linux_Application_Platform]]
* [[Reference10:Concept_Provisioning]]
* [[Howto:PHP_based_Update_Server]] (old version)
* [[Howto:Creating custom Certificates using a Windows Certificate Authority]]
* [[Howto:Effect arbitrary Configuration Changes using a HTTP Command Line Client or from an Update]]
[[Category:Sample|{{PAGENAME}}]]

Revision as of 11:44, 5 October 2018