A lightweight, privacy-focused open-source pastebin with temporary storage. Share code snippets, text, and files securely with automatic expiration.
OpenPasteBin is designed with privacy and minimalism at its core:
- 🔒 Zero Logging: No logs are written to disk - neither access logs, application logs, nor error logs
- 🚫 No Tracking: No analytics, no cookies, no user tracking whatsoever
- 💾 Temporary Only: All data is automatically deleted after expiration - nothing persists permanently
- 🔐 End-to-End Encryption: All paste content is encrypted with AES-256-GCM before storage - never stored in cleartext
- 🪶 Lightweight: Minimal resource footprint, fast performance
- 🔐 Privacy-First: No accounts, no authentication, complete anonymity
Data is encrypted at the application level with AES-256-GCM, stored temporarily in MongoDB, and automatically removed upon expiration. Nothing is logged, tracked, or stored in cleartext.
- Text & Code Sharing: Share code snippets with syntax highlighting for 15+ languages (JavaScript, Python, Java, Go, Rust, PHP, HTML, CSS, JSON, SQL, Bash, and more)
- File Uploads: Upload programming files up to 5MB (only text/code files allowed)
- Temporary Storage: All pastes automatically expire (30 days max for text, 24 hours max for files)
- Auto Language Detection: Automatically detects programming language from content
- Syntax Highlighting: Powered by highlight.js with GitHub Dark/Light themes
- Prettify JSON: One-click JSON formatting with proper indentation
- Paste Editing: Edit pastes after creation with optional edit password protection
- Light/Dark Theme: Animated theme toggle with smooth moon/sun transition (View Transitions API)
- Raw View: Direct access to raw content
- Download Files: Easy file download functionality
- Responsive Design: Modern "hacker-lite" theme optimized for desktop and mobile
- PWA Support: Full favicon set and web manifest for Progressive Web App
- 🔐 AES-256-GCM Encryption: All paste content encrypted at application level before database storage - never stored in cleartext
- 🔐 Password Protection: Protect pastes with bcrypt-hashed passwords (10 rounds)
- View Password: Required to view the paste content
- Edit Password: Optional separate password for editing (independent from view password)
- ✂️ Split Token: Split sensitive content into 2 separate URLs for extra security
- 🔥 Burn After Read: Set max views (1, 2, 5, 10) - paste auto-deletes when limit reached
⚠️ Security Warnings: Automatic detection of API keys, tokens, and passwords with best practice recommendations- 🔒 Multi-Channel Sharing: Guidance for splitting tokens across different communication channels
- ⚡ Custom URL Warning: Visual warning when using custom URLs without password protection (yellow border + warning message)
- Short URLs: Clean, 8-character URLs using nanoid (281 trillion combinations)
- Custom Short URLs: Personalize your paste URLs with custom slugs (format:
[2 digits][your-slug][1 digit])- Minimum 6 characters
- Must contain at least 1 number or special character
- Not compatible with Split Token feature
⚠️ Security Note: Custom URLs have only 900 combinations per slug - password protection is strongly recommended
- RESTful API: Full API for programmatic access (create, view, edit, delete)
- Paste Editing API: PUT endpoint for updating paste content with password verification
- Auto-Cleanup: Automatic deletion of expired pastes every minute
- No Accounts Required: Completely anonymous usage
- 1:1 Content Preservation: Perfect whitespace, tab, and newline preservation
- Auto Language Re-detection: Language automatically re-detected after edits
- Node.js with Express
- MongoDB with Mongoose for data storage
- AES-256-GCM for content encryption (Node.js crypto module)
- bcrypt for password hashing (10 rounds)
- Multer for file uploads
- Nanoid for URL generation
- Automatic cleanup of expired pastes
- React 18 with Vite
- Axios for API calls
- highlight.js for syntax highlighting (15+ languages)
- Modern CSS with GitHub Dark/Light themes
- View Transitions API for smooth theme switching
- LocalStorage for user preferences (theme, security warnings)
- PWA ready with full favicon set and web manifest
- Docker & Docker Compose
- Caddy or Nginx as reverse proxy
- Health checks and auto-restart
- External
caddy-netnetwork support
- Docker and Docker Compose installed
- Git (optional, for cloning)
Just one command to start everything:
docker compose upThis will automatically:
- ✅ Build all containers (frontend, backend, MongoDB)
- ✅ Start all services
- ✅ Create necessary networks and volumes
- ✅ Make the app accessible at
http://localhost(frontend) andhttp://localhost:5000(backend API)
Note: The first run might take a few minutes to build. Subsequent starts are instant.
Common commands:
# Run in background (detached mode)
docker compose up -d
# Stop all containers
docker compose down
# Rebuild after code changes
docker compose up --build
# View logs
docker compose logs -f
# Remove everything including volumes
docker compose down -vIf you see a caddy-net error: Simply create it once:
docker network create caddy-net(You don't need Caddy installed, just the network needs to exist)
- Clone the repository:
git clone https://github.com/weisser-dev/openpastebin.git
cd openpastebin- For Caddy reverse proxy, ensure
caddy-netnetwork exists:
docker network create caddy-net- Start the application:
docker compose up -d- Configure your reverse proxy (see Production Deployment section below)
That's it! The application will be running with all services connected.
POST /api/paste
Content-Type: application/json
{
"content": "Your text or code here",
"title": "My Paste",
"type": "text",
"language": "javascript",
"expiresValue": 15,
"expiresUnit": "minutes",
"password": "optional-password",
"isSplit": false,
"maxViews": null,
"customUrl": "mylink123"
}Response (Regular Paste):
{
"success": true,
"id": "abc12345",
"url": "http://localhost/abc12345",
"expiresAt": "2024-01-01T12:30:00.000Z",
"detectedLanguage": "javascript"
}Response (Split Token):
{
"success": true,
"isSplit": true,
"id1": "abc12345",
"id2": "xyz67890",
"url1": "http://localhost/abc12345",
"url2": "http://localhost/xyz67890",
"expiresAt": "2024-01-01T12:30:00.000Z"
}Response (Custom URL):
{
"success": true,
"id": "42mylink!7",
"url": "http://localhost/42mylink!7",
"expiresAt": "2024-01-01T12:30:00.000Z",
"detectedLanguage": "javascript"
}POST /api/upload
Content-Type: multipart/form-data
file: [binary file]
expiresValue: 15
expiresUnit: "minutes"Note: Files are limited to 5MB and must be programming/text files only. Max expiration: 24 hours.
GET /api/paste/:idResponse (Password Protected):
{
"id": "abc12345",
"title": "My Paste",
"passwordProtected": true,
"expiresAt": "2024-01-01T12:30:00.000Z"
}POST /api/paste/:id/verify
Content-Type: application/json
{
"password": "your-password"
}GET /api/raw/:idDELETE /api/paste/:idGET /api/statsBackend (backend/.env):
NODE_ENV=production
PORT=5000
MONGO_URI=mongodb://mongodb:27017/openpastebinExpiration Times: Edit frontend/src/App.jsx to modify available expiration options
File Size Limit: Edit backend/server.js line 29 to change the 10MB limit
MongoDB Cleanup: Edit backend/server.js line 40 to change cleanup interval
This project is configured to work with Caddy reverse proxy out of the box.
- Ensure your Caddy is running and has the
caddy-netDocker network:
docker network create caddy-net- Add this configuration to your Caddyfile:
paste.weisser.dev {
reverse_proxy openpastebin-frontend:80
encode gzip zstd
}
Or use the provided Caddyfile.example as a template.
- Start OpenPasteBin:
docker-compose up -dThe frontend container will automatically join the caddy-net network and be accessible to Caddy. HTTPS is automatically configured by Caddy.
The frontend is a static SPA and can be hosted on Cloudflare Pages. The backend keeps running on
your own server under its own hostname (for example api.paste.example.org); the backend already
answers cross-origin requests (cors()), so no proxy is needed.
| Setting | Value |
|---|---|
| Production branch | main |
| Root directory | frontend |
| Build command | npm ci && npm run build |
| Build output directory | dist |
NODE_VERSION |
22 |
VITE_API_BASE |
https://api.paste.example.org (build-time, no trailing slash; leave unset for same-origin behind nginx) |
public/_redirects (SPA fallback) and public/_headers (no-cache for HTML, immutable for
/assets/*) are copied into dist. The backend hostname must stay reachable over HTTPS and
forward /api/* to the backend container (port 5000). Uploads (up to 10 MB) go directly from the
browser to that host, not through Pages. The nginx container image is only needed for the
self-hosted setup.
For deployment behind Nginx:
- Update
docker-compose.ymlto expose the frontend port:
services:
frontend:
ports:
- "127.0.0.1:3000:80"- Configure Nginx:
server {
listen 80;
server_name paste.weisser.dev;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}- Enable SSL with Let's Encrypt:
certbot --nginx -d paste.weisser.dev- Always use HTTPS in production
- Keep Docker images updated
- Use strong MongoDB credentials if exposing the database
- Implement rate limiting on the reverse proxy
- Monitor logs regularly
- Set up backup for MongoDB data
Backend:
cd backend
npm install
npm run devFrontend:
cd frontend
npm install
npm run devopenpastebin/
├── backend/
│ ├── server.js # Express server & API
│ ├── package.json
│ └── Dockerfile
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Main React component
│ │ ├── main.jsx # Entry point
│ │ └── index.css # Styles
│ ├── index.html
│ ├── vite.config.js
│ ├── package.json
│ ├── Dockerfile
│ └── nginx.conf # Nginx configuration
├── docker-compose.yml # Docker orchestration
└── README.md
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f backend
docker-compose logs -f frontendcurl http://localhost:5000/api/healthcurl http://localhost:5000/api/stats# Check logs
docker-compose logs
# Restart services
docker-compose restart
# Rebuild from scratch
docker-compose down -v
docker-compose up --build- Ensure MongoDB service is healthy:
docker-compose ps - Check MongoDB logs:
docker-compose logs mongodb - Verify network connectivity
If ports 80 or 5000 are already in use, modify docker-compose.yml to use different ports.
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
OpenPasteBin is feature-complete with all planned functionality:
- ✅ Syntax highlighting for 15+ programming languages (JavaScript, Python, Java, Go, Rust, PHP, HTML, CSS, JSON, SQL, Bash, and more)
- ✅ Password protection with bcrypt encryption
- ✅ Custom expiration times (seconds, minutes, hours, days - max 30 days for text, 24h for files)
- ✅ Burn After Read with max views (1, 2, 5, 10 views)
- ✅ Auto language detection from content
- ✅ Custom short URLs with personalized slugs
- ✅ Split Token security feature (content split into 2 parts)
- ✅ Security warnings for API keys, tokens, and passwords
- ✅ Paste editing with optional edit password protection
- ✅ Light/Dark theme toggle with animated moon/sun transition
- ✅ Favicon with PWA support
- ✅ File uploads (5MB max, programming files only)
- ✅ 1:1 content preservation (whitespace, tabs, newlines)
- ✅ Prettify JSON with one-click formatting
- ✅ View Transitions API for smooth theme changes
The project is now production-ready and actively maintained. Future updates will focus on bug fixes, performance improvements, and security enhancements.
For issues, questions, or suggestions:
- Open an issue on GitHub
- Check existing issues for solutions
Built with modern web technologies and a focus on privacy and simplicity.
Made with ❤️ by the open-source community