Skip to main content

CLI file sharing and link shortening. Backed by Cloudflare R2 + Workers.

Project description

share

CLI file sharing and link shortening with download tracking. Backed by Cloudflare R2 + Workers KV + Workers. Zero cost, full ownership.

Live at icecube.to ยท ๐ŸงŠ.to

Why

Google Drive has no CLI. transfer.sh is dead. Presigned S3 URLs expire. This uploads a file or shortens a URL, gives you a short link, copies it to clipboard. Done.

$ share upload README.md --slug readme.md --public
https://icecube.to/readme.md (copied)

$ share link https://github.com/adriangalilea/share --slug gh --public
https://icecube.to/gh โ†’ https://github.com/adriangalilea/share (copied)

$ share ls
                              Files
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”“
โ”ƒ Slug      โ”ƒ Name      โ”ƒ     Size โ”ƒ Uploaded   โ”ƒ DLs โ”ƒ Vis โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”ฉ
โ”‚ readme.md โ”‚ README.md โ”‚   7.2 KB โ”‚ 2026-03-19 โ”‚  15 โ”‚ pub โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜
                              Links
โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”“
โ”ƒ Slug โ”ƒ URL                                       โ”ƒ Created    โ”ƒ Clicks โ”ƒ Vis โ”ƒ
โ”กโ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”ฉ
โ”‚ gh   โ”‚ https://github.com/adriangalilea/share     โ”‚ 2026-03-19 โ”‚      2 โ”‚ pub โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜
icecube.to/<slug>

$ share rm gh
Deleted https://github.com/adriangalilea/share (/gh)

This README is shared at icecube.to/readme.md.

Usage

share upload <file>                         # upload file, auto-generate slug
share upload <file> --slug <name>           # custom slug
share upload <file> --public                # show on landing page (default: private)
share upload <file> --name <name>           # override download filename
share upload <file> --keep-metadata         # skip EXIF/metadata stripping
share link <url>                            # shorten a URL
share link <url> --slug <name>              # custom slug for short link
share link <url> --public                   # show on landing page
share ls                                    # list all files and links
share rm <slug>                             # delete by slug, filename, URL, or r2_key
share setup                                 # interactive first-time config

Uploads strip EXIF/metadata by default (images via Pillow, videos via ffmpeg).

Install

uv tool install git+https://github.com/adriangalilea/share.git

Architecture

CLI (Python)                        Cloudflare Free Tier
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    boto3/S3 API    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  share CLI   โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚       R2        โ”‚ files (10GB free)
โ”‚              โ”‚                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚              โ”‚    CF Python SDK           โ”‚
โ”‚              โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              โ”‚                    โ”‚       KV        โ”‚ slug โ†’ metadata
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                            โ”‚
Browser                                     โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  short link  โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ†’ โ”‚     Worker      โ”‚ serves files,
โ”‚              โ”‚                    โ”‚ (custom domain) โ”‚ tracks downloads,
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ landing page

The CLI uploads files to R2 and writes metadata to KV keyed by slug:<slug>. The Worker on your custom domain looks up slugs, streams files from R2 with range request support (for video/audio streaming), and increments download counters.

Every response carries a Content-Disposition header with the original filename so downloads keep their extension regardless of browser or OS (the slug in the URL has no extension; without this header some browsers save the file extensionless). Previewable types โ€” text/*, anything containing json/xml/javascript, image/*, audio/*, video/*, and application/pdf โ€” are served inline so the link still renders in-tab. Everything else (all archives: .7z, .zip, .tar, .gz, .rar, โ€ฆ; binaries; unknown application/octet-stream) is served attachment and downloads with the correct name.

Self-hosting

Prerequisites

  • Python >=3.12, uv
  • Cloudflare account (free tier)
  • Node.js (for worker deployment)
  • A domain pointed to Cloudflare nameservers

1. Install the CLI

uv tool install git+https://github.com/adriangalilea/share.git

2. Create Cloudflare resources

You need two API tokens:

R2 API token (S3-compatible, for file uploads):

  • Cloudflare dashboard โ†’ R2 โ†’ Manage R2 API Tokens โ†’ Create
  • Permissions: Object Read & Write
  • Save the Access Key ID + Secret

CF API token (for KV + worker deployment):

  • My Profile โ†’ API Tokens โ†’ Create Token
  • Use template: Edit Cloudflare Workers
  • Add permissions: Zone DNS Edit + Zone Read
  • Save the token

3. Run setup

share setup

This verifies credentials, creates the R2 bucket and KV namespace, and writes config to ~/.config/share/config.toml.

4. Configure and deploy the worker

Clone the repo and edit worker/wrangler.toml:

name = "share"
main = "src/index.ts"
compatibility_date = "2026-03-19"

[[r2_buckets]]
binding = "R2"
bucket_name = "share"

[[kv_namespaces]]
binding = "KV"
id = "your-kv-namespace-id"  # printed by share setup

[[routes]]
pattern = "yourdomain.com"
custom_domain = true

[vars]
SITE_NAME = "yourdomain.com"

Then deploy:

cd worker
npx wrangler deploy

5. Add your domain to Cloudflare

If not already done:

  1. Cloudflare dashboard โ†’ Add a site โ†’ your domain
  2. Update nameservers at your registrar to the ones Cloudflare gives you
  3. The worker deploy will create the DNS records automatically
  4. SSL/TLS โ†’ Edge Certificates โ†’ Always Use HTTPS โ†’ ON

6. Upload

share upload myfile.pdf
# https://yourdomain.com/kX9mT (copied)

Config

~/.config/share/config.toml โ€” see config.example.toml.

Key Description
cloudflare.account_id Cloudflare account ID
cloudflare.r2_access_key_id R2 S3 API access key
cloudflare.r2_secret_access_key R2 S3 API secret key
cloudflare.api_token CF API token
cloudflare.bucket R2 bucket name (default: share)
cloudflare.kv_namespace_id Workers KV namespace ID
urls.public_base Your domain (e.g. https://yourdomain.com)
upload.strip_metadata Strip EXIF before upload (default: true)

Cloudflare free tier limits

Service Limit Usage
R2 10 GB storage, 1M writes/mo, 10M reads/mo, zero egress File storage
Workers KV 1 GB storage, 100K reads/day, 1K writes/day File metadata
Workers 100K requests/day, 10ms CPU/request Serve files + landing page

VPN note

R2's S3 endpoint uses TLS that some VPNs break. If uploads fail with SSL errors, bypass VPN for r2.cloudflarestorage.com.

KV schema

slug:<slug> โ†’ file: { type?, name, size, content_type, uploaded_at, downloads, r2_key, slug, public }
slug:<slug> โ†’ link: { type: "link", url, slug, created_at, clicks, public }

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

share-0.5.4.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

share-0.5.4-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file share-0.5.4.tar.gz.

File metadata

  • Download URL: share-0.5.4.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for share-0.5.4.tar.gz
Algorithm Hash digest
SHA256 8854c72a86924d6034054c54dc6ea98b603951c998251bb2bb12b6f26a63940b
MD5 8e4f10840dfdc14aeecc6b480c004af6
BLAKE2b-256 0437cf91a034f58fb4b7701ec47a3683f69bfbf4486e5649be390ed16ab9b907

See more details on using hashes here.

Provenance

The following attestation bundles were made for share-0.5.4.tar.gz:

Publisher: release.yml on adriangalilea/share

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file share-0.5.4-py3-none-any.whl.

File metadata

  • Download URL: share-0.5.4-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for share-0.5.4-py3-none-any.whl
Algorithm Hash digest
SHA256 ced38ab30ab65ac89333716f9f2501456ab27582ea360fd02a5876f8c0fee5f6
MD5 7f1baf4fadc9d28ccea56ae0d4a33a56
BLAKE2b-256 63ea595760b38c6859a182dbb5a7c4c0cdaf2ca7621e4d204ca923cef7055b80

See more details on using hashes here.

Provenance

The following attestation bundles were made for share-0.5.4-py3-none-any.whl:

Publisher: release.yml on adriangalilea/share

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page