A blazing fast, minimal ShareX backend written in Go. Echo-Vault features a powerful, configurable media processing pipeline and a built-in, dependency-free dark mode dashboard. It leverages ffmpeg and gifsicle to handle transcoding and optimization, keeping the core service lean while giving you full control over your media.
- Drop-in ShareX uploader with bearer-token auth
- Minimal, responsive Web UI for gallery viewing and management
- Find screenshots by describing them ("blue car", "internet speed test") using local vector embeddings
- Automatically generates metadata and tags for images via OpenRouter (LLMs)
- Scheduled
tar.gzsnapshots of your database and media files with configurable retention policies - Configurable image processing to WebP, PNG, or JPEG
- Video transcoding and optimization (MP4, WebM, etc.) powered by ffmpeg
- Advanced GIF pipeline: convert from video, resample, downscale, reduce colors, and optimize with gifsicle
- Import existing files straight into the database with the
scancommand - Smart background backfilling for existing uploads
- Commented
config.ymlgenerated on first run
- Download the latest release or build from source.
- Install dependencies.
ffmpegandffprobeare required for video/GIF features.
# Debian/Ubuntu
sudo apt install ffmpeg
# Arch Linux
sudo pacman -S ffmpegIf you are using the AI-enabled version (for semantic screenshot search), you must set up the onnx/ directory structure next to your executable.
The final folder layout should look like this:
echo_vault (or echo_vault.exe)
onnx/
├── lib/
│ └── libonnxruntime.so (or onnxruntime.dll)
└── models/
├── clip_tokenizer/
│ ├── tokenizer.json
│ └── tokenizer_config.json
├── clip_text.onnx
├── clip_text.onnx.data
├── clip_visual.onnx
└── clip_visual.onnx.data
Follow these steps to set it up:
-
Download the Binary: Choose either
echo_vault_linux-amd64_aiorecho_vault_windows-amd64_ai.exeand rename it toecho_vault(orecho_vault.exe). -
Download & Extract Models: Download
clip_model.tar.gzfrom the release assets and extract it inside the same directory as the binary. This automatically creates theonnx/models/folder. -
Install ONNX Runtime: Download the appropriate shared library (v1.16.0+ recommended) for your platform from the ONNX Runtime Releases:
- Windows: Download
onnxruntime-win-x64-<version>.zip, extractonnxruntime.dlland place it inonnx/lib/onnxruntime.dll. - Linux: Download
onnxruntime-linux-x64-<version>.tgz, extractlibonnxruntime.so.<version>, rename/symlink it tolibonnxruntime.soand place it inonnx/lib/libonnxruntime.so.
- Windows: Download
-
Run the binary once in the target directory to create
config.ymlandstorage/. -
Edit
config.ymlto enable features and set your domain, port, and upload token. -
(Optional) Install the provided echo_vault.service unit next to the binary.
-
Make the binary executable:
chmod +x echo_vault. -
Update the service file paths, symlink it into
/etc/systemd/system/, and start it (service echo_vault start). -
Point nginx (or another reverse proxy) at the backend (config below).
-
Configure ShareX to send uploads to your instance using the bearer token.
Running Echo-Vault creates a commented config.yml. Adjust it and restart the service.
server:
# base url of your instance (default: http://localhost:8080/)
url: http://localhost:8080/
# port to run echo-vault on (default: 8080)
port: 8080
# only append the filename to the base url, no "/i/" (for custom endpoints; default: false)
direct: false
# upload token for authentication, leave empty to disable auth (default: p4$$w0rd)
token: p4$$w0rd
# maximum upload file-size in MB (default: 20MB)
max_file_size: 20
# maximum concurrent uploads (default: 4)
max_concurrency: 4
# if echos without their file should be deleted (default: false)
delete_orphans: false
backup:
# if backups should be created (default: true)
enabled: true
# how often backups should be created (in hours; default: 120)
interval: 120
# how many backups to keep before deleting the oldest (default: 4)
keep_amount: 4
# if files (images/videos) should be included in backups (without, only the database is backed up; default: true)
backup_files: true
images:
# target format for images (webp, png or jpeg; default: webp)
format: webp
# quality/speed trade-off (1 = fast/big, 2 = medium, 3 = slow/small; default: 2)
effort: 2
# webp quality (0-100, 100 = lossless; default: 90)
quality: 90
videos:
# allow video uploads (requires ffmpeg; default: false)
enabled: false
gifs:
# allow gif uploads (requires ffmpeg when using gif as target; default: true)
enabled: true
# target format for gifs (gif or webp; default: webp)
format: webpThe application serves the Dashboard at /, API endpoints at /echos and /upload, and raw files at /i/.
To support the Web UI, Nginx should proxy requests to the backend. You can still serve storage files directly via Nginx for maximum performance if desired.
# Serve images directly (optional, for performance)
location /i/ {
alias /path/to/your/storage/;
etag on;
expires 30d;
location ~* \.(mp4|webm|mov|mkv|m4v)$ {
add_header Accept-Ranges bytes always;
output_buffers 2 1m;
}
}
# Proxy UI and API
location / {
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# Required for large uploads
client_max_body_size 100M;
}If you host your images on a separate custom domain (e.g., i.example.com) and serve them directly via Nginx, users visiting the root / of your image domain will hit an empty directory index, and broken links will result in generic Nginx 404 pages.
To handle this cleanly, Echo-Vault provides a generic /not_found endpoint that renders a clean, templated error page. You can configure Nginx on your image domain to fallback to this page:
# Custom Image Domain Server Block (e.g., i.example.com)
server {
listen 80;
server_name i.example.com;
root /path/to/your/storage/;
error_page 404 = @notFound;
# Try serving files directly from your storage folder, falling back to 404
location / {
try_files $uri =404;
etag on;
expires 30d;
}
location @notFound {
proxy_pass http://localhost:8080/not_found;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}All API routes under /upload and /echos expect Authorization: Bearer <token>. The Web UI handles this automatically via a login prompt.
Returns the current server version and feature flags.
{
"version": "dev",
"queries": true
}Used to check token validity. Returns 200 OK or 401 Unauthorized.
Upload a file via multipart form (upload=<file>). Supported types: JPEG, PNG, GIF, WebP, MP4, WebM, MOV, MKV.
{
"change": "saved 45.28% (-1.1 MB)",
"extension": "mp4",
"hash": "ASODE3CEHE",
"size": "1.4 MB",
"sniffed": "mp4",
"timing": {
"read": "5.2058ms",
"store": "5.0093ms",
"write": "1.2276779s"
},
"url": "http://localhost:8080/i/ASODE3CEHE.mp4"
}Returns up to 100 uploads per page (1-indexed). The tag object contains safety info. Unsafe images are blurred in the dashboard until hovered.
[
{
"id": 21,
"hash": "ASODE3CEHE",
"name": "my video.mp4",
"extension": "mp4",
"upload_size": 2483452,
"timestamp": 1761174760,
"tag": {
"safety": "ok"
}
}
]Semantic search endpoint. Returns results sorted by relevance. Includes a similarity score in the tag object (0.0 - 1.0).
[
{
"id": 45,
"hash": "B82JSD9A2",
"timestamp": 1761175000,
"tag": {
"safety": "ok",
"similarity": 0.4281
}
}
]Removes both the file and its database entry. Replies with 200 OK.
Echo-Vault doubles as a tiny maintenance tool when invoked with commands:
Walks the storage/ directory and imports missing files into the database. Progress is logged to stdout.


