A fast, minimal, and secure pastebin alternative β built with FastAPI.
cText lets you share text snippets privately and securely. Pastes are encrypted at rest, can be password-protected, and automatically expire. No accounts, no tracking, no ads.
- π’ Code type selector β choose how the paste code (URL) is generated: numbers only, letters + numbers, or letters only. Thanks to @hujigko for the idea and help.
- π Local timezone β expiry times are now shown in Asia/Tehran local time instead of UTC.
- π¨ UI polish β refined dark dropdowns on mobile, a new neon grid background, and an optional light theme.
- π End-to-end encryption β paste content is encrypted at rest using Fernet (AES-128-CBC)
- π Password protection β optional bcrypt-hashed password per paste
- β³ Auto-expiry β choose expiration from 10 minutes up to 30 days
- π’ Code type selector β generate paste codes as numbers, letters, or both
- π‘οΈ CSRF protection β HMAC-based CSRF tokens on all forms
- π Raw view β direct plaintext access via
/raw/{id} - ποΈ Manual delete β delete your paste at any time
- π§Ή Auto-cleanup β daily cron job removes expired pastes
- π« No registration required β completely anonymous usage
- π HTTPS-first β designed to run behind Nginx with Let's Encrypt SSL
| Layer | Technology |
|---|---|
| Backend | FastAPI + Uvicorn |
| ORM | SQLAlchemy |
| Database | SQLite |
| Encryption | Cryptography (Fernet) |
| Password Hashing | bcrypt |
| Sessions | Starlette SessionMiddleware |
| Templating | Jinja2 |
| Reverse Proxy | Nginx |
| Process Manager | Systemd |
| SSL | Let's Encrypt (Certbot) |
ctext/
βββ app/
β βββ main.py # FastAPI routes and application logic
β βββ models.py # SQLAlchemy models
β βββ db.py # Database session setup
β βββ static/ # CSS, JS, assets
β βββ templates/ # Jinja2 HTML templates
β βββ index.html
β βββ view.html
β βββ created.html
β βββ 404.html
βββ cleanup_expired.py # Standalone cleanup script (used by cron)
βββ requirements.txt
βββ .env # Secret keys (not committed)
βββ pastes.db # SQLite database (auto-created)
- Ubuntu 22.04+ (or similar Debian-based distro)
- Python 3.10+
- Nginx
- Certbot (for SSL)
- A domain pointing to your server
apt update -y && apt upgrade -y && apt autoremove -ysudo apt install -y python3 python3-pip nginxIf you encounter conflicts with typing-extensions:
apt remove --purge python3-typing-extensionsmkdir /var/www/ctext/
cd /var/www/ctext/
git clone https://github.com/DevURANIUM/cText.git .
pip install -r requirements.txt --break-system-packagesCreate the .env file:
nano /var/www/ctext/.envAdd the following:
PASTE_SECRET_KEY=
SESSION_SECRET_KEY=
CSRF_SESSION_KEY=How to generate each key:
# PASTE_SECRET_KEY (Fernet key β must be this exact format)
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
# SESSION_SECRET_KEY (random URL-safe string)
python3 -c "import secrets; print(secrets.token_urlsafe(64))"
# CSRF_SESSION_KEY (just a session key name, e.g. a short string)
python3 -c "import secrets; print(secrets.token_urlsafe(64))"Example .env after filling in:
PASTE_SECRET_KEY=Ib7k2YourGeneratedFernetKeyHere=
SESSION_SECRET_KEY=yourLongRandomSessionSecretHere
CSRF_SESSION_KEY=csrf_token
β οΈ Never commit.envto version control. Add it to.gitignore.
Create /etc/systemd/system/ctext.service:
[Unit]
Description=ctext FastAPI application
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/ctext
EnvironmentFile=/var/www/ctext/.env
ExecStart=/usr/local/bin/uvicorn app.main:app \
--host 127.0.0.1 \
--port 8001 \
--proxy-headers
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl daemon-reload
sudo systemctl start ctext
sudo systemctl enable ctext
sudo systemctl status ctextCreate /etc/nginx/sites-available/ctext.ir:
server {
listen 80;
server_name ctext.ir;
location / {
proxy_pass http://127.0.0.1:8001;
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 the site:
sudo ln -s /etc/nginx/sites-available/ctext.ir /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxsudo certbot --nginx -d ctext.ir
sudo certbot renew --dry-runchown www-data:www-data /var/www/ctext/pastes.db
chmod 664 /var/www/ctext/pastes.db
chown www-data:www-data /var/www/ctext
chmod 775 /var/www/ctextsudo timedatectl set-timezone Asia/TehranThe app also resolves time using the
Asia/Tehranzone internally (viazoneinfo), so paste expiry times are shown in local time regardless of the host setting.
Run crontab -e and add:
# Run cleanup every day at 03:00 AM
0 3 * * * cd /var/www/ctext && /usr/bin/python3 cleanup_expired.py >> /var/www/ctext/ctext_cleanup.log 2>&1Verify:
crontab -lClient (Browser)
β
βΌ
Nginx :80/:443 ββββ SSL termination (Let's Encrypt)
β
βΌ
Uvicorn :8001 (127.0.0.1 only)
β
βΌ
FastAPI Application
β
βΌ
SQLite (pastes.db)
- Nginx handles all public traffic and TLS
- Uvicorn binds only to localhost for security
- Systemd ensures the process restarts automatically on failure
- Paste content is encrypted at rest using Fernet symmetric encryption
- Passwords are hashed with bcrypt (12 rounds); passwords longer than 72 bytes are SHA-256-prehashed before bcrypt to prevent truncation
- CSRF tokens are signed using
hmac.compare_digestto prevent timing attacks - Sessions use
SameSite=Laxandhttps_only=True - The application process runs as
www-data(least privilege) - Uvicorn binds only to
127.0.0.1β never exposed directly to the internet
sudo systemctl status ctext
sudo nginx -t
sudo certbot renew --dry-runYour application will be live at:
https://ctext.ir
fastapi
uvicorn
gunicorn
jinja2
sqlalchemy
python-dotenv
python-multipart
bcrypt
cryptography
itsdangerous
Install with:
pip install -r requirements.txt --break-system-packages- @hujigko β for the idea and help with the Code type feature, which added the option to generate paste codes as numbers, letters, or both.
If cText is useful to you, consider supporting its development:
| Network | Address |
|---|---|
| BTC | bc1qcclcp574hnznm0nmdzzf0ta7366svjskttqks3 |
| LTC | ltc1qcrkelw38gjrmg0ptjy2nshqej622kp76het7q0 |
| XRP | rPoK5SBChFPqEiQv1W97LW6FKoJZLipDVQ |
| XLM | GDMUQREEZNBSTQOT5BV7MYEMXJFV3CYRZXUVOYCTIUZTHUWPHLVASFVD |
| TON | UQAJH2N0pqpvC9YN841w5NH1dCN9Lakwkpjvoy7vXf-vfqgv |
| TRON | TXJqhhwvkrTdnf5HReZf55hEzZuxjto3R4 |
| USDT (BEP20) | 0x1591036c4bD05b046532B65Df939fcd7824E18c7 |
Every contribution, no matter how small, helps keep the project running. β€οΈ
This project is open source. See LICENSE for details.