tutorial

Monitoring Lufi with Vigilmon

Lufi is a self-hosted encrypted temporary file sharing platform built on Perl/Mojolicious. Here's how to monitor its Hypnotoad server, file upload/download endpoints, Minion job queue, and SQLite/PostgreSQL database with Vigilmon.

Lufi is a self-hosted temporary file sharing platform with a key property: files are encrypted client-side before being sent to the server, so even the server operator can't read uploaded content. Built on Perl and Mojolicious, it uses Hypnotoad as its production server and Minion for background job processing. The encryption makes it uniquely trustworthy, but self-hosting means you own the uptime — and Vigilmon gives you the external visibility to know when the platform breaks before your users hit a broken upload page.

What You'll Set Up

  • HTTP uptime monitor for the Hypnotoad/Mojolicious application
  • File upload and download endpoint health checks
  • Minion job queue worker heartbeat
  • File expiry worker heartbeat
  • SQLite or PostgreSQL database connectivity check
  • Disk usage threshold alerting
  • SSL/TLS certificate expiry alerts
  • Admin API endpoint availability check

Prerequisites

  • Lufi deployed on a VPS (Perl/Mojolicious, Hypnotoad, port 8080 typically proxied via nginx)
  • SQLite or PostgreSQL database
  • Minion for background jobs
  • A free Vigilmon account

Step 1: Monitor the Hypnotoad Web Server

Lufi runs under Mojolicious's Hypnotoad production server, typically on port 8080 behind an nginx reverse proxy that handles SSL. Monitor the public-facing URL:

  1. Log in to vigilmon.online and click Add Monitor.
  2. Set Type to HTTP / HTTPS.
  3. Enter your instance URL: https://lufi.yourdomain.com
  4. Set Check interval to 1 minute.
  5. Set Expected HTTP status to 200.
  6. Enable Monitor SSL certificate with a 21 day expiry alert.
  7. Click Save.

Add a keyword check to confirm the Lufi upload interface loads:

  • Under Keyword check, enter lufi or upload — both appear in the default Lufi page title and UI.

This distinguishes between nginx returning 200 from a static error page (Hypnotoad crashed) vs. the real Lufi application responding.


Step 2: Add a Custom Health Check Endpoint

Lufi's Mojolicious application can be extended with a lightweight health route. Add it to your Lufi configuration by creating a custom plugin or modifying the app startup.

For Mojolicious Lite-style extensions, add to your lufi.conf startup or create a small plugin at lib/Lufi/Plugin/HealthCheck.pm:

package Lufi::Plugin::HealthCheck;
use Mojo::Base 'Mojolicious::Plugin';

sub register {
    my ($self, $app) = @_;

    $app->routes->get('/health' => sub {
        my $c = shift;

        my %checks;
        my $status = 200;

        # Database connectivity check
        eval {
            $c->app->db->db->query('SELECT 1');
            $checks{database} = 'ok';
        };
        if ($@) {
            $checks{database} = 'error';
            $status = 503;
        }

        # Upload directory writable
        my $upload_dir = $c->app->config('upload_dir') // 'files';
        $checks{upload_dir} = (-d $upload_dir && -w $upload_dir) ? 'ok' : 'error';
        $status = 503 if $checks{upload_dir} eq 'error';

        # Disk space check (alert below 10% free)
        my @df = `df -k "$upload_dir"`;
        if (@df > 1) {
            my @fields = split(/\s+/, $df[1]);
            my $use_pct = $fields[4];
            $use_pct =~ s/%//;
            $checks{disk_space} = ($use_pct < 90) ? 'ok' : 'warn';
        }

        $c->render(json => {
            status => $status == 200 ? 'ok' : 'degraded',
            checks => \%checks,
        }, status => $status);
    });
}

1;

Load the plugin in your Lufi application startup. Then add a Vigilmon HTTP monitor for https://lufi.yourdomain.com/health.


Step 3: Monitor File Upload and Download Endpoints

The upload and download handlers are Lufi's core functionality. Test them independently from the web UI.

Upload endpoint check:

Create a probe script at /usr/local/bin/lufi-upload-probe.sh:

#!/bin/bash
set -e

LUFI_URL="https://lufi.yourdomain.com"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_UPLOAD_TOKEN"

# Create a tiny test file
TMPFILE=$(mktemp)
echo "vigilmon probe $(date)" > "$TMPFILE"

# Attempt upload using Lufi's API
RESPONSE=$(curl -fsS -X POST "$LUFI_URL/upload" \
    -F "file=@$TMPFILE" \
    -F "delay=1" \
    -w "%{http_code}" \
    -o /tmp/lufi-probe-response.json)

rm -f "$TMPFILE"

if echo "$RESPONSE" | grep -qE "^(200|201|302)$"; then
    curl -fsS "$HEARTBEAT_URL" > /dev/null
else
    echo "Lufi upload probe failed with HTTP $RESPONSE" >&2
    cat /tmp/lufi-probe-response.json >&2
    exit 1
fi
chmod +x /usr/local/bin/lufi-upload-probe.sh

# Run every 5 minutes
*/5 * * * * /usr/local/bin/lufi-upload-probe.sh

Create a Vigilmon Cron Heartbeat monitor with a 10 minute expected interval.

Download endpoint check:

After a successful probe upload, capture the generated download URL and add a static Vigilmon HTTP monitor for a known-good file link. This stays valid until the file's expiry TTL.


Step 4: Heartbeat for the Minion Job Queue Worker

Lufi uses Minion to process background jobs including file expiry, cleanup, and potentially virus scanning. If the Minion worker stops, files won't be cleaned up and jobs will accumulate silently.

Add a Minion task that pings Vigilmon after each successful job execution cycle. In your Lufi app or a custom plugin:

# Add a recurring Minion task that acts as a heartbeat
$app->minion->add_task(vigilmon_heartbeat => sub {
    my $job = shift;
    my $url = $app->config('vigilmon_minion_heartbeat_url');
    return unless $url;

    eval {
        Mojo::UserAgent->new->get($url);
    };
    $job->finish('heartbeat sent');
});

# Schedule it every 5 minutes
$app->minion->enqueue('vigilmon_heartbeat') 
    unless $app->minion->jobs({tasks => ['vigilmon_heartbeat'], states => ['active', 'inactive']})->total;

For a simpler approach, add a cron-based check that confirms the Minion worker process is alive:

#!/bin/bash
# /usr/local/bin/lufi-minion-heartbeat.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_MINION_TOKEN"

# Check if the Minion worker is running
if pgrep -f "minion worker" > /dev/null; then
    curl -fsS "$HEARTBEAT_URL" > /dev/null
else
    echo "Lufi Minion worker not running" >&2
    exit 1
fi
chmod +x /usr/local/bin/lufi-minion-heartbeat.sh

# Run every 5 minutes
*/5 * * * * /usr/local/bin/lufi-minion-heartbeat.sh

Create a Vigilmon Cron Heartbeat with a 10 minute expected interval.


Step 5: Heartbeat for the File Expiry Worker

Lufi automatically deletes files after their expiry period. This is typically handled by a Minion job or a standalone cron task. Wrap it in a heartbeat so you know if cleanup stops working.

If Lufi uses a dedicated cleanup script:

#!/bin/bash
# /etc/cron.hourly/lufi-cleanup

set -e
cd /var/www/lufi

# Run the Lufi cleanup command (adjust for your installation)
carton exec perl lufi.pl minion job -e clean_expired >> /var/log/lufi/cleanup.log 2>&1

# Ping Vigilmon on success
curl -fsS --retry 3 "https://vigilmon.online/heartbeat/YOUR_CLEANUP_TOKEN" > /dev/null
chmod +x /etc/cron.hourly/lufi-cleanup

Create a Vigilmon Cron Heartbeat with a 2 hour expected interval. A missed hourly cleanup fires an alert within two hours — before the disk fills.


Step 6: Database Connectivity and Disk Usage

Database health:

The health endpoint created in Step 2 already covers database connectivity. For an additional low-level check targeting SQLite specifically, add this wrapper:

#!/bin/bash
# SQLite integrity check (run daily)
DB_PATH="/var/www/lufi/lufi.db"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_DB_TOKEN"

RESULT=$(sqlite3 "$DB_PATH" "PRAGMA integrity_check;" 2>&1)
if echo "$RESULT" | grep -q "^ok$"; then
    curl -fsS "$HEARTBEAT_URL" > /dev/null
else
    echo "SQLite integrity check failed: $RESULT" >&2
    exit 1
fi

For PostgreSQL, use pg_isready:

if pg_isready -h 127.0.0.1 -d lufi -U lufi > /dev/null 2>&1; then
    curl -fsS "$HEARTBEAT_URL" > /dev/null
fi

Disk usage:

#!/bin/bash
# /usr/local/bin/lufi-disk-check.sh
UPLOAD_DIR="/var/www/lufi/files"
HEARTBEAT_URL="https://vigilmon.online/heartbeat/YOUR_DISK_TOKEN"
THRESHOLD=85

USED=$(df "$UPLOAD_DIR" | awk 'NR==2 {gsub(/%/,"",$5); print $5}')

if [ "$USED" -lt "$THRESHOLD" ]; then
    curl -fsS "$HEARTBEAT_URL" > /dev/null
else
    echo "Disk at ${USED}% — above ${THRESHOLD}% threshold" >&2
    exit 1
fi
# Run every 15 minutes
*/15 * * * * /usr/local/bin/lufi-disk-check.sh

Step 7: Monitor the Admin API Endpoint

Lufi exposes an admin interface for managing stored files. Monitor it to confirm it's accessible (authenticated 403 is fine — it proves the route is live):

  1. In Vigilmon, add an HTTP monitor for https://lufi.yourdomain.com/admin.
  2. Set Expected HTTP status to 200 or 302 (redirect to login).
  3. Set Check interval to 5 minutes.

A 503 from the admin endpoint when the main UI is responding normally can indicate a Minion worker crash affecting the admin statistics page.


Step 8: Configure Alert Channels

  1. Go to Alert Channels in Vigilmon and add your email or Slack webhook.
  2. On the main web monitor and upload heartbeat, set Consecutive failures before alert to 2.
  3. On the disk usage heartbeat, set Consecutive failures before alert to 1.
  4. On the Minion worker heartbeat, set Consecutive failures before alert to 1.

Suppress alerts during Hypnotoad restarts (typically under 5 seconds) by using Vigilmon's maintenance window API in your deployment scripts:

# Before restarting Hypnotoad
curl -X POST https://vigilmon.online/api/maintenance \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{"monitor_id": "MONITOR_ID", "duration_minutes": 2}'

hypnotoad /var/www/lufi/lufi.pl

Summary

| Monitor | Target | What It Catches | |---|---|---| | Web availability | https://lufi.yourdomain.com | Hypnotoad crash, nginx misconfiguration | | Health endpoint | /health | DB down, upload dir unwritable | | Upload probe heartbeat | Vigilmon heartbeat URL | Upload handler broken | | Minion worker heartbeat | Vigilmon heartbeat URL | Background job worker stopped | | Expiry job heartbeat | Vigilmon heartbeat URL | File cleanup stopped | | Disk threshold heartbeat | Vigilmon heartbeat URL | Disk above 85% | | Database check heartbeat | Vigilmon heartbeat URL | SQLite/PostgreSQL integrity failure | | Admin endpoint | /admin | Admin API down | | SSL certificate | Main domain | TLS certificate expired |

Lufi's client-side encryption means you can promise users their files are private — but that promise only holds if the service stays up. With Vigilmon monitoring Hypnotoad, the Minion job queue, file expiry jobs, disk space, and every critical endpoint, you can keep that promise running 24/7.

Get started free at vigilmon.online.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →