A minimal file upload/pastebin service with client-side highlighting.
Go to file
Dan Ponte b7350f340d Update readme 2023-05-18 11:05:44 -04:00
.github feat(deps): allow using openssl for tls (#37) 2023-05-17 11:30:59 +02:00
extra/systemd chore(systemd): add systemd service files (#22) 2022-03-25 23:51:20 +03:00
fixtures feat(server): add landing page (#26) 2022-10-03 21:27:35 +00:00
img docs(readme): add README.md 2021-07-26 21:29:46 +03:00
shuttle feat(deploy): deploy on shuttle.rs (#36) 2023-05-14 18:03:53 +02:00
src Separate into mod 2023-05-18 11:01:04 -04:00
.dockerignore feat(deploy): deploy on shuttle.rs (#36) 2023-05-14 18:03:53 +02:00
.env refactor(server): use .env for auth token 2021-07-24 14:10:30 +03:00
.gitignore test(fixtures): add a test framework along with test fixtures 2022-05-21 15:27:38 +03:00
CHANGELOG.md chore(release): prepare for v0.9.0 2023-05-17 13:47:01 +03:00
Cargo.lock Add prettyness. 2023-05-17 08:10:01 -04:00
Cargo.toml Add prettyness. 2023-05-17 08:10:01 -04:00
Dockerfile chore(docker): enable dependency caching in Dockerfile 2023-05-14 21:57:27 +03:00
LICENSE docs(license): update copyright years 2023-01-01 20:38:12 +03:00
README.md Update readme 2023-05-18 11:05:44 -04:00
codecov.yml chore(codecov): add codecov config (#21) 2022-03-17 00:29:26 +03:00
config.toml Separate into mod 2023-05-18 11:01:04 -04:00
docker-compose.yml chore(docker): share the config file between host and container 2021-08-09 23:27:35 +03:00


GitHub Release Crate Release Coverage Continuous Integration Continuous Deployment Docker Builds Documentation

Rustypaste-pretty is a minimal file upload/pastebin service with client side highlighting provided by highlight.js.

It will use pretty mode if the client sends an Accept: header with text/html present and server.pretty_default is true in the config, or if ?pretty is in the query string. Use ?nopretty in the query string to force disable.

$ echo "some text" > awesome.txt

$ curl -F "file=@awesome.txt" https://paste.site.com

$ curl https://paste.site.com/safe-toad.txt
some text

The public instance is available at https://rustypaste.shuttleapp.rs 🚀


  • File upload & URL shortening & upload from URL
    • supports basic HTTP authentication
    • random file names (optional)
      • pet name (e.g. capital-mosquito.txt)
      • alphanumeric string (e.g. yB84D2Dv.txt)
    • supports expiring links
      • auto-expiration of files (optional)
      • auto-deletion of expired files (optional)
    • supports one shot links (can only be viewed once)
    • guesses MIME types
      • supports overriding and blacklisting
      • supports forcing to download via ?download=true
    • no duplicate uploads (optional)
  • Single binary
  • Simple configuration
    • supports hot reloading
  • Easy to deploy
  • No database
    • filesystem is used
  • Self-hosted
    • centralization is bad!
  • Written in Rust
    • blazingly fast!


From crates.io

cargo install rustypaste

Arch Linux

pacman -S rustypaste

Alpine Linux

rustypaste is available for Alpine Edge. It can be installed via apk after enabling the testing repository.

apk add rustypaste

Binary releases

See the available binaries on the releases page.

Build from source

git clone https://github.com/orhun/rustypaste.git
cd rustypaste/
cargo build --release

Feature flags

  • shuttle: enable an entry point for deploying on Shuttle
  • openssl: use distro OpenSSL (binary size is reduced ~20% in release mode)
  • rustls: use rustls (enabled as default)

To enable a feature for build, pass --features flag to cargo build command.

For example, to reuse the OpenSSL present on a distro already:

cargo build --release --no-default-features --features openssl


Unit tests
cargo test -- --test-threads 1
Test Fixtures


The standalone command line tool (rpaste) is available here.


function rpaste() {
  curl -F "file=@$1" -H "Authorization: <auth_token>" "<server_address>"

* consider reading authorization headers from a file. (e.g. -H @rpaste_auth)

# upload a file
$ rpaste x.txt

# paste from stdin
$ rpaste -


$ curl -F "file=@x.txt" -H "expire:10min" "<server_address>"

(supported units: ns, us, ms, sec, min, hours, days, weeks, months, years)

One shot

$ curl -F "oneshot=@x.txt" "<server_address>"

URL shortening

$ curl -F "url=https://example.com/some/long/url" "<server_address>"

Paste file from remote URL

$ curl -F "remote=https://example.com/file.png" "<server_address>"

Cleaning up expired files

Configure delete_expired_files to set an interval for deleting the expired files automatically.

On the other hand, following script can be used as cron for cleaning up the expired files manually:

#!/bin/env sh
now=$(date +%s)
find upload/ -maxdepth 2 -type f -iname "*.[0-9]*" |
while read -r filename; do
	[ "$(( ${filename##*.} / 1000 - "${now}" ))" -lt 0 ] && rm -v "${filename}"


To start the server:

$ rustypaste

If the configuration file is not found in the current directory, specify it via CONFIG environment variable:

$ CONFIG="$HOME/.rustypaste.toml" rustypaste

To enable basic HTTP auth, set the AUTH_TOKEN environment variable (via .env):

$ echo "AUTH_TOKEN=$(openssl rand -base64 16)" > .env
$ rustypaste

See config.toml for configuration options.


Following command can be used to run a container which is built from the Dockerfile in this repository:

$ docker run --rm -d \
  -v "$(pwd)/upload/":/app/upload \
  -v "$(pwd)/config.toml":/app/config.toml \
  --env-file "$(pwd)/.env" \
  -e "RUST_LOG=debug" \
  -p 8000:8000 \
  --name rustypaste \
  • uploaded files go into ./upload (on the host machine)
  • set the AUTH_TOKEN via -e or --env-file to enable auth

You can build this image using docker build -t rustypaste . command.

If you want to run the image using docker compose, simply run docker-compose up -d. (see docker-compose.yml)


Example server configuration with reverse proxy:

server {
    listen 80;
    location / {
        proxy_pass                         http://localhost:8000/;
        proxy_set_header Host              $host;
        proxy_set_header X-Forwarded-For   $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header X-XSS-Protection        "1; mode=block";
        add_header X-Frame-Options         "sameorigin";
        add_header X-Content-Type-Options  "nosniff";

If you get a 413 Request Entity Too Large error during upload, set the max body size in nginx.conf:

http {
    # ...
    client_max_body_size 100M;


Pull requests are welcome!

Consider submitting your ideas via issues first and check out the existing issues.


All code is licensed under The MIT License.