Pinry is a private, self-hosted image bookmarking and pinboard application — a Python/Django backend with a React frontend that lets you pin images from the web or upload your own, organise them into boards, and search them later. Unlike Pinterest, every image you pin stays on your server. Vigilmon keeps watch over your Pinry stack: Django web server, PostgreSQL database, Celery image-processing workers, Redis queue broker, image storage, and TLS certificates — so you know the moment something goes wrong.
What You'll Set Up
- HTTP uptime monitor for the Pinry web interface (port 80/443)
- PostgreSQL database connectivity check via a dedicated health endpoint
- Django application server health check
- Celery worker heartbeat (image processing: thumbnail generation, metadata extraction)
- Redis queue broker TCP connectivity check
- Image storage backend accessibility check
- Image proxy and thumbnail service response-time monitor
- User authentication service check
- Cron heartbeat for scheduled image re-processing jobs
- SSL/TLS certificate expiry alert
Prerequisites
- Pinry running and accessible over HTTP or HTTPS
- PostgreSQL, Redis, and Celery all deployed as part of your Pinry stack
- A free Vigilmon account
Step 1: Monitor the Pinry Web Interface
The first check confirms that Django and your reverse proxy are both serving requests.
- Log in to vigilmon.online and click Add Monitor.
- Set Type to
HTTP / HTTPS. - Enter your Pinry URL:
https://pinry.yourdomain.com. - Set Check interval to
1 minute. - Set Expected HTTP status to
200. - Click Save.
If you run Pinry behind nginx or Caddy, this single check covers both the proxy layer and the gunicorn/uwsgi Django application server.
Step 2: Add a Django Health Check Endpoint
Pinry's default deployment doesn't expose a /health route, but you can add one in minutes using the django-health-check package or a minimal custom view:
# pinry/health_views.py
from django.http import JsonResponse
from django.db import connection
def health(request):
try:
connection.ensure_connection()
db_ok = True
except Exception:
db_ok = False
status = 200 if db_ok else 503
return JsonResponse({"db": db_ok}, status=status)
# urls.py
from django.urls import path
from . import health_views
urlpatterns = [
path("health/", health_views.health),
# ... existing urls
]
Now add a Vigilmon monitor for https://pinry.yourdomain.com/health/ with expected status 200. A 503 means Django is up but the database is unreachable — a different failure mode than a 502 proxy error.
Step 3: Monitor PostgreSQL Connectivity
The health endpoint from Step 2 already covers the database from Django's perspective. For a lower-level check, add a TCP monitor directly to the PostgreSQL port:
- Click Add Monitor → TCP Port.
- Enter your database server hostname and port (default
5432). - Set Check interval to
1 minute. - Click Save.
A TCP failure on port 5432 that the health endpoint doesn't catch means the issue is network-level (firewall rule change, container restart) rather than application-level.
Step 4: Monitor Celery Worker Health
Pinry uses Celery to process images asynchronously — generating thumbnails, extracting metadata, and re-fetching updated images. If Celery workers die, new pins queue up silently and users see broken or missing thumbnails.
The cleanest way to monitor Celery workers is a dedicated heartbeat task. Add this to your Celery beat schedule:
# celery_config.py or settings.py
from celery.schedules import crontab
CELERYBEAT_SCHEDULE = {
"vigilmon-heartbeat": {
"task": "pinry.tasks.send_vigilmon_heartbeat",
"schedule": crontab(minute="*/5"), # every 5 minutes
},
}
# pinry/tasks.py
import requests
from celery import shared_task
@shared_task
def send_vigilmon_heartbeat():
requests.get("https://vigilmon.online/heartbeat/YOUR_CELERY_ID", timeout=5)
In Vigilmon:
- Click Add Monitor → Cron Heartbeat.
- Set Expected interval to
5 minutes. - Copy the heartbeat URL and paste it into
YOUR_CELERY_IDabove.
If all Celery workers crash, the task never runs, the ping never arrives, and Vigilmon alerts after 5 minutes.
Step 5: Check Redis Queue Broker Connectivity
Celery uses Redis as its message broker. If Redis goes down, Celery workers stop receiving tasks even if they are still running.
- Click Add Monitor → TCP Port.
- Enter your Redis server hostname and port (default
6379). - Set Check interval to
1 minute. - Click Save.
A Redis TCP failure combined with healthy Celery heartbeats (from a previous successful ping interval) tells you that new tasks are not being queued, but workers haven't died yet.
Step 6: Verify Image Storage Backend Accessibility
Pinry stores pinned and uploaded images on local disk or S3-compatible object storage. Monitor the storage path by checking whether Pinry can serve a known image file:
- Pin a test image and copy its direct URL (e.g.
https://pinry.yourdomain.com/media/pins/test-image.jpg). - Add an HTTP monitor for that URL with expected status
200. - Label it Image storage.
If your storage backend (NFS mount, S3 bucket, or local disk) becomes unavailable, this monitor fails while the web interface monitor (Step 1) may still pass — catching the failure faster than user reports.
Step 7: Monitor Thumbnail Service Response Times
Pinry generates thumbnails for every pinned image. Slow thumbnails degrade the browsing experience even when the app is technically up.
- Open the image storage monitor from Step 6 (or create a new one for a known thumbnail URL like
https://pinry.yourdomain.com/media/thumbnails/test_thumbnail.jpg). - Enable Response time alerting.
- Set the alert threshold to
2000 ms.
Thumbnails above 2 seconds indicate storage I/O pressure or Celery processing backlog.
Step 8: Check the Authentication Service
Pinry's login endpoint must be healthy for users to access their boards.
- Add an HTTP monitor for
https://pinry.yourdomain.com/accounts/login/. - Set Expected status to
200. - Label it Auth service.
Django's authentication middleware is part of the request cycle, so a broken auth service often surfaces as a 500 on the login page rather than on the home page.
Step 9: Heartbeat for Scheduled Image Re-Processing
Pinry can re-fetch and re-process pinned images on a schedule (updating metadata, refreshing broken image sources). Add a heartbeat for this job:
# crontab example
0 2 * * * cd /opt/pinry && python manage.py reprocess_images && curl -s https://vigilmon.online/heartbeat/YOUR_REPROCESS_ID
In Vigilmon, create a Cron Heartbeat with the expected interval matching your schedule (e.g. 1440 minutes for daily).
Step 10: SSL/TLS Certificate Expiry Alert
- Open the web-interface monitor from Step 1.
- Enable Monitor SSL certificate.
- Set Alert when certificate expires in less than
21 days. - Click Save.
Pinry is typically deployed with Let's Encrypt. Renewal failures are silent until the certificate actually expires — the 21-day window gives you three renewal cycles to investigate.
Step 11: Configure Alert Channels
- Go to Alert Channels in Vigilmon and connect Slack, email, or a webhook.
- Set Consecutive failures before alert to
2on all HTTP monitors — Django cold starts and container restarts can cause single-probe failures. - Keep Consecutive failures at
1for the Celery heartbeat and the scheduled re-processing heartbeat — a missed worker ping is always worth investigating.
Summary
| Monitor | Target | What It Catches |
|---|---|---|
| Web interface | https://pinry.yourdomain.com | App crash, proxy failure |
| Django health | GET /health/ | DB connectivity from app |
| PostgreSQL TCP | host:5432 | Network-level DB failure |
| Celery heartbeat | Vigilmon heartbeat URL | Worker crash, task queue dead |
| Redis TCP | host:6379 | Message broker down |
| Image storage | Known media URL | Storage backend failure |
| Thumbnail response time | Known thumbnail URL | Slow image processing |
| Auth service | /accounts/login/ | Login flow broken |
| Re-processing heartbeat | Vigilmon heartbeat URL | Scheduled job not running |
| SSL certificate | pinry.yourdomain.com | TLS cert expiry |
Pinry gives you a private, ad-free image collection — but that privacy comes with full ownership of the stack. With Vigilmon watching every layer from the Django web server to the Celery workers and Redis broker, you catch failures before your pins start showing broken images.