
Deploy Feedbacks | (Just Updated) Self-Hosted Website Feedback Capture with REST API & MCP, Owner Pre-Created
Feedbacks self-hosted feedback capture, REST API, MCP, Postgres
postgres
Just deployed
/var/lib/postgresql
feedbacks
Just deployed
Just deployed
/data
Deploy and Host Feedbacks on Railway
Built for an LLM agent to deploy and use. The deploy form has no fields to fill: the owner account is created from generated credentials at first boot, the object-storage bucket is created for you, and the REST API and MCP server take an agent token that the owner mints with one call. Feedbacks is an open-source, self-hosted website feedback tool: a Chrome extension captures screenshots and annotations, and threads, replies, statuses and agent tokens are served over a REST API and a built-in MCP server, on PostgreSQL.
About Hosting Feedbacks
This template runs three services: feedbacks (the web app, the REST API at POST /api/OPERATION (for example /api/projects.list) and the MCP endpoint at /mcp, behind one public domain), postgres (PostgreSQL 18 on a volume mounted at /var/lib/postgresql) and minio (an S3-compatible store, pgsty/silo, on a volume at /data).
Why there is a storage service. In production Feedbacks refuses local storage and starts only with a private S3 bucket on an HTTPS endpoint. The minio service gets a public Railway domain only because that gives the endpoint its HTTPS; it is not anonymous. Every request needs the generated MINIO_ROOT_USER and MINIO_ROOT_PASSWORD, and the console is switched off. The feedbacks service creates the feedbacks bucket on first boot. Point S3_HOST, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY at AWS S3, R2 or any other HTTPS S3 endpoint to replace it.
Created at boot. A stock image has no owner and no way to make one except a CLI, and it needs a unique ORGANIZATION_ID. This template's image creates the owner from ADMIN_EMAIL and ADMIN_PASSWORD, derives a stable ORGANIZATION_ID from the database password, builds DATABASE_URL, APP_ORIGIN and S3_ENDPOINT from the variables, trusts two proxy hops so the real client address reaches the login throttle, and then starts the unmodified upstream server. Sign-up is invite-only.
What persists. Projects, feedback threads, replies, accounts and agent tokens live in the PostgreSQL volume; screenshots and attachments live in the minio volume.
Using the web interface. Open the public URL and sign in with the ADMIN_EMAIL and ADMIN_PASSWORD values from the feedbacks service variables. The Chrome extension pairs with the same URL.
Agent contract
- Public URL:
https://RAILWAY_PUBLIC_DOMAIN(the generated domain of thefeedbacksservice) - Private URL:
http://feedbacks.railway.internal:8080 - Credentials: the variables
ADMIN_EMAILandADMIN_PASSWORDon thefeedbacksservice - Auth:
POST /api/auth.login(JSONemail,password, headerOriginequal to the public URL) sets a session cookie and returnscsrf; with the cookie, the headerX-CSRF-Tokenand the sameOrigin,POST /api/tokens.createreturns an agent token shown once, which is then sent asAuthorization: Bearer TOKENon every/api/OPERATIONand/mcpcall. Without a valid credential the API answers401 - Health:
GET /readyzreturns 200 without credentials
#!/bin/sh
# needs: SITE_URL (public https URL of the feedbacks service), ADMIN_EMAIL and ADMIN_PASSWORD (its variables); also curl, sed
J='Content-Type: application/json'
O="Origin: $SITE_URL"
JAR=$(mktemp)
CSRF=$(curl -s -c "$JAR" -X POST "$SITE_URL/api/auth.login" -H "$J" -H "$O" -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" | sed -n 's/.*"csrf":"\([^"]*\)".*/\1/p')
web() { curl -s -b "$JAR" -X POST "$SITE_URL/api/$1" -H "$J" -H "$O" -H "X-CSRF-Token: $CSRF" -d "$2"; }
curl -s -o /dev/null -w "health: %{http_code}\n" "$SITE_URL/readyz"
curl -s -o /dev/null -w "read without key: %{http_code}\n" -X POST -H "$J" -d '{}' "$SITE_URL/api/projects.list"
curl -s -o /dev/null -w "write without key: %{http_code}\n" -X POST -H "$J" -d '{"name":"x","origins":["https://example.org"]}' "$SITE_URL/api/projects.create"
curl -s -o /dev/null -w "write wrong key: %{http_code}\n" -X POST -H "Authorization: Bearer wrong" -H "$J" -d '{"name":"x","origins":["https://example.org"]}' "$SITE_URL/api/projects.create"
PID=$(web projects.create '{"name":"Agent check","origins":["https://example.org"]}' | sed -n 's/.*"id":"\([^"]*\)".*/\1/p')
echo "project created: $PID"
TOKEN=$(web tokens.create "{\"name\":\"agent\",\"projectIds\":[\"$PID\"],\"scopes\":[\"projects.list\",\"projects.get\",\"threads.list\"]}" | sed -n 's/.*"token":"\([^"]*\)".*/\1/p')
curl -s -X POST -H "Authorization: Bearer $TOKEN" -H "$J" -d '{}' "$SITE_URL/api/projects.list" | sed -n 's/.*"name":"\(Agent check\)".*/agent key read: \1/p'
rm -f "$JAR"
A fresh deploy prints health: 200, read without key: 401, write without key: 401, write wrong key: 401, a created project id and agent key read: Agent check.
Why Deploy Feedbacks on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying Feedbacks on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
- Agent-ready - no deployer fields, a contract block and one script that proves a sign-in, an agent token, an authenticated read and the refusal of a write without a key.
- Boots from an empty form - owner, bucket and organization id are created for you, which the stock image cannot do.
- Data survives redeploys - PostgreSQL and the object store each sit on a volume.
- Pinned - all three images are pinned by digest.
- Your feedback stays yours - no SaaS seat pricing, screenshots stay in your own bucket.
Common Use Cases
- Website and web-app feedback capture - testers and customers send annotated screenshots tied to the page and element.
- Agent-driven triage - a coding agent lists threads, reads screenshots, replies and updates status over the REST API or MCP.
- Bug reporting for QA and staging - collect issues with context from a Chrome extension into one self-hosted inbox.
- UserSnap or Marker.io alternative - self-hosted visual feedback without per-seat pricing.
Dependencies for Feedbacks Hosting
- PostgreSQL, deployed alongside as the
postgresservice, and an S3-compatible bucket, deployed alongside as theminioservice. A custom domain is optional.
Deployment Dependencies
Template Content
