Skip to main content

PrivateBin NGINX Access Log Dashboard

ยท 6 min read
VoidQuark
Open-source enthusiast

PrivateBin NGINX Access Log Dashboard

The PrivateBin NGINX JSON Access Log dashboard provides statistics for tracking user activity on your PrivateBin instance. You can monitor the creation and access of pastes.

It's important to note that PrivateBin does not generate application logs, so we rely solely on the NGINX Access Log. While this log doesn't contain extensive audit data, it does provide sufficient information to display certain insights.

If you're unfamiliar with PrivateBin, you can learn more about it by visiting this PrivateBin deployment guide.

To set up the required components, please ensure you have the following:

What You NeedAnsible Role for Deployment
GrafanaAnsible Grafana Collection
Grafana LokiAnsible Loki Role
Grafana PromtailAnsible Promtail Role
PrivateBinAnsible PrivateBin Role

Assuming you have fulfilled the above requirements, let's proceed from this point.

Dashboard Featuresโ€‹

privatebin_dashboard_1 privatebin_dashboard_2

Before I list the features, I want to say thank you to the creators of the NGINX JSON Access Log dashboard that inspired me. You might be wondering why I decided to create another dashboard. Well, the answer is straightforward: While the dashboard I mentioned earlier provides an overview of NGINX statistics, it doesn't focus directly on monitoring the "created" or "accessed" paste requests. My dashboard is designed specifically for that purpose.

With my dashboard, you can easily keep an eye on important paste-related information, such as:

Panel TitlePanel TypeDescription
Total Created PasteStatTotal number of pastes created
Total Requested PasteStatTotal number of pastes requested
Total Created Paste by Unique IPStatTotal number of unique IP addresses that created pastes
Total Requested Paste by Unique IPStatTotal number of unique IP addresses that requested pastes
Paste - Total Body Bytes SendStatTotal number of body bytes sent in POST and GET requests
Total Request 4xxStatTotal number of requests with a 4xx status code (including all server requests, not just pastes)
Total Request 5xxStatTotal number of requests with a 5xx status code (including all server requests, not just pastes)
Paste - Privatebin Recent LogLogsRecent logs focused on important information (using lineformat)
Paste - GET/POST Status CodeTime SeriesGraphical representation of GET/POST request status codes over time
Paste - Body Bytes SendTime SeriesGraphical representation of body bytes sent in POST and GET requests over time
Paste - Top 10 User AgentsTableTable showing the top 10 user agents
Paste - Top 10 Requested Paste by IP and CountryTableTable displaying the top 10 requested pastes by IP addresses and countries
Paste - Top 15 Requested PasteTableTable showing the top 15 requested pastes
Paste - Top 15 RefererTableTable highlighting the top 15 referrers
Top 10 Requested Paste by CountryTableTable presenting country codes and the number of requested pastes per country

I used a few emojis to make it cleaner and easier to recognize what is what in the log panel:

โœ‰๏ธ POST ๐Ÿ“‹/ ๐ŸŒ<COUNTRY> <IP> ๐Ÿ†”<CF-RAY-ID> ๐Ÿ’ป<USER_AGENT>
๐Ÿ“œ GET ๐Ÿ“‹/?pasteid=7dcb133aee836cdf ๐ŸŒ<COUNTRY> <IP> ๐Ÿ†”<CF-RAY-ID> ๐Ÿ’ป<USER_AGENT>

These features will help you get valuable insights into the activity on your PrivateBin instance, with a specific focus on paste-related data.

PrivateBin Logging Configurationโ€‹

To ensure smooth Loki parsing, the best approach is to use the JSON format for NGINX Access Log. This blog post is focused on deploying my PrivateBin Ansible Role, so I will include the variables that allow you to configure the access_log.conf for PrivateBin NGINX directly. Keep in mind that you will also need to update variables related to volumes, as you must mount this file.

  • Extend volume-related variable:
- "{{ privatebin_dir }}/access_log.conf:/etc/nginx/http.d/access_log.conf:ro,Z"
  • Below is an example of how you can extend the variable list with access_log.conf for NGINX:
privatebin_custom_conf:
- filename: "access_log.conf"
raw_content: |
log_format log-json escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"status": "$status",'
'"msec": "$msec",'
'"bytes_sent":"$bytes_sent",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request":"$request",'
'"request_time":"$request_time",'
'"request_method":"$request_method",'
'"request_uri":"$request_uri",'
'"request_length":"$request_length",'
'"host":"$http_host",'
'"referer":"$http_referer",'
'"user_agent":"$http_user_agent",'
'"x_forwarded_for":"$http_x_forwarded_for",'
'"x_forwarded_proto":"$http_x_forwarded_proto",'
'"connection":"$connection",'
'"accept_encoding":"$http_accept_encoding",'
'"accept_language":"$http_accept_language",'
'"accept":"$http_accept",'
'"cf_ray":"$http_cf_ray",'
'"cf_connecting_ip":"$http_cf_connecting_ip",'
'"cf_ipcountry":"$http_cf_ipcountry",'
'"sec_fetch_site":"$http_sec_fetch_site",'
'"sec_fetch_mode":"$http_sec_fetch_mode",'
'"sec_fetch_dest":"$http_sec_fetch_dest"'
'}';
access_log /dev/stdout log-json;

From this point, journald will log our access.log in JSON format. It's important to note that this dashboard relies on Cloudflare headers. If you don't use Cloudflare, you must change, for example, cf_connecting_ip and cf_ipcountry in all panels or simply do the following in above configuration:

'"cf_connecting_ip":"$remote_addr",'
'"cf_ipcountry":"$geoip_country_code",'

Promtail Configurationโ€‹

Below is an extracted configuration snippet for Promtail, specifically tailored for PrivateBin:

scrape_configs:
- job_name: journal-container-json
journal:
json: false
max_age: 1h
labels:
instance: privatebin.voidquark.com
env: dev
job: containers-json
relabel_configs:
- source_labels:
- __journal_container_name
target_label: container
- source_labels:
- __journal_container_name
action: keep
regex: privatebin

This configuration ensures that only containers with the name privatebin will send logs to Loki. Any logs from other containers will be discarded if their names don't match. I strongly recommend setting the instance and env labels as they help you identify which host is actually hosting this container. This is particularly useful if you are running multiple PrivateBin instances, as it allows you to select which one should display data in the PrivateBin dashboard.

PrivateBin Configurationโ€‹

It's important to note that certain options must be disabled in PrivateBin config (/srv/cfg/conf.php); otherwise, the dashboard will not function properly. This issue arises because POST requests are made to the / URL both when creating a new paste and when someone create comment. Consequently, it becomes challenging to distinguish between a comment and a newly created paste in the logs. To address this, the following options should be disabled to ensure accurate tracking of newly created pastes:

[main]
discussion = false
opendiscussion = false

Source Code Available for Everyoneโ€‹


While this dashboard may not offer extensive functionality, it's still a valuable resource. It can assist you in gaining insights into the behavior of visitors who use your PrivateBin instance. It's important to note that this dashboard is specifically designed to focus on clients that accept the application/json header. As a result, it should effectively capture standard user interactions through web browsers.


Thanks for reading. I'm entering the void. ๐Ÿ›ธ โžก๏ธ ๐Ÿ•ณ๏ธ