How to verify and monitor Tinyproxy as a HTTP forward proxy

Written by - 0 comments

Published on - Listed in Monitoring Proxy Linux Internet Network


Tinyproxy is a lightweight yet powerful open source HTTP proxy, which can be used as both forward (outgoing) and reverse (incoming) HTTP proxy. One of the great features is the use of filters, which can serve as a list of either allowed or blocked domains.

In order to properly monitor Tinyproxy (used as a Forward Proxy), there are a couple of things to look out for.

Check HTTP through Proxy

Let's start with the most important check: An actual HTTP check which goes through the forward proxy, making an outgoing HTTP connection to a destination.

Luckily the check_http monitoring plugin, which is part of the monitoring-plugins package on Debian and Ubuntu and part of the nagios-plugins package on RedHat and derivatives, allows the use of a proxy.

The trick here is to change the request method (-j parameter). Instead of using a more commonly used GET or POST method, use the CONNECT method here.

  -j, --method=STRING  (for example: HEAD, OPTIONS, TRACE, PUT, DELETE, CONNECT, CONNECT:POST)
    Set HTTP method.

The --help output of check_http should even show an actual example how to use check_http with a proxy:

  CHECK SSL WEBSERVER CONTENT VIA PROXY USING HTTP 1.1 CONNECT:
 check_http -I 192.168.100.35 -p 80 -u https://www.verisign.com/ -S -j CONNECT -H www.verisign.com
 all these options are needed: -I <proxy> -p <proxy-port> -u <check-url> -S(sl) -j CONNECT -H <webserver>

To monitor my own blog through the Proxy, I can therefore use:

ck@linux ~ $ /usr/lib/nagios/plugins/check_http -I 127.0.0.1 -p 8888 -u https://www.claudiokuenzler.com/ -S -j CONNECT -H www.claudiokuenzler.com
HTTP OK: HTTP/1.1 200 OK - 34990 bytes in 0.063 second response time |time=0.062641s;;;0.000000;10.000000 size=34990B;;;0

In this situation Tinyproxy is listening on 127.0.0.1:8888. 

Using check_http is helpful to add this automated check into a monitoring software, such as Nagios or Icinga.

As a (manual) alternative, curl can be used to quickly check whether or not the HTTP request works through the Proxy. From curl's man page:

        -x, --proxy [protocol://]host[:port]
              Use the specified proxy.

              The proxy string can be specified with a protocol:// prefix. No protocol specified or http:// will be
              treated as HTTP proxy. Use socks4://, socks4a://, socks5:// or socks5h:// to request a specific SOCKS
              version to be used.  (The protocol support was added in curl 7.21.7)

              HTTPS proxy support via https:// protocol prefix was added in 7.52.0 for OpenSSL, GnuTLS and NSS.

In the following example I am using curl via the Tinyproxy (again, listening on 127.0.0.1:8888) and send a HEAD request (-I) to my own blog:

ck@linux ~ $ curl --proxy http://127.0.0.1:8888 https://www.claudiokuenzler.com -I
HTTP/1.0 200 Connection established
Proxy-agent: tinyproxy/1.10.0

HTTP/2 200
server: nginx
date: Thu, 15 Dec 2022 06:43:00 GMT
content-type: text/html; charset=UTF-8
vary: Accept-Encoding
strict-transport-security: max-age=63072000

Keep an eye on the log file

The Tinyproxy log file (default location is /var/log/tinyproxy/tinyproxy.log) contains important information about connections. It also shows whether or not a destination domains was blocked (filtered). The default log verbosity does not show a lot, only with a LogLevel set to at least NOTICE important log events can be seen.

ck@linux ~ $ grep ^LogLevel /etc/tinyproxy/tinyproxy.conf
LogLevel Info

If Tinyproxy is under a lot of pressure (lots of concurrent connections) there might be need to increase the number of concurrent Tinyproxy servers (child processes) or to increase the number of concurrent connections. Log entries such as "Waiting servers" or similar are such log events.

ck@linux ~ $ tail -f /var/log/tinyproxy/tinyproxy.log
NOTICE    Dec 15 07:08:26 [3999474]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:26 [4021250]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:26 [4021615]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:31 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:08:36 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:08:41 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:08:46 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:08:51 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:08:51 [3998401]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:51 [4004268]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:51 [4021297]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:51 [4020932]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:51 [4022756]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:08:56 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:01 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:06 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:11 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:16 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:21 [1608899]: Waiting servers (0) is less than MinSpareServers (5). Creating new child.
NOTICE    Dec 15 07:09:21 [4001896]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:09:21 [4002820]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.
NOTICE    Dec 15 07:09:21 [4022676]: Waiting servers (21) exceeds MaxSpareServers (20). Killing child.

The reason could also be that a lot of HTTP request at this moment are timing out (slow destination website) and causing the servers to be "stale" until the Tinyproxy timeout (default 300s) is hit.

Tinyproxy's internal (live) statistics

Tinyproxy also comes with its own statistics site. The configuration file gives a hint:

ck@linux ~ $ grep stats /etc/tinyproxy/tinyproxy.conf
# tinyproxy.stats.
StatHost "tinyproxy.stats"
StatFile "/usr/share/tinyproxy/stats.html"

The StatHost is an "internal fake DNS" which tells Tinyproxy to display an internal HTTP page containing live statistics. These stats contain:

  • Number of open connections (live value)
  • Number of requests (a counter since the last start)
  • Number of bad connections (a counter since the last start)
  • Number of denied connections (a counter since the last start)
  • Number of refused connections due to high load (a counter since the last start)

The statistics can be retrieved by making a HTTP request to Tinyproxy (such as a web server) and request the domain configured in StatHost (default: tinyproxy.stats):

ck@linux ~ $ curl -H "Host: tinyproxy.stats" http://127.0.0.1:8888
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

<head>
<title>tinyproxy version 1.10.0 run-time statistics</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

<style type="text/css" media="screen">
<!--/*--><![CDATA[<!--*/

th, td
  text-align: left;
  padding: 0.5em;
  border: 1px solid gray;
}

/*]]>*/-->
</style>

</head>

<body>

<h1>tinyproxy version 1.10.0 run-time statistics</h1>

<table>

<tr>
  <th>Name</th>
  <th>Value</th>
</tr>

<tr>
  <td>Number of open connections</td>
  <td>1</td>

</tr>

<tr>
  <td>Number of requests</td>
  <td>191</td>

</tr>

<tr>
  <td>Number of bad connections</td>
  <td>2</td>

</tr>

<tr>
  <td>Number of denied connections</td>
  <td>2</td>

</tr>

<tr>
  <td>Number of refused connections due to high load</td>
  <td>0</td>

</tr>

</table>

<hr />

<p><em>Generated by <a href="https://tinyproxy.github.io/">tinyproxy</a> version 1.10.0.</em></p>

</body>

</html>

As the output shows, this is a HTML output containing tables and nicely formatted columns for the human eye. If you want to (automatically) parse this output, a JSON output would be more better.

But this HTML output can be modified. The template to be used can be set in the Tinyproxy config using the StatFile option. By copying and modifying the existing template, you can easily create a better parseable output, such as JSON. Note that in order to "trick Tinyproxy" the starting curly braces needs to be set twice (Tinyproxy uses curly braces to define the internal variables):

ck@linux ~ $ cat /usr/share/tinyproxy/stats-json.html
{{ "version":"{version}", "open":{opens}, "requests":{reqs}, "bad":{badconns}, "denied":{deniedconns}, "refused":{refusedconns} }

This new template (stats-json.html) can now be defined in the Tinyproxy config:

ck@linux ~ $ grep StatFile /etc/tinyproxy/tinyproxy.conf
# StatFile: The HTML file that gets sent when a request is made
StatFile "/usr/share/tinyproxy/stats-json.html"

And after another reload (/etc/init.d/tinyproxy reload works, systemctl reload tinyproxy doesn't on Debian Bullseye), the HTTP stats can be retrieved in JSON format:

ck@linux ~ $ curl -H "Host: tinyproxy.stats" http://127.0.0.1:8888
{ "version":"1.10.0", "open":1, "requests":263, "bad":2, "denied":2, "refused":0 }

And with a JSON parser this can also be displayed as "pretty":

ck@linux ~ $ curl -s -H "Host: tinyproxy.stats" http://127.0.0.1:8888 | jq
{
  "version": "1.10.0",
  "open": 1,
  "requests": 267,
  "bad": 2,
  "denied": 2,
  "refused": 0
}

An output like this can now also be added into a monitoring software, e.g. by using the check_json monitoring plugin or an alternative.


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   Icingaweb   Icingaweb2   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   Office   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   


Update cookies preferences