Skip to content

Add nginx reverse proxy for Plausible analytics and security filtering#2595

Open
mroderick wants to merge 1 commit intocodebar:masterfrom
mroderick:feature/nginx-plausible-proxy-clean
Open

Add nginx reverse proxy for Plausible analytics and security filtering#2595
mroderick wants to merge 1 commit intocodebar:masterfrom
mroderick:feature/nginx-plausible-proxy-clean

Conversation

@mroderick
Copy link
Copy Markdown
Collaborator

@mroderick mroderick commented Apr 25, 2026

Summary

This PR implements the proposal from #2580 to run nginx as a reverse proxy in front of Rails on Heroku. This achieves two primary goals:

  1. Plausible Proxy — Serve Plausible analytics through our domain, bypassing adblockers
  2. Security Filtering — Block obvious bad actors and common attack patterns before they reach Rails

Changes

Infrastructure

  • Add heroku-community/nginx buildpack configuration (config/nginx.conf.erb)
  • Update Procfile to use bin/start-nginx wrapper
  • Configure Puma to bind to Unix socket on Heroku (config/puma.rb)

Analytics

  • Update Plausible snippet to use proxied endpoints (/js/script.js, /api/event)
  • Pass through Cache-Control headers from Plausible

Security

  • Block known malicious user agents (Nikto, sqlmap, etc.) — returns HTTP 444
  • Block common attack paths (WordPress, config files, admin tools)
  • Add security headers at nginx level:
    • X-Frame-Options: SAMEORIGIN
    • X-Content-Type-Options: nosniff
    • X-XSS-Protection: 1; mode=block
    • Referrer-Policy: strict-origin-when-cross-origin
  • Set proxy timeouts (5s connect/send, 10s read)
  • Limit request body size on analytics endpoint (1m)
  • Restrict Unix socket permissions to owner-only (umask 0077)

Security Review

This implementation has been reviewed against OWASP Top 10 (2021):

  • ✅ A01 Broken Access Control — Socket permissions, path blocking
  • ✅ A05 Security Misconfiguration — Security headers present
  • ✅ A06 Vulnerable Components — Official buildpack, timeouts configured
  • All other categories: No issues identified

Deployment

Required (one-time):

heroku buildpacks:add --index 1 heroku-community/nginx --app codebar-staging
heroku buildpacks:add --index 1 heroku-community/nginx --app codebar-production

Deployment:

  1. Deploy to staging first
  2. Run manual testing checklist (see Testing section below)
  3. Monitor for 24 hours
  4. Deploy to production

Testing Checklist

Plausible Proxy:

  • /js/script.js returns Plausible script with correct content-type
  • /api/event accepts POST and forwards to Plausible
  • Plausible dashboard shows events from staging
  • Response headers include Cache-Control from Plausible

Security Filters:

  • curl -A "Nikto" https://staging/ returns 444 (no response)
  • curl https://staging/.env returns 444
  • curl https://staging/wp-admin returns 444

Rails Functionality:

  • Homepage loads correctly
  • Login works
  • Workshop pages load
  • Admin area accessible (with auth)
  • Assets load (CSS, JS, images)
  • Forms submit correctly

Rollback

If issues arise:

heroku buildpacks:remove heroku-community/nginx --app codebar-production
heroku rollback --app codebar-production

References

- Add nginx configuration with Plausible proxy routes and security filters
- Configure Puma to bind to Unix socket with restricted permissions
- Update Procfile to use bin/start-nginx wrapper
- Update Plausible snippet to use proxied endpoints (/js/script.js, /api/event)

Security features:
- Block malicious user agents (Nikto, sqlmap, etc.) with HTTP 444
- Block common attack paths (WP admin, .env, .git, etc.)
- Add security headers: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy
- Set proxy timeouts and request size limits
@mroderick mroderick force-pushed the feature/nginx-plausible-proxy-clean branch from 50f96fa to ae07616 Compare April 25, 2026 13:28
@mroderick mroderick requested a review from till April 25, 2026 13:32
@mroderick mroderick marked this pull request as ready for review April 25, 2026 13:56
Comment thread config/nginx.conf.erb
@@ -0,0 +1,84 @@
daemon off;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why doesn't this config use proxy_cache etc. as outlined in the docs?

https://plausible.io/docs/proxy/guides/nginx

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And resolver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants