Euphoria Paste is an open-source pastebin server written in Node.js and forked from Haste. It supports multiple storage backends and includes a modernized frontend, structured logging, health checks, and safer runtime defaults.
- ES Modules runtime
- Mobile-friendly UI updates
- Line/word/character counters
- Request tracing with
X-Request-Id GET /healthendpoint- Graceful shutdown handling
- Optional Discord webhook logging (explicitly gated)
- Security-focused runtime headers and request limits
- Node.js
>=18
-
Install dependencies:
npm install
-
Start the server:
npm start
-
Open the app:
http://localhost:8080
- The app expects
config.js. - If
config.jsis missing, the server automatically copiesconfig.js.exampletoconfig.json startup. config.jsis ignored by git so local secrets/settings stay local.
npm start— start servernpm run dev— start with auto-reload (nodemon)npm run lint— lint maintained server/store/test filesnpm test— run smoke testsnpm run format— format files with Prettiernpm run format:check— check formatting without changing files
GET /health
Example response:
{
"status": "ok",
"requestId": "f8f5f8c1-4bb0-4d76-9a13-0d0cb5e1f893"
}POST /documents (plain text body)
Success response:
{
"key": "exampleKey",
"requestId": "0a4d2fef-37b0-4100-9077-97d3642b4da7"
}GET /documents/:id
Success response:
{
"data": "document contents",
"key": "exampleKey",
"requestId": "4e946b8e-5ebc-46df-a937-3b8e10f145ca"
}GET /raw/:id
Returns plain text body.
Error payloads now include request tracing:
{
"message": "Document not found.",
"requestId": "40ea3f76-e4ac-4b85-9d03-f8e1d1507ef2"
}Configured in config.js (based on config.js.example):
host— bind host (default0.0.0.0)port— bind port (default8080)keyLength— generated document key lengthmaxLength— max document body lengthstaticMaxAge— static asset cache max-age secondsrecompressStaticAssets— minify static JS on startuppostTimeoutMs— upload timeout forPOST /documentsrequestTimeoutMs— Node server request timeoutheadersTimeoutMs— Node server headers timeoutdocuments— static preloaded documents mapstorage— storage backend configrateLimits— connect-ratelimit settingsdiscordWebhookUrl— webhook URLenableDiscordLogging— must betrueto forward Discord logs
Environment variable overrides used by server:
PORT,HOSTSTORAGE,STORAGE_TYPEDISCORD_WEBHOOK_URLENABLE_DISCORD_LOGGINGPOST_TIMEOUT_MS,REQUEST_TIMEOUT_MS,HEADERS_TIMEOUT_MS
Set storage.type in config.js.
{
"type": "file",
"path": "./data"
}{
"type": "redis",
"host": "localhost",
"port": 6379,
"db": 2
}{
"type": "postgres",
"connectionUrl": "postgres://user:password@host:5432/database"
}{
"type": "mongo",
"connectionUrl": "mongodb://localhost:27017/database"
}{
"type": "memcached",
"host": "127.0.0.1",
"port": 11211
}{
"type": "rethinkdb",
"host": "127.0.0.1",
"port": 28015,
"db": "haste"
}{
"type": "google-datastore"
}{
"type": "amazon-s3",
"bucket": "your-bucket-name",
"region": "us-east-1"
}Uses AWS SDK v3 (@aws-sdk/client-s3).
Workflow: .github/workflows/ci.yml
Runs on push, PR, and weekly schedule:
npm cinpm run lintnpm testnpm audit --omit=dev
This repo includes a Redis profile for local backend testing:
docker compose --profile local-redis up -dThen configure storage.type to redis in config.js.
Run npm start once; the server auto-creates config.js from config.js.example if needed.
Change port in config.js or set PORT env var.
The app uses local static assets (static/favicon.ico, static/logo.png).
Hard refresh browser cache if needed.
Rep Graphics repgraphics@euphoriadevelopment.uk
- jQuery: MIT/GPL
- highlight.js: Copyright © 2006 Ivan Sagalaev
- highlightjs-coffeescript: WTFPL, Copyright © 2011 Dmytrii Nagirniak