Your Kbin instance had been running for three weeks without incident. The homepage loaded fine. Users were browsing magazines and posting content. But nobody noticed that federation had stopped delivering posts to Mastodon for two days — the RabbitMQ queue had grown to 80,000 unacked messages after a single memory spike caused the Symfony Messenger worker to crash. By the time a user reported it, half your federated subscribers had seen nothing from your instance in 48 hours.
Kbin is a federated content aggregator and microblogging platform built with PHP and the Symfony framework. It combines Reddit-style magazine subscriptions with Mastodon-compatible microblogging over ActivityPub, giving communities a space that federates with the rest of the Fediverse. Running Kbin reliably means keeping PHP-FPM, PostgreSQL, Redis, RabbitMQ, Mercure, and Symfony Messenger all healthy simultaneously. Vigilmon gives you the external uptime monitoring and alerting to catch failures before your users do.
What You'll Set Up
- HTTP uptime monitor for the Kbin web interface
- PHP-FPM health check to detect process pool exhaustion
- PostgreSQL database connectivity check
- Redis cache health endpoint monitor
- RabbitMQ management API queue depth alert
- Mercure real-time push hub availability check
- ActivityPub federation inbox and outbox endpoint checks
- Heartbeat monitor for Symfony Messenger workers
- SSL certificate expiry alerts
Prerequisites
- A running Kbin instance (v0.11+ recommended) behind Nginx or Caddy on port 80/443
- RabbitMQ management plugin enabled (
rabbitmq-plugins enable rabbitmq_management) - A free Vigilmon account
Step 1: Monitor the Kbin Web Interface
The Kbin homepage is the primary health signal for the entire stack. A successful response confirms that Nginx is serving traffic, PHP-FPM is processing requests, and PostgreSQL is returning data for the magazine listing.
Test it:
curl -I https://kbin.yourdomain.com/
You should see 200 OK with Content-Type: text/html.
Set up the Vigilmon monitor:
- Log in to Vigilmon and click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/. - Set Check interval to
60 seconds. - Set Expected status code to
200. - Under Advanced → Keyword check, add keyword present:
kbin. - Save the monitor.
Step 2: Monitor PHP-FPM Process Pool Health
PHP-FPM manages the pool of worker processes that handle all Kbin PHP requests. Under heavy federation load — incoming ActivityPub deliveries, outgoing queue processing, or a crawl burst — the pool can exhaust itself. When max children are reached, Nginx returns 502 errors while the site appears technically "up."
Kbin ships with a PHP-FPM health endpoint at /php-fpm-ping (configured in your pool's pm.status_path and ping.path). Enable it in /etc/php/8.x/fpm/pool.d/www.conf:
ping.path = /php-fpm-ping
ping.response = pong
pm.status_path = /php-fpm-status
Expose the ping path through Nginx:
location = /php-fpm-ping {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
For external monitoring, create a lightweight status route in your Nginx config that proxies to the FPM ping internally, or add a thin /health endpoint to Kbin's routing that returns 200 if FPM is responsive.
Then in Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/health(or whichever route you expose). - Set Expected status code to
200. - Set Check interval to
60 seconds. - Save.
Step 3: Monitor PostgreSQL Database Connectivity
Kbin stores magazines, threads, entries, comments, votes, OAuth tokens, and ActivityPub actor records in PostgreSQL. A database connectivity failure causes a complete application outage — Symfony's DBAL layer returns 500 errors on every request.
The safest external check is a lightweight Kbin application endpoint that queries the database. Many Symfony apps expose a /healthcheck or /health/db route. If Kbin doesn't expose one by default, you can add a minimal controller:
// src/Controller/HealthController.php
#[Route('/health/db', name: 'health_db')]
public function db(Connection $conn): Response
{
$conn->executeQuery('SELECT 1');
return new JsonResponse(['status' => 'ok']);
}
Restrict the route to trusted IPs in your firewall so it's not publicly abusable.
In Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/health/db. - Set Expected status code to
200. - Under Keyword check, add keyword present:
ok. - Save.
If you see this monitor fail while the main web monitor is up, the problem is almost certainly PostgreSQL connectivity or a pool exhaustion issue.
Step 4: Monitor Redis Cache Health
Kbin uses Redis as a session store, cache backend, and rate-limiting store. A Redis outage causes session-based authentication to fail (users get logged out or can't log in), cached magazine listings to fall back to slow database queries, and rate limiting to stop enforcing. Performance degrades sharply; some routes return errors.
Add a Redis health check route to Kbin, or expose the Redis PING command through a lightweight endpoint:
#[Route('/health/redis', name: 'health_redis')]
public function redis(\Redis $redis): Response
{
$result = $redis->ping('healthcheck');
return new JsonResponse(['status' => $result === 'healthcheck' ? 'ok' : 'error']);
}
In Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/health/redis. - Set Expected status code to
200. - Under Keyword check, add keyword present:
ok. - Save.
Step 5: Monitor RabbitMQ Queue Depth
RabbitMQ is Kbin's async message transport for Symfony Messenger. All ActivityPub federation deliveries — outgoing posts to followers on other servers, incoming activities from remote actors — flow through RabbitMQ queues. A growing queue with idle consumers means federation is falling behind. A queue with zero consumers means the Symfony Messenger workers have stopped.
The RabbitMQ management API at port 15672 exposes queue depth:
curl -u guest:guest http://localhost:15672/api/queues/%2F/messages
For an external HTTP monitor, you need to expose this through a secure proxy or add a Symfony health check that queries the AMQP management API:
#[Route('/health/rabbitmq', name: 'health_rabbitmq')]
public function rabbitmq(): Response
{
$ch = curl_init('http://localhost:15672/api/healthchecks/node');
curl_setopt($ch, CURLOPT_USERPWD, 'guest:guest');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
return new JsonResponse(['status' => ($result['status'] ?? '') === 'ok' ? 'ok' : 'error']);
}
In Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/health/rabbitmq. - Set Expected status code to
200. - Under Keyword check, add keyword present:
ok, keyword absent:error. - Save.
Step 6: Monitor the Mercure Hub
Kbin uses Mercure for real-time push events — live vote counts, new comment notifications, and live feed updates on magazine pages. The Mercure hub runs as a separate service (typically on port 3000 or behind a subpath on your main domain).
Test it:
curl -I https://kbin.yourdomain.com/.well-known/mercure
You should see a 200 or 405 response (the hub accepts GET for SSE subscriptions and rejects others, both of which indicate the hub is alive).
In Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/.well-known/mercure. - Set Expected status code to one of
200,405(Mercure returns 405 for unauthenticated GET on some versions). - Set Check interval to
60 seconds. - Save.
When the Mercure hub is down, users see a degraded experience with no live updates, but the site remains functional — so this is a warning-priority alert rather than an immediate critical alert.
Step 7: Monitor ActivityPub Federation Endpoints
Kbin's ActivityPub implementation exposes inbox and outbox endpoints for each magazine and user actor. These are the entry points for all federated traffic from other servers. An unhealthy inbox means remote servers can't deliver posts or interactions to your Kbin instance.
Check the WebFinger discovery endpoint first — it's the starting point for federation discovery:
curl "https://kbin.yourdomain.com/.well-known/webfinger?resource=acct:magazine@kbin.yourdomain.com"
In Vigilmon:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/.well-known/webfinger?resource=acct:admin@kbin.yourdomain.com. - Set Expected status code to
200. - Under Keyword check, add keyword present:
subject. - Save.
Then check the NodeInfo endpoint for federation health:
- Click New Monitor → HTTP.
- Set URL to
https://kbin.yourdomain.com/.well-known/nodeinfo. - Set Expected status code to
200. - Under Keyword check, add keyword present:
links. - Save.
Step 8: Heartbeat Monitor for Symfony Messenger Workers
Symfony Messenger workers (bin/console messenger:consume) process the RabbitMQ queues. When workers stop — due to memory limits, crashes, or messenger:stop-workers being called — the queues fill up and federation stalls. Unlike web requests, worker crashes are completely invisible without explicit monitoring.
Configure the worker to send a heartbeat to Vigilmon after each successful message processing batch:
Step 8a: Create a Vigilmon heartbeat monitor.
- Click New Monitor → Heartbeat in Vigilmon.
- Set Name to
Kbin Messenger Worker. - Set Expected heartbeat interval to
5 minutes. - Save. Copy the Heartbeat URL shown (e.g.,
https://vigilmon.online/heartbeat/abc123).
Step 8b: Configure the worker to ping Vigilmon.
Add a Messenger event subscriber that fires after each message is handled:
// src/EventSubscriber/MessengerHeartbeatSubscriber.php
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
class MessengerHeartbeatSubscriber implements EventSubscriberInterface
{
private int $messageCount = 0;
public static function getSubscribedEvents(): array
{
return [WorkerMessageHandledEvent::class => 'onMessageHandled'];
}
public function onMessageHandled(): void
{
if (++$this->messageCount % 10 === 0) {
file_get_contents('https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_TOKEN');
}
}
}
Or add a simpler cron-based approach — ping the heartbeat URL from a system cron that checks whether the worker process is alive:
# /etc/cron.d/kbin-messenger-heartbeat
*/5 * * * * www-data pgrep -f "messenger:consume" && curl -fsS https://vigilmon.online/heartbeat/YOUR_TOKEN
If the messenger worker crashes, this cron check will fail (pgrep returns non-zero) and the heartbeat ping won't be sent. Vigilmon will alert you after the expected interval passes without a ping.
Step 9: SSL Certificate Expiry Alerts
Kbin instances must run over HTTPS for ActivityPub federation to work with most servers. Let's Encrypt certificates are widely used but renewal failures are silent.
- Open the web UI monitor from Step 1.
- Enable Monitor SSL certificate.
- Set Alert when certificate expires in less than
21 days. - Save.
Alerting Configuration
Set up notification channels so you're alerted immediately on failures:
- In Vigilmon, go to Alerts → Notification Channels.
- Add an Email channel with your admin address.
- Optionally add a Slack webhook for your ops channel.
- Assign all Kbin monitors to these notification channels.
Recommended alert thresholds:
| Monitor | Alert after | |---|---| | Web UI | 2 consecutive failures (2 min) | | PHP-FPM health | 2 consecutive failures | | PostgreSQL health | 1 failure (immediate) | | Redis health | 2 consecutive failures | | RabbitMQ health | 3 consecutive failures | | Mercure hub | 5 consecutive failures | | ActivityPub/WebFinger | 3 consecutive failures | | Messenger worker heartbeat | 1 missed heartbeat (5 min) | | SSL certificate | 21 days before expiry |
The PostgreSQL and Messenger worker alerts should be highest priority — a database failure or queue worker crash causes immediate user-visible breakage. The Mercure and Elasticsearch monitors can have slightly more tolerance since they affect real-time features but not core functionality.
Conclusion
A healthy Kbin instance is more than just an accessible homepage. Federation depends on RabbitMQ queues staying drained, Symfony Messenger workers staying alive, and PHP-FPM not exhausting its process pool under load. Without external monitoring, any of these can fail silently for hours.
With Vigilmon watching your Kbin web interface, PHP-FPM pool, PostgreSQL connectivity, Redis cache, RabbitMQ queue health, Mercure hub, ActivityPub endpoints, and Messenger worker heartbeat, you'll know about failures within minutes rather than learning about them from your users.
Start monitoring your Kbin instance for free at vigilmon.online.