Skip to content
 
 

Repository files navigation

Armbian logo

Armbian Hastebin

Purpose of This Repository

Armbian Hastebin is a lightweight pastebin server written in Go with ANSI color rendering. It began as a fork of haste-server, then was migrated from Node.js to Go, and supports multiple storage backends for saving pastes.

Features

  • ANSI and syntax-highlighted paste rendering
  • Responsive interface with a collapsible mobile toolbar
  • Random or human-readable (phonetic) paste keys
  • Filesystem, Redis, Memcached, MongoDB, PostgreSQL, and S3 storage backends
  • Optional per-paste delete after lifetime
  • Background expired-paste cleanup for the file backend
  • IP-based rate limiting, Prometheus metrics, and a health endpoint
  • Request-body, HTTP-header, and server timeout limits

Built With

  • Go (go.mod targets Go 1.26) — application code under cmd/, handler/, config/, and internal/
  • HTTP router: go-chi/chi with go-chi/httprate for rate limiting
  • Storage clients: redis/go-redis, bradfitz/gomemcache, mongo-driver, jackc/pgx, aws-sdk-go-v2 (S3)
  • Compression: klauspost/compress (gzip, zstd)
  • Observability: prometheus/client_golang, rs/zerolog
  • Testing: stretchr/testify, testcontainers-go (including the MinIO module)
  • Config: gopkg.in/yaml.v3
  • Front-end assets: static HTML/CSS/JS under static/, embedded into the binary via static/static.go
  • Container: multi-stage Dockerfile (Alpine builder → gcr.io/distroless/static:nonroot)

Quick Start

Docker Compose

docker compose up --build

The application listens on http://localhost:7777 by default. Paste files are persisted under ./data (see docker-compose.yaml).

Static assets are embedded in the Go binary, so rebuild the image after changing the UI. If the browser still serves an old JavaScript or CSS asset, use a hard refresh (Ctrl+Shift+R).

Local development

Go 1.26 or newer is required (per go.mod).

go run ./cmd --config config.yaml

Run the test suite:

go test ./...

Run allocation and throughput benchmarks:

go test -run '^$' -bench . -benchmem ./handler ./internal/storage ./internal/keygenerator

Configuration

The server reads config.yaml from the working directory by default. Use --config /path/to/config.yaml to select another file.

Example:

host: "0.0.0.0"
port: 7777
key_length: 10
max_length: 4000000 # bytes
key_generator: "phonetic" # phonetic or random
key_space: "abcdefghijklmnopqrstuvwxyz"

storage:
  type: "file"
  file_path: "./data"
  compression: "none" # none, gzip, or zstd

delete_after:
  enable: true

rate_limiting:
  enable: true
  limit: 500
  window: 15 # seconds
  trusted_proxy_count: 0

logging:
  level: "info"
  colorize: true

documents:
  - key: "about"
    path: "./about.md"

Main settings

Key Description
host, port HTTP bind address and port.
key_length Length of generated paste keys.
key_generator phonetic or random.
key_space Character set used only by the random generator.
max_length Maximum accepted paste-body size in bytes.
expiration Default backend TTL in seconds. 0 disables it.
documents Permanent static documents loaded at startup.

Storage settings

Supported storage.type values: file, redis, memcached, mongodb, postgres, and s3.

Field Used by
file_path file
compression file; none, gzip, or zstd
host, port Redis, Memcached, MongoDB, PostgreSQL, and S3 endpoint
username, password Redis, MongoDB, PostgreSQL, and S3
database MongoDB and PostgreSQL
bucket, aws_region S3

The PostgreSQL table and required migrations are created during startup.

Rate limiting and proxies

trusted_proxy_count: 0 is the safe default: the rate-limit key uses the direct TCP peer IP and ignores client-provided X-Forwarded-For headers.

If the service is behind a known number of trusted reverse proxies, for example one Nginx or Traefik proxy:

rate_limiting:
  trusted_proxy_count: 1

Only configure this when those proxies reliably overwrite and forward client-IP headers.

Environment variables

Most YAML values can be overridden with environment variables:

HOST, PORT, KEY_LENGTH, MAX_LENGTH, STATIC_MAX_AGE
KEY_GENERATOR
STORAGE_TYPE, STORAGE_HOST, STORAGE_PORT, STORAGE_USERNAME,
STORAGE_PASSWORD, STORAGE_DATABASE, STORAGE_BUCKET,
STORAGE_AWS_REGION, STORAGE_FILE_PATH, STORAGE_COMPRESSION
LOGGING_LEVEL, LOGGING_COLORIZE
RATE_LIMITING_ENABLE, RATE_LIMITING_LIMIT, RATE_LIMITING_WINDOW,
RATE_LIMITING_TRUSTED_PROXY_COUNT
DELETE_AFTER_ENABLE

Additional static documents can be added as DOCUMENTS_<key>=<path>.

API

Operation Endpoint Response
Create a paste POST /documents { "key": "...", "expires_at": "..." }
Haste-client-compatible upload PUT /log or POST /log Direct URL
Read a paste GET /documents/{key} { "key": "...", "data": "..." }
Read raw content GET /raw/{key} text/plain
Health check GET /health 200 OK
Metrics GET /metrics Prometheus metrics

Paste creation accepts a plain-text request body or a multipart/form-data request with a data field.

Delete after

Enable the feature with delete_after.enable: true. API clients can provide an X-Delete-After header:

curl -X POST http://localhost:7777/documents \
  -H 'Content-Type: text/plain' \
  -H 'X-Delete-After: 1h' \
  --data 'temporary paste'

The value uses Go duration syntax: 10m, 1h, 24h, or 168h. The maximum is 30 days. never, or omitting the header, creates a permanent paste.

  • Redis and Memcached use native TTL support.
  • MongoDB uses a TTL index.
  • PostgreSQL stores a fixed expiry timestamp.
  • The file backend stores .expires metadata and cleans expired pastes at startup and every 10 minutes.
  • S3 stores expiry metadata and deletes an expired object when it is read. Configure an S3 bucket lifecycle policy to remove expired objects that are never read.

When delete_after.enable: false, the UI selector is hidden and API requests with X-Delete-After return 403.

Repository Layout

cmd/                 # Application entry point (main.go)
config/              # YAML/env configuration loader
handler/             # HTTP handlers for documents
internal/keygenerator/  # Random and phonetic key generators
internal/server/     # HTTP server wiring
internal/storage/    # Backends: file, redis, memcached, mongodb, postgres, s3
internal/unsafeconv/ # Internal conversion helper
static/              # Embedded UI assets (HTML/CSS/JS/images)
scripts/compress/    # Auxiliary Go tool
Dockerfile
docker-compose.yaml
config.yaml
about.md

Continuous Integration

For an overview of this repository's CI workflows and their current status, see the Armbian CI dashboard:

https://actions.armbian.com/?repo=hastebin-ansi

License

Licensed under the GNU Affero General Public License v3.0. See LICENSE for the full text.

Related Links

About

Armbian Hastebin fork with ANSI support as well as being rewritten in Go.

Resources

Security policy

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages