High-performance content delivery for automatic image and video optimization, accelerating load times and lowering resource use.
Find a file
maxpeterkaya 01e9a4038d
Some checks failed
Lint / vet (push) Successful in 34s
Lint / golangci-lint (push) Failing after 45s
Merge pull request 'chore(deps): update docker/login-action action to v4.2.0' (#135) from renovate/docker-login-action-4.x into master
Reviewed-on: #135
2026-05-27 19:01:40 -04:00
.forgejo/workflows chore(deps): update docker/login-action action to v4.2.0 2026-05-22 12:47:29 +00:00
api feat: respond upload with struct response 2026-05-27 15:48:39 -04:00
config feat: create config function to getdomain 2026-05-16 00:28:33 -04:00
docker feat: create example docker compose config 2026-05-27 15:30:54 -04:00
file fix: check if cwebp exists before attempting optimization 2026-05-15 23:50:27 -04:00
watcher Merge pull request 'Existing files will be synced with any new optimization methods added' (#130) from syncing into master 2026-05-14 16:14:44 -04:00
.gitignore feat: Create .gitignore 2025-02-19 13:05:40 -05:00
.golangci.yml Linting (#126) 2026-05-13 14:52:56 -04:00
.goreleaser.yaml fix: remove extra docker platforms 2026-05-15 23:25:33 -04:00
artifacthub-repo.yml fix: change artifacthub repo owner 2025-08-18 23:27:34 -04:00
FAQ.md feat: create faq with example prom config (#39) 2025-08-10 20:33:25 -04:00
go.mod Merge pull request 'chore(deps): update module github.com/go-chi/chi/v5 to v5.3.0' (#136) from renovate/github.com-go-chi-chi-v5-5.x into master 2026-05-27 19:01:29 -04:00
go.sum Merge pull request 'chore(deps): update module github.com/go-chi/chi/v5 to v5.3.0' (#136) from renovate/github.com-go-chi-chi-v5-5.x into master 2026-05-27 19:01:29 -04:00
LICENSE update license 2026-05-22 22:08:03 -04:00
main.go feat: create tmp folder if doesnt exist 2026-05-16 00:10:51 -04:00
README.md feat: update demo readme portion 2026-05-27 15:41:17 -04:00
renovate.json Add renovate.json 2026-01-26 00:02:46 +00:00

Amur - Automatic Media Optimization Server


This is a self-hosted media server that automatically processes and serves optimized images and videos. When a user uploads any file, the server saves it and, for images, creates thumbnail, AVIF, and WebP versions automatically. For videos, it generates HLS adaptive bitrate streams. When serving, it intelligently selects the best format (AVIF > WebP > original) based on what's available, without the client specifying an extension. This means front-end developers can request /XYge6W8BSXYhGUhczLqyK and always get the smallest, fastest-loading image with zero extra code.

Without this system, a content team would manually convert images and write complex client-side logic. This automates the entire pipeline, cutting page load times and bandwidth costs dramatically.

Demo


How to Run

curl -o https://vc.maxkaya.com/maxpeterkaya/amur/raw/branch/master/docker/docker-compose.yml && docker compose up -d

The server is now accepting uploads on http://{{DOMAIN}}/upload and serving files on http://{{DOMAIN}}/.

Uploading

Request: curl -X POST -H "Authorization: {{UPLOAD_KEY}}" http(s)://{{DOMAIN}}/upload

Response:

{
  "id": "XYge6W8BSXYhGUhczLqyK",
  "domain": "{{DOMAIN}}",
  "url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK",
  "original_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK.{{png|jpg|jpeg|mp4|.etc}}",
  "avif_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK.avif",
  "webp_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK.webp",
  "thumbnail_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK_thumb",
  "thumbnail_avif_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK_thumb.avif",
  "thumbnail_webp_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK_thumb.webp",
  "thumbnail_original_url": "http(s)://{{DOMAIN}}/XYge6W8BSXYhGUhczLqyK.{{png|jpg|jpeg|mp4|.etc}}"
}

Serving

Pick a URL from the response for directly referencing a file extension or just use the extension-less URL to serve whichever file format is most optimized and available.

Functionality


  • Re-Process failed optimizations
  • File watching, optimize on new uploads
  • Migrate non-sharded folders
  • Process files on cron job
  • Upload files via REST
  • Complete structured logs (compatible with alloy, promtail, etc.)
  • Healthcheck
  • Graceful shutdown
  • Prometheus metrics
  • Avif optimizations
  • WebP optimizations
  • HLS conversions & resolution resizing via FFmpeg

ENV


These are all default values so you don't have to define them all yourself.

Variable Default Value Data type Description
PORT 3000 *int Port that the server runs on.
DOMAIN localhost string Domain the server runs on, useful for custom CORS configurations and cookies.
PUBLIC_FOLDER /public *string Folder with all files to be served by server.
UPLOAD_KEY *string Upload key for upload authentication.
PROMETHEUS_USERNAME admin *string Username to use with prometheus
PROMETHEUS_PASSWORD *string Password for prometheus, if left empty then prometheus is disabled
TZ UTC *string Set timezone of server.

* Purely optional variables that aren't needed for basic functionality.

To properly work the following are REQUIRED:

  • DOMAIN MUST be set to your serving domain for security header purposes.
  • UPLOAD_KEY MUST be over 8 characters to unlock upload capabilities.
  • PUBLIC_FOLDER If you are running on host, make sure to define something like ./public/, otherwise leave the default in the docker container.

Docker Images


The binary for amur comes with avif support via a WASM bundle.

Bare

vc.maxkaya.com/maxpeterkaya/amur:bare OR vc.maxkaya.com/maxpeterkaya/amur:latest

This image does NOT include webp or ffmpeg, only avif support which is already part of the binary.

AIO - All In One

vc.maxkaya.com/maxpeterkaya/amur:aio

This image includes the webp and ffmpeg libraries.

Webp

vc.maxkaya.com/maxpeterkaya/amur:webp

This image includes the webp library.

FFmpeg

vc.maxkaya.com/maxpeterkaya/amur:ffmpeg

This image includes the ffmpeg library.

Credits