Gokapi: Lightweight Self-Hosted File Sharing with Expiring Links
Most self-hosted file sharing tools try to be full-featured platforms: user management, folder hierarchies, collaboration, previews, version history. Sometimes you just need to upload a file, get a link, and have that link stop working after a set number of downloads or after a certain time period. No accounts, no folders, no complexity.
Photo by Green Liu on Unsplash
Gokapi is a lightweight, self-hosted file sharing server inspired by the now-defunct Firefox Send. Upload a file, set an expiration (by time, download count, or both), optionally add a password, and share the link. Once the expiration condition is met, the file is automatically deleted. The entire application is a single binary with minimal resource usage, and it supports storing files on local disk, AWS S3, or any S3-compatible storage backend.

Why Gokapi
The self-hosted file sharing landscape includes heavy platforms (Nextcloud, Seafile) and purpose-built sharing tools (Pingvin Share, Send clones, Zipline). Gokapi differentiates itself through deliberate simplicity:
- Automatic expiration -- files are deleted after a configurable time period, download count, or both. No manual cleanup needed.
- No recipient accounts -- anyone with the link can download. Zero friction for recipients.
- End-to-end encryption -- optional server-side encryption ensures files are encrypted at rest. With the right configuration, not even the server admin can read the files without the download link.
- Password protection -- add an optional password to any shared file for an extra layer of security.
- S3 backend support -- store files on local disk or offload to AWS S3, Backblaze B2, MinIO, or any S3-compatible storage.
- Single binary -- Gokapi compiles to a single Go binary. No runtime dependencies, no framework, no database server.
- Minimal resource usage -- runs comfortably on 50 MB of RAM.
- API-first -- full REST API for programmatic uploads and management.
- Hotlink protection -- prevent files from being embedded on external sites.
- Duplicate detection -- if you upload the same file twice, Gokapi deduplicates storage.
What Gokapi is not
Gokapi is not a file manager, a sync tool, or a collaboration platform. It has no folder hierarchy, no file previews, no versioning, and no multi-user file management. It is specifically a tool for sharing files via expiring links. If you need more than that, look at the alternatives discussed later in this article.
Gokapi vs. Other File Sharing Tools
| Feature | Gokapi | FileBrowser | Pingvin Share | Send (forks) |
|---|---|---|---|---|
| Primary purpose | Expiring file links | File manager | File sharing platform | Encrypted file sharing |
| Automatic expiration | Time + download count | No | Time + download count | Time + download count |
| Password protection | Yes | Yes (folder-level) | Yes | Yes |
| End-to-end encryption | Server-side (AES) | No | No | Client-side (Web Crypto) |
| S3 backend | Yes | No | No | No (S3 for some forks) |
| File management | No (upload only) | Full file manager | Upload + share | Upload only |
| Multiple users | Admin only | Yes (multi-user) | Yes (multi-user) | No accounts |
| API | REST API | REST API | REST API | Limited |
| Folder support | No | Yes | No | No |
| File preview | No | Yes (images, text, video) | Yes (images) | No |
| Resource usage | Very low (~50 MB) | Low (~100 MB) | Moderate (~200 MB) | Low (~80 MB) |
| Technology | Go (single binary) | Go | Next.js + Prisma | Node.js / Rust |
| Self-hosted | Yes | Yes | Yes | Yes |
When to pick Gokapi
- You want the simplest possible file sharing with expiring links
- You need S3 backend support (Backblaze B2, MinIO, AWS S3)
- You want minimal resource usage on a small VPS or Raspberry Pi
- You need a REST API for automated file uploads (CI/CD artifacts, backup reports, generated files)
- You want files to clean themselves up without manual intervention
When to pick alternatives
FileBrowser -- when you need a full web-based file manager with folders, previews, and multi-user access. FileBrowser is like a self-hosted Google Drive interface for browsing and managing files on your server. It's not focused on sharing; it's focused on file management.
Pingvin Share -- when you need a richer sharing experience with multi-user support, reverse sharing (letting others upload to you), email integration, and ClamAV virus scanning. Pingvin Share is a more full-featured sharing platform with a polished UI, but it requires more resources.
Send (forks like send.vis.ee or Spacedrop) -- when you need client-side end-to-end encryption where the server never sees the plaintext file. Send forks encrypt in the browser before uploading, and the decryption key is part of the URL fragment (never sent to the server). This is the strongest privacy model, but it limits file sizes and prevents server-side processing.
Self-Hosting Gokapi: Docker Compose Setup
Basic setup with local storage
# docker-compose.yml
services:
gokapi:
image: f0rc3/gokapi:latest
container_name: gokapi
ports:
- "53842:53842"
volumes:
- gokapi-data:/app/data
- gokapi-config:/app/config
environment:
# Timezone
TZ: "America/New_York"
restart: unless-stopped
volumes:
gokapi-data:
gokapi-config:
Setup with S3 backend (Backblaze B2)
For larger deployments or when you don't want to store files on the local disk:
# docker-compose.yml
services:
gokapi:
image: f0rc3/gokapi:latest
container_name: gokapi
ports:
- "53842:53842"
volumes:
- gokapi-config:/app/config
environment:
TZ: "America/New_York"
restart: unless-stopped
volumes:
gokapi-config:
S3 configuration is done through the initial setup wizard or the configuration file. Gokapi supports:
- AWS S3
- Backblaze B2 (via S3-compatible API)
- MinIO (self-hosted S3)
- Cloudflare R2
- Wasabi
- Any S3-compatible storage
Setup with MinIO (self-hosted S3)
If you want S3 storage without a cloud provider, pair Gokapi with MinIO:
# docker-compose.yml
services:
gokapi:
image: f0rc3/gokapi:latest
container_name: gokapi
ports:
- "53842:53842"
volumes:
- gokapi-config:/app/config
environment:
TZ: "America/New_York"
depends_on:
- minio
restart: unless-stopped
minio:
image: minio/minio:latest
container_name: gokapi-minio
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio-data:/data
environment:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: your-secure-minio-password
command: server /data --console-address ":9001"
restart: unless-stopped
volumes:
gokapi-config:
minio-data:
After starting, configure Gokapi to use MinIO as its S3 backend:
- Endpoint:
http://minio:9000 - Region:
us-east-1(default for MinIO) - Bucket: Create a bucket in MinIO's console first (e.g.,
gokapi-files) - Access Key: Your MinIO root user
- Secret Key: Your MinIO root password
First-time setup
docker compose up -d
On first launch, Gokapi runs an interactive setup wizard in the terminal. Attach to the container to complete it:
docker attach gokapi
The wizard configures:
- Admin password -- for the web admin interface
- Storage backend -- local disk or S3
- Server URL -- the public URL where Gokapi will be accessible
- Default expiration -- default time and download limits for new uploads
- Encryption -- whether to enable server-side encryption
After initial setup, configuration is stored in /app/config/config.json and the wizard won't run again.
Reverse proxy configuration
Gokapi runs on port 53842 by default. Put it behind a reverse proxy for HTTPS:
Caddy:
share.yourdomain.com {
reverse_proxy gokapi:53842
}
Nginx:
server {
listen 443 ssl;
server_name share.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
client_max_body_size 50G; # Adjust for your max file size
location / {
proxy_pass http://localhost:53842;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Note the client_max_body_size directive -- set this to accommodate your largest expected file upload.
Like what you're reading? Subscribe to Self-Hosted Weekly — free weekly guides in your inbox.
Using Gokapi
Web interface
The admin interface is clean and functional. Upload a file by dragging it into the browser or clicking the upload button. For each upload, you configure:
- Expiration time -- hours, days, or weeks until the file is deleted
- Download limit -- maximum number of downloads before deletion (0 for unlimited)
- Password -- optional password that recipients must enter before downloading
- Filename -- optionally rename the file for the download link
After uploading, Gokapi generates a shareable link. The link format is https://share.yourdomain.com/d?id=RANDOM_ID. Share this link with anyone.
Expiration behavior
When an expiration condition is met (time elapsed OR download limit reached, whichever comes first), Gokapi:
- Marks the file as expired
- Returns a "file not found" page for the download link
- Deletes the file from storage (local disk or S3)
This is automatic and requires no intervention. Your storage doesn't slowly fill up with forgotten files.
Encryption
Gokapi supports AES-256 server-side encryption. When enabled:
- Files are encrypted before being written to disk or S3
- The encryption key is derived from the file's download ID
- Without the download link, the file cannot be decrypted
- If someone gains access to your storage backend directly, they see encrypted blobs
This isn't client-side end-to-end encryption (the server sees the plaintext during upload), but it protects files at rest against storage-level breaches.
REST API
Gokapi's API is its secret weapon for automation. Every operation available in the web interface is available via the API.
Authentication
API requests require an API key, which you can generate from the admin interface under API Keys.
# All API requests include the apikey header
curl -H "apikey: YOUR_API_KEY" https://share.yourdomain.com/api/...
Uploading a file
curl -X POST https://share.yourdomain.com/api/files/add \
-H "apikey: YOUR_API_KEY" \
-F "file=@/path/to/report.pdf" \
-F "allowedDownloads=5" \
-F "expiryDays=7" \
-F "password=optional-password"
Response:
{
"result": "OK",
"fileInfo": {
"id": "abc123def456",
"name": "report.pdf",
"size": "2.4 MB",
"url": "https://share.yourdomain.com/d?id=abc123def456",
"hotlinkUrl": "https://share.yourdomain.com/hotlink/abc123def456",
"remainingDownloads": 5,
"expiry": 1708560000
}
}
Listing active files
curl -H "apikey: YOUR_API_KEY" https://share.yourdomain.com/api/files/list
Deleting a file
curl -X DELETE -H "apikey: YOUR_API_KEY" \
https://share.yourdomain.com/api/files/delete?id=abc123def456
Automation use cases
The API makes Gokapi useful beyond manual file sharing:
CI/CD artifact sharing:
# In your CI pipeline: upload build artifacts and share with QA
RESPONSE=$(curl -s -X POST https://share.yourdomain.com/api/files/add \
-H "apikey: $GOKAPI_KEY" \
-F "file=@build/app-v1.2.3.apk" \
-F "allowedDownloads=10" \
-F "expiryDays=3")
DOWNLOAD_URL=$(echo $RESPONSE | jq -r '.fileInfo.url')
echo "Build artifact available at: $DOWNLOAD_URL"
Automated report sharing:
# Generate a report and share it with a download limit
generate_monthly_report > /tmp/report-2026-02.pdf
curl -X POST https://share.yourdomain.com/api/files/add \
-H "apikey: $GOKAPI_KEY" \
-F "file=@/tmp/report-2026-02.pdf" \
-F "allowedDownloads=1" \
-F "expiryDays=30" \
-F "password=secure-report-password"
Backup file distribution:
# Share database dumps with team members, auto-expire after 24 hours
curl -X POST https://share.yourdomain.com/api/files/add \
-H "apikey: $GOKAPI_KEY" \
-F "file=@/backups/db-dump-20260215.sql.gz" \
-F "allowedDownloads=3" \
-F "expiryDays=1"
Advanced Configuration
Hotlink protection
By default, Gokapi provides both a download page URL and a hotlink URL. The download page shows a landing page where the user clicks to download. The hotlink URL serves the file directly -- useful for embedding images or linking directly to files.
You can disable hotlinks globally if you don't want files to be directly embeddable:
{
"HotlinkProtection": true
}
Custom download page
Gokapi supports customizing the download page with your own HTML template. Place a custom template in the config directory:
config/
templates/
download.html
This lets you brand the download page with your organization's logo and colors.
Maximum file size
Configure the maximum upload size in the configuration file:
{
"MaxFileSizeMB": 5120
}
The default is generous, but you may want to restrict it based on your storage capacity.
Logging
Gokapi logs all uploads, downloads, and expirations. Logs are written to stdout (visible via docker logs gokapi) and can be directed to a file:
# docker-compose.yml
services:
gokapi:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Backup and Migration
Configuration backup
The critical files to back up are:
config/
config.json # Server configuration
gokapi.sqlite # File metadata database
# Backup script
docker cp gokapi:/app/config/config.json ./backup/
docker cp gokapi:/app/config/gokapi.sqlite ./backup/
Data backup
If using local storage, also back up the data volume:
docker run --rm \
-v gokapi-data:/data \
-v $(pwd)/backup:/backup \
alpine tar czf /backup/gokapi-data.tar.gz /data
If using S3 storage, your files are backed up by your S3 provider's durability guarantees. You only need to back up the config and metadata database.
Migration
To migrate Gokapi to a new server:
- Stop the container on the old server
- Copy the config directory and data volume to the new server
- Start the container on the new server
- Update DNS to point to the new server
If using S3, you don't need to move file data at all -- just the config and database.
Resource Usage and Limits
Gokapi is exceptionally lightweight:
- RAM: ~30-50 MB under normal usage
- CPU: Negligible (Go is efficient; the server is I/O bound)
- Disk: Only the uploaded files plus a tiny SQLite database
- Startup time: Under 2 seconds
This makes Gokapi an excellent choice for resource-constrained environments: Raspberry Pi, cheap VPS instances, or servers already running many other services.
Scaling considerations
Gokapi is a single-process application without horizontal scaling. For most use cases, this is fine -- a single instance can handle hundreds of concurrent downloads. If you need to scale beyond a single server:
- Use S3 as the storage backend to separate compute from storage
- Put Gokapi behind a CDN (Cloudflare, etc.) to cache downloads
- Run multiple instances behind a load balancer (they'd need a shared config database, which isn't natively supported)
For the vast majority of self-hosting use cases, a single instance is more than sufficient.
Honest Trade-offs
Gokapi is ideal if you:
- Want the simplest possible file sharing with automatic cleanup
- Need an API for programmatic file uploads and sharing
- Run on limited hardware and need minimal resource usage
- Want S3 backend support for scalable storage
- Share files temporarily and don't want to manage storage growth
- Need a lightweight tool that does one thing well
Gokapi is not the right choice if you:
- Need a full file manager with folders, previews, and browsing (use FileBrowser)
- Want multi-user support with individual accounts and quotas (use Pingvin Share)
- Need client-side end-to-end encryption where the server never sees plaintext (use a Send fork)
- Want reverse sharing where others upload files to you (use Pingvin Share)
- Need file synchronization across devices (use Syncthing or Nextcloud)
The bottom line: Gokapi fills a specific niche perfectly: lightweight, API-driven file sharing with automatic expiration. It's the self-hosted equivalent of "upload, share link, forget about it." The file cleans itself up, your storage stays tidy, and the API makes it trivially easy to integrate into scripts and automation workflows. For homelabs and small organizations that regularly share files and don't want the overhead of a full file management platform, Gokapi is hard to beat.
