Simple file upload and sharing tool
  • Go 80.3%
  • HTML 11%
  • Makefile 4.2%
  • Nix 2.8%
  • CSS 1.7%
Find a file
2026-07-19 00:22:35 +02:00
cmd feat: add a migration tool. 2026-07-18 22:17:37 +02:00
internal feat: add a migration tool. 2026-07-18 22:17:37 +02:00
public/views feat: add intinity scrolling. 2026-07-18 21:50:18 +02:00
static/css Serve basic files page. 2023-12-21 11:22:31 +01:00
.envrc Use nix-direnv flake support. 2024-03-07 19:50:22 +01:00
.gitignore feat: add bin artifact to gitignore. 2026-07-19 00:22:35 +02:00
assets.go feat: refactoring the codebase, dropped echo dependency. 2026-07-18 21:37:40 +02:00
default.nix fix: make it so can run with nix run 'repo link#migrate/default' 2026-07-18 22:23:44 +02:00
flake.lock feat: simplity the now redundant nix flake. 2026-07-18 21:56:57 +02:00
flake.nix fix: make it so can run with nix run 'repo link#migrate/default' 2026-07-18 22:23:44 +02:00
go.mod feat: refactoring the codebase, dropped echo dependency. 2026-07-18 21:37:40 +02:00
LICENSE Start a go rewrite. 2023-12-21 11:22:31 +01:00
Makefile feat: add a migration tool. 2026-07-18 22:17:37 +02:00
README.md feat: update README.md 2026-07-18 22:07:09 +02:00
shell.nix feat: simplity the now redundant nix flake. 2026-07-18 21:56:57 +02:00

UpFast

Minimal file upload and sharing tool. Influenced by 0x0.st.

Upload files via curl or browser, get a shareable URL back. Files are listed with previews for images, videos, and text.

curl -F "file=@/path/to/image.jpg" https://upfast.example.com
# → https://upfast.example.com/files/image.jpg

Features

  • Single binary — zero runtime dependencies, pure Go
  • Upload via curl (-F "file=@...") or browser form
  • File listing with inline previews (images, videos, text)
  • Infinite scroll on the file listing page (loads 20 files at a time)
  • curl-aware — returns plain text for curl, HTML for browsers
  • Delete files via curl -X DELETE
  • JSON APIGET /api/files?offset=0&limit=20 for pagination
  • Metadata sidecar — file types detected once at upload, saved in meta.json
  • No external dependencies — uses only Go standard library (Go 1.23+)

Quick start

# Build
go build -o upfast ./cmd/upfast

# Run (default: http://127.0.0.1:1323)
./upfast

# Or with options
./upfast -p 8080 -a 0.0.0.0 -d https://upfast.example.com

Or using the Makefile:

make build   # -> bin/upfast
make run     # -> runs on :1323
make run ARGS="-p 8080 -a 0.0.0.0 -d https://upfast.example.com"

Usage

Upload a file

curl -F "file=@/path/to/image.jpg" http://127.0.0.1:1323
# → http://127.0.0.1:1323/files/image.jpg

List all files (plain text)

curl http://127.0.0.1:1323/files
# → image.jpg
# → notes.txt

List via browser

Open http://127.0.0.1:1323/files in a browser. The page loads the first 20 files and automatically loads more as you scroll.

Delete a file

curl -X DELETE http://127.0.0.1:1323/files/image.jpg
# → Deleted file from server: image.jpg

JSON API (for custom clients)

curl 'http://127.0.0.1:1323/api/files?offset=0&limit=10'
# → {"files":[{"name":"image.jpg","fileType":"image","url":"...","size":12345}],"hasMore":false,"offset":0,"limit":10}

Development

Prerequisites

  • Go 1.23 or later
  • Optionally: Nix for the dev shell

Commands

make all        # fmt → vet → lint → test → build
make test       # run all tests
make test-race  # run tests with race detector
make test-cover # run tests with coverage report
make lint       # run golangci-lint
make fmt        # format code with gofumpt
make clean      # remove build artifacts

Nix shell

A flake.nix and shell.nix are provided for a reproducible development environment:

nix develop          # enter dev shell (Go 1.26, golangci-lint, gopls, etc.)
nix build            # build the package
nix flake check      # run all checks (build + lint)

Project structure

├── assets.go              ← Embedded templates and static files
├── cmd/
│   └── upfast/
│       └── main.go        ← Entry point
├── internal/
│   ├── handler/           ← HTTP handlers (one file per endpoint)
│   │   ├── handler.go     ← Shared Handler struct + helpers
│   │   ├── index.go       ← GET /
│   │   ├── upload.go      ← POST /
│   │   ├── files.go       ← GET /files/ + GET /api/files
│   │   ├── delete.go      ← DELETE /files/{file}
│   │   └── handler_test.go
│   ├── server/
│   │   └── server.go      ← Route setup, middleware, Config
│   └── store/
│       ├── store.go       ← Store interface + FileSystemStore
│       └── store_test.go
├── public/views/           ← HTML templates (index, files)
├── static/css/             ← Stylesheets
├── go.mod                  ← Go 1.23, zero dependencies
├── Makefile
├── flake.nix / shell.nix   ← Nix development environment
└── README.md

Deployment

Option A: Direct binary

# Build on the target machine
go build -o /usr/local/bin/upfast ./cmd/upfast

# Or cross-compile from your dev machine
GOOS=linux GOARCH=amd64 go build -o upfast-linux-amd64 ./cmd/upfast

Option B: Nix

nix build           # produces result/bin/upfast
cp result/bin/upfast /usr/local/bin/

Production hardening

Create a dedicated user and limit storage with a virtual filesystem:

# Create upfast user
useradd --shell /usr/sbin/nologin --system -M upfast
usermod -L upfast

# Limit storage with a 20GB loop filesystem
dd if=/dev/zero of=/usr/local/upfast/storage.img bs=1M count=20480
mkfs.ext4 /usr/local/upfast/storage.img
mount -o loop,rw /usr/local/upfast/storage.img /usr/local/upfast/data

# Add to /etc/fstab:
# /usr/local/upfast/storage.img /usr/local/upfast/data ext4 loop,rw,usrquota,grpquota 0 0

# Set ownership
chown upfast:upfast -R /usr/local/upfast
chmod 700 /usr/local/upfast

Systemd service

Create /etc/systemd/system/upfast.service:

[Unit]
Description=UpFast file sharing service
Documentation=https://github.com/cronyakatsuki/upfast
After=network.target

[Service]
User=upfast
Group=upfast
WorkingDirectory=/usr/local/upfast/data
ExecStart=/usr/local/upfast/upfast -p 8000 -a 127.0.0.1 -d https://upfast.example.com
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now upfast

Nginx reverse proxy

server {
    listen 80;
    listen [::]:80;
    server_name upfast.example.com;

    client_max_body_size 0;  # no upload size limit

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

How it works

Files are stored in a files/ directory. Metadata (filename, type, size, upload timestamp) is kept in a files/meta.json sidecar for fast listing without re-reading every file's header.

When a file is uploaded, its content type is detected from the first 512 bytes using magic byte signatures (JPEG, PNG, GIF, MP4, etc.). This happens once at upload time, not on every listing request.

The server detects curl via the User-Agent header and returns plain text responses instead of HTML.

License

MIT