Screenshot. Upload. Link. On your own server.
Press ⇧⌘2 (CtrlShift2 on Windows and Linux), drag over anything on screen,
and a link is on your clipboard a second later.
Your files live on your own server. No accounts, no subscriptions, no one else's cloud.
Get started · Server guide · FAQ · Build from source · Support Push
push-github.mp4
Push has two parts:
- The app on your computer. It takes the screenshot (or any file), uploads it, and copies the link.
- The server that you run. It stores your files and shows them to anyone who has the link.
Links look like https://share.example.com/i/Xc3nzK9qPa.png. They are long and random, so nobody can guess them.
Images and videos preview inline in Slack, Discord, X, Telegram and WhatsApp.
You need:
- A server with Docker. The smallest VPS from any provider is enough. Intel and ARM both work.
- A domain for your links, like
share.example.com. In your DNS settings, add anArecord that points it at your server's IP address.
Then follow A or B.
This runs Push together with Caddy, which sets up HTTPS for you. Make sure ports 80 and 443 are open, then run this on your server:
mkdir push && cd push
curl -fsSLO https://raw.githubusercontent.com/itsfutsy/push/main/docker-compose.yml
echo "PUSH_DOMAIN=share.example.com" > .env # use your domain
echo "PUSH_TOKEN=$(openssl rand -hex 32)" >> .env # creates your token
docker compose up -dRun cat .env to see your token. You'll paste it into the app in step 3.
These tools set up HTTPS for you. Create an app from a Docker image, with these settings:
| Setting | Value |
|---|---|
| Image | ghcr.io/itsfutsy/push:latest |
| Port | 3000 |
| Volume | A persistent volume mounted at /data. This is where your files are kept. |
PUSH_TOKEN |
Your token: a long random password. Create one with openssl rand -hex 32. |
PUSH_PUBLIC_URL |
Your address, like https://share.example.com |
Then add your domain to the app in your tool, and deploy it.
Open https://share.example.com/healthz in your browser. It should say ok. If it doesn't, see
Troubleshooting.
Download it from the latest release.
- Mac (Apple silicon, macOS 14 or later): open the
.dmgand drag Push into Applications. - Windows (10 or 11): run the
x64-setup.exeinstaller. If Windows SmartScreen warns you, click More info > Run anyway. See Windows notes. - Linux: install the
.deb, or run the.AppImage. See Linux notes.
Open Push > Settings. Enter your server's address (like https://share.example.com) and paste your token. When
it says Connected, you're done.
Press ⇧⌘2 (CtrlShift2 on Windows and Linux) and drag over part of your screen. The first time, macOS asks for permission to record the screen: turn on Push in System Settings > Privacy & Security > Screen & System Audio Recording.
| To | Do this |
|---|---|
| Capture part of the screen | ⇧⌘2 and drag. Press Space to capture a window instead, Esc to cancel. On Windows, the shortcut opens Windows' snipping bar, which can also capture a window or the whole screen. |
| Upload a file | Drop it on the Push window, click the drop area, or use Share > Push in Finder. On Windows, right-click it and choose Send to > Push. |
| Upload several files | Drop them together. All their links are copied, one per line. |
| Copy a link again | Click it in Recent, or open it in the Library and choose Copy Link. |
| Browse everything | Show All in the Push window, or Library in the menu bar (the tray on Windows and Linux). Press Space to preview and the arrow keys to move. |
| Delete | Hover a file and choose Delete, or select files in the Library and choose Delete. The link stops working right away. |
| Change the shortcut | Settings > Capture Shortcut. Holding both ⌘ keys works too (it needs Input Monitoring permission). |
| Setting | What it does |
|---|---|
PUSH_TOKEN |
Required. Your upload password, at least 32 characters. Create one with openssl rand -hex 32. Anyone who has it can upload and delete files, so keep it secret. |
PUSH_PUBLIC_URL |
Required. Your server's address, like https://share.example.com. Links start with this. With setup A, set PUSH_DOMAIN=share.example.com instead. |
PUSH_ROOT_REDIRECT |
Optional. Where to send people who open https://share.example.com/ itself, like your homepage. Without it, they see "not found". |
PUSH_DATA_DIR |
Optional. Where files are saved. Default /data. |
PORT |
Optional. The port the server listens on. Default 3000. |
With setup A, settings live in the .env file. Run docker compose up -d after you change them.
To change your token, set a new one, restart the server, and paste it into Settings in each app.
- Setup A:
docker compose pull && docker compose up -d - Setup B: redeploy the app in your tool so it downloads the new image.
Your files are normal files, in the files folder of the /data volume. There is no database. With setup A, this
saves them all to push-backup.tgz:
docker run --rm -v push_push-data:/data -v "$PWD":/backup alpine tar czf /backup/push-backup.tgz -C /data .Already run nginx, Traefik or Caddy? Run only the Push image and point your proxy at port 3000. For example:
docker run -d --name push --restart unless-stopped -p 127.0.0.1:3000:3000 --log-driver local \
-e PUSH_TOKEN=your-token -e PUSH_PUBLIC_URL=https://share.example.com \
-v push-data:/data ghcr.io/itsfutsy/push:latestThen set your proxy to:
- Allow requests of at least 10 MB. Push sends big files in 8 MB pieces, so any file size works.
- Wait at least 60 seconds before timing out a request.
- Never cache responses, so a deleted file stops working right away.
Cloudflare works well in front of Push. With setup A, set the DNS record to DNS only (grey cloud) until Caddy has its certificate. Then switch it to Proxied and set SSL/TLS to Full (strict).
- Caching > Cache Rules: add a rule for your domain with Bypass cache, so deleted files stop working right away.
- Turn these off, because they leak your links or break them:
- Caching > Configuration > Always Online (sends your links to the Internet Archive)
- Caching > Configuration > Crawler Hints (sends your links to search engines)
- Security > Bots > Bot Fight Mode (blocks link previews in apps like Discord)
- Security > Bots > Managed robots.txt (replaces Push's own robots.txt)
- Scrape Shield > Hotlink Protection (breaks embeds)
- If a Redirect Rule sends your whole domain somewhere else, limit it to
/only, or every link will redirect too.PUSH_ROOT_REDIRECTcan do this for you.
Cloudflare's 100 MB request limit is no problem, because Push sends 8 MB pieces.
| Problem | Fix |
|---|---|
| With setup A, the site doesn't load | Caddy couldn't get an HTTPS certificate. Check that your A record points at this server and that ports 80 and 443 are open. With Cloudflare, use DNS only until it works. docker compose logs caddy says what went wrong. |
The server keeps restarting, and its log says cannot write to /data/files: Permission denied |
The data folder belongs to the wrong user. This is common when you mount a folder instead of a volume. Run sudo chown -R 65532:65532 /path/to/folder, then restart. |
The app says your token is wrong (401) |
Check PUSH_TOKEN for a missing or extra character, then restart. The server logs every rejected request. |
Big uploads fail on slow connections (504 or a reset) |
Your proxy times out too soon. Raise its read timeout to 600 seconds. On Traefik, that's entryPoints.websecure.transport.respondingTimeouts.readTimeout. |
Uploads fail with 413 |
Your proxy or Cloudflare blocks large requests. Allow at least 10 MB. |
| Links open a different website | A redirect rule on your domain also catches your links. Limit it to / only, or use PUSH_ROOT_REDIRECT. |
To test your server and token from a terminal:
curl https://share.example.com/healthz # ok
curl -s -o /dev/null -w "%{http_code}\n" -H "Authorization: Bearer YOUR_TOKEN" \
https://share.example.com/api/ping # 204 means the token works, 401 means it doesn'tDo I need a domain?
Yes. Links need an HTTPS address. A subdomain of a domain you already own is perfect.
Can I use it on more than one computer?
Yes. Install the app on each one and give them the same server address and token. Each keeps its own upload history.
How much does it cost to run?
Only what your server costs. The server is one small program, so the cheapest VPS is plenty. Storage is just your files.
How private is it?
- Only you can upload. Every upload and delete needs your token. The server checks it before reading any data, and gives the same answer for a wrong token as for a missing one.
- Your token stays on your computer. It's kept in the macOS Keychain (Credential Manager on Windows, Secret Service on Linux). The app never follows redirects, so it can't be tricked into sending your token anywhere else.
- Links can't be guessed. Each file gets a name of 10 random characters, and there are no lists or index pages.
- Nothing gets indexed. The server tells search engines and archives to stay away. Only link-preview bots may fetch files.
- Shared files can't attack viewers. HTML, SVG, scripts and PDFs always download. They never open as pages on your domain.
- The Finder Share extension is locked down. It has no network or keychain access. It only passes files to the app.
- Push uses Windows' own snipping bar (the one behind WinShiftS) to capture, so it needs Snipping Tool, which comes with Windows. Depending on Snipping Tool's settings, Windows may also save a copy in Pictures > Screenshots.
- Upload from File Explorer with Send to > Push, or from a terminal with
push FILE. - The installer isn't signed yet, which is why SmartScreen warns you the first time.
- Global shortcuts work on X11. On Wayland, set a system shortcut that runs
push --capture(GNOME: Settings > Keyboard > Custom Shortcuts). - Upload from a terminal with
push FILE. For an "Upload with Push" item in Nautilus, save#!/bin/sh+exec push "$@"as~/.local/share/nautilus/scripts/Upload with Pushand make it executable. - The tray icon needs a StatusNotifier host (on GNOME, the AppIndicator extension).
Server image. Compiling needs 1 to 2 GB of RAM (add swap on small servers) and Docker's buildx plugin (included when you install Docker from get.docker.com). Tag the image like this and setup A uses it instead of downloading one:
git clone https://github.com/itsfutsy/push.git && cd push
docker build -t ghcr.io/itsfutsy/push:latest serverServer without Docker. Run it behind any HTTPS reverse proxy pointed at port 3000, and keep it running with systemd or similar:
cd server && cargo build --release
PUSH_TOKEN=... PUSH_PUBLIC_URL=https://share.example.com PUSH_DATA_DIR=/var/lib/push ./target/release/push-serverMac app. Needs Xcode's command line tools and Rust. This builds Push.app, installs it in /Applications and
turns on its Share extension:
xcode-select --install # once, if you don't have it
curl https://sh.rustup.rs -sSf | sh # once, if you don't have Rust
cargo install tauri-cli --version "^2.12" --locked # once
git clone https://github.com/itsfutsy/push.git && cd push
scripts/build-macos.sh --installWindows app. Install Rust, then run cargo tauri build --bundles nsis in src-tauri.
Linux app. Install the packages listed in .github/workflows/linux.yml, then run
cargo tauri build --bundles deb,appimage in src-tauri.
| Folder | What it is |
|---|---|
src-tauri/, ui/ |
The desktop app: Tauri 2 and Rust, with a plain HTML, CSS and JS interface. |
macos/share/ |
The Finder Share extension (Swift). |
server/ |
The server: Rust, one program, no database. |
dev/ |
A browser preview of the interface with fake data, for working on the UI without the app. |
cd server && cargo run # server (needs PUSH_TOKEN, PUSH_PUBLIC_URL and PUSH_DATA_DIR)
cd src-tauri && cargo tauri dev # desktop app (PUSH_TOKEN=... skips the Keychain in debug builds)
python3 dev/serve.py # UI preview: http://127.0.0.1:5174/dev/?s=list
scripts/check-linux.sh # compile the desktop app for Linux in DockerPushing a v* tag builds a release: the Mac .dmg, the Windows installer, the Linux .deb and .AppImage, and the
server image at ghcr.io/itsfutsy/push.
Push is free for everyone, businesses included. If it saves you time, please consider buying us a coffee. And if your company uses Push for its team, a sponsorship is hugely appreciated and keeps the project going.
Copyright (C) 2026 Abram Industries Pty Ltd
Push is open source under the MIT License.