How to fix broken monitoring checks using PhantomJS (TypeError) after Ubuntu upgrade

Written by - 0 comments

Published on - Listed in Linux Monitoring Icinga Internet SSL TLS


To run a simple monitoring on websites or web applications it in most situations enough to use the well established and widely used check_http nagios-plugin or monitoring-plugin. Only in specific or advanced monitoring situations, such as a full end-to-end user simulation, something else is needed.

check_http and the problem with JavaScript loaded content

check_http is great in checking for the web server's and application's response, able to do check for specific response codes or check the response body for a specific string. But this won't work when the site content is loading with a JavaScript; the expected content won't show up in the HTTP response body of the requested site. And as check_http, similar to curl, is not a browser but a script, it is unable to launch the JavaScript and then load the contents.

Website content loaded with JavaScript

To solve this problem, an additional monitoring plugin called check_http_load_time was created. This plugin uses PhantomJS in the background.

Note: Unfortunately PhantomJS is no longer an active project since 2023.

PhantomJS is simply explained as "command line browser" and is able to load content similar as a normal browser would do. It can therefore be used to simulate a user accessing a specific URL and load contents using JavaScript, retrieving statistics of the effective load time.

ck@monitoring:~# /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs
OK: https://myapp.example.com/#webview/62 load time: 0.42

Note: The phantomjs package from the Ubuntu repositories never seemed to work correctly, I therefore had the binary from phantomjs.org installed at /usr/local/bin/phantomjs.

Since I integrated this plugin back in 2020, initially on Ubuntu 20.04, the plugin has been successfully used to check specific web applications loading content with JavaScript.

The plugin was fully integrated into our Icinga2 monitoring, featuring it's own CheckCommand (we called it check_http_phantom in our setup).

After Ubuntu upgrade: Could not parse JSON from phantomjs

Fast forward five years. It's 2025 and Ubuntu 20.04 LTS is EOL at the end of April. Time to upgrade to Ubuntu 22.04 or 24.04. 

However after the first distribution upgrade to Ubuntu 22.04, monitoring started to alert on all websites using this specific monitoring plugin. A manual launch of the plugin showed the same error as we could see in the alert notifications and in the Icinga2 UI:

ck@monitoring:~$ /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs -v
UNKNOWN: Could not parse JSON from phantomjs

There were two initial thoughts of potential reasons:

  • An updated Ruby version could cause the plugin to run into an error
  • The phantomjs binary was compiled on an older system and is not compatible with this system or requires a specific environment

The Ruby version turned out to be not a problem at all. The plugin itself could still be executed. An strace on the plugin execution revealed how phantomjs was executed:

ck@monitoring:~$ strace -f -s 1000 -e trace=execve /usr/lib/nagios/plugins/check_http_load_time.rb -p /usr/local/bin/phantomjs -u https://myapp.example.com/#webview/62
execve("/usr/lib/nagios/plugins/check_http_load_time.rb", ["/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd70e299d8 /* 34 vars */) = 0
execve("/home/admck/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/home/admck/.local/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/sbin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/local/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/sbin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = -1 ENOENT (No such file or directory)
execve("/usr/bin/ruby", ["ruby", "/usr/lib/nagios/plugins/check_http_load_time.rb", "-p", "/usr/local/bin/phantomjs", "-u", "https://myapp.example.com/#webview/62"], 0x7ffd4f514fb8 /* 34 vars */) = 0
strace: Process 1371139 attached
strace: Process 1371140 attached
[pid 1371140] execve("/bin/sh", ["sh", "-c", "/usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no  /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62 'false' 2> /dev/null"], 0x56026c5dfba0 /* 34 vars */) = 0
strace: Process 1371141 attached
[pid 1371141] execve("/usr/local/bin/phantomjs", ["/usr/local/bin/phantomjs", "--load-images=yes", "--local-to-remote-url-access=yes", "--disk-cache=no", "/usr/lib/nagios/plugins/netsniff.js", "https://myapp.example.com/#webview/62", "false"], 0x56123391cc78 /* 34 vars */) = 0
[pid 1371141] +++ exited with 1 +++
[pid 1371140] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1371141, si_uid=901, si_status=1, si_utime=0, si_stime=1} ---
[pid 1371140] +++ exited with 1 +++
[pid 1371138] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1371140, si_uid=901, si_status=1, si_utime=0, si_stime=0} ---
UNKNOWN: Could not parse JSON from phantomjs
[pid 1371139] +++ exited with 3 +++
+++ exited with 3 +++

strace also shows the the child process (the phantomjs command) exited with a non-zero exit code. What is happening there?

Let's find out by executing the exact same command:

ck@monitoring:~$ /usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
Auto configuration failed
140551518091200:error:25066067:DSO support routines:DLFCN_LOAD:could not load the shared library:dso_dlfcn.c:185:filename(libproviders.so): libproviders.so: cannot open shared object file: No such file or directory
140551518091200:error:25070067:DSO support routines:DSO_load:could not load the shared library:dso_lib.c:244:
140551518091200:error:0E07506E:configuration file routines:MODULE_LOAD_DSO:error loading dso:conf_mod.c:285:module=providers, path=providers
140551518091200:error:0E076071:configuration file routines:MODULE_RUN:unknown module name:conf_mod.c:222:module=providers

Yep, that definitely looks like a problem. But does it mean that manually installed phantomjs binary simply won't work anymore on the upgraded Ubuntu 22.04 or later? Or is it something else?

TypeError on packaged phantomjs binary

I tried the Ubuntu packaged phantomjs, located under /usr/bin/phantomjs. This package was still installed, although the package doesn't exist any longer in Ubuntu 22.04.

To make the question mark above my head even bigger, it turns out this binary somewhat worked:

ck@monitoring:~$ /usr/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
{
    "log": {
        "version": "1.2",
        "creator": {
            "name": "PhantomJS",
            "version": "2.1.1"
        },
        "pages": [
            {
                "startedDateTime": "2025-04-15T11:46:40.350Z",
                "endedDateTime": "2025-04-15T11:46:40.546Z",
                "initialResourceLoadTime": 54,
                "id": "https://myapp.example.com/#webview/62",
                "size": 29861,
                "resourcesCount": 4,
                "domElementsCount": 32,
                "title": "Einen Moment bitte, die Ausgabe wird geladen...",
                "jscheckout": null,
                "pageTimings": {}
            }
        ]
    }
}
TypeError: Attempting to change the setter of an unconfigurable property.
TypeError: Attempting to change the setter of an unconfigurable property.

The phantomjs output was clearly able to open the JavaScript elements on the target URL. However the output at the end contains two TypeError lines, making the whole output an invalid JSON.

Now the UNKNOWN error from the monitoring plugin makes sense: Could not parse JSON from phantomjs. Indeed.

Default OPENSSL_CONF causing problems

A good old pre-AI-times Internet research for this PhantomJS TypeError led me to a question on StackOverflow. The same two TypeError lines show up in the OP's question from 2020.

A comment, added 3 years later, mentioned that it was a problem with the SSL configuration:

The way I solved it was: export OPENSSL_CONF=/dev/null

I didn't really think that would solve anything, but at the same time I've also ran into big OpenSSL communication issues after an OS/OpenSSL upgrade in the past.

To turn my question mark above my head even bigger, /usr/bin/phantomjs would now return an even different error.

Website content loaded with JavaScript

HOWEVER the manually installed binary at /usr/local/bin/phantomjs would now suddenly work!

ck@monitoring:~$ export OPENSSL_CONF=/dev/null
ck@monitoring:~$ /usr/local/bin/phantomjs --load-images=yes --local-to-remote-url-access=yes --disk-cache=no /usr/lib/nagios/plugins/netsniff.js https://myapp.example.com/#webview/62
{
    "log": {
        "version": "1.2",
        "creator": {
            "name": "PhantomJS",
            "version": "2.1.1"
        },
        "pages": [
            {
                "startedDateTime": "2025-04-15T13:56:09.373Z",
                "endedDateTime": "2025-04-15T13:56:09.609Z",
                "initialResourceLoadTime": 58,
                "id": "https://myapp.example.com/#webview/62",
                "size": 26643,
                "resourcesCount": 4,
                "domElementsCount": 32,
                "title": "Einen Moment bitte, die Ausgabe wird geladen...",
                "jscheckout": null,
                "pageTimings": {}
            }
        ]
    }
}

No error, no TypeError lines at the end; a valid JSON output!

How would this now show when using the check_http_load_time plugin?

ck@monitoring:~$ /usr/lib/nagios/plugins/check_http_load_time.rb -u "https://myapp.example.com/#webview/62" -p /usr/local/bin/phantomjs
OK: https://myapp.example.com/#webview/62 load time: 0.21

Hurray! The monitoring plugin works again with the OPENSSL_CONF environment variable set to something different than the system default (which is /etc/ssl/openssl.cnf, just FYI).

Adjusting Icinga2 CheckCommand to use environment variable

Of course the actual check is executed by Icinga2 and the environment variable is not defined anywhere. It could be set on the "nagios" system user, which is used in our environment to launch checks, however there's a better solution.

The Icinga2 CheckCommand object allows to include environment variables. This is pretty helpful if you need to set environment variables for proxy access or similar in front of a command. In our situation it helps us to set the OPENSSL_CONF environment variable for this specific check.

Here's an excerpt with the relevant part:

root@icingamaster:~# head /etc/icinga2/zones.d/global-templates/commands/check_http_phantom.conf
object CheckCommand "check_http_phantom" {
  import "plugin-check-command"
  command = [ PluginContribDir + "/check_http_load_time.rb" ]
  env.OPENSSL_CONF = "/dev/null"

  arguments = {

After an Icinga2 config reload (systemctl reload icinga2), all the checks using the check_http_load_time plugin turned OK again.

Where to in the future?

With PhantomJS no longer receiving updates or fixes, something else must come in the future, to replace these kind of HTTP checks with JavaScript loaded content. I'm tending towards real E2E testing tools, such as Selenium or Playwright. I've seen a great presentation at the OSMC 2024 about these E2E tools. But right now I have to stick with the PhantomJS based check - due to lack of time :-/.


Add a comment

Show form to leave a comment

Comments (newest first)

No comments yet.

RSS feed

Blog Tags:

  AWS   Android   Ansible   Apache   Apple   Atlassian   BSD   Backup   Bash   Bluecoat   CMS   Chef   Cloud   Coding   Consul   Containers   CouchDB   DB   DNS   Database   Databases   Docker   ELK   Elasticsearch   Filebeat   FreeBSD   Galera   Git   GlusterFS   Grafana   Graphics   HAProxy   HTML   Hacks   Hardware   Icinga   Influx   Internet   Java   KVM   Kibana   Kodi   Kubernetes   LVM   LXC   Linux   Logstash   Mac   Macintosh   Mail   MariaDB   Minio   MongoDB   Monitoring   Multimedia   MySQL   NFS   Nagios   Network   Nginx   OSSEC   OTRS   Observability   Office   OpenSearch   PGSQL   PHP   Perl   Personal   PostgreSQL   Postgres   PowerDNS   Proxmox   Proxy   Python   Rancher   Rant   Redis   Roundcube   SSL   Samba   Seafile   Security   Shell   SmartOS   Solaris   Surveillance   Systemd   TLS   Tomcat   Ubuntu   Unix   VMWare   VMware   Varnish   Virtualization   Windows   Wireless   Wordpress   Wyse   ZFS   Zoneminder