Deploy VERT

File converter, image converter, video converter, self-hosted on Railway

Deploy VERT

Just deployed

/data

Just deployed

Deploy and Host VERT on Railway

VERT is an open-source file converter that does the work in your browser instead of on a server. Images, audio and documents are converted by WebAssembly builds of ImageMagick, FFmpeg and Pandoc inside the tab, so the file never leaves the machine that opened the page — no queue, no upload wait, no third party holding your data. It covers more than 250 formats and looks like a product rather than an ad-funded conversion site. Video is the exception: transcoding a movie in WebAssembly is painfully slow, so VERT hands video to vertd, a small Rust service driving a real FFmpeg binary.

Deploy VERT on Railway and you get both halves wired together. The vert service builds the interface and serves it with nginx; the vertd service runs the FFmpeg daemon on the private network with a volume for files in flight. The web service also proxies /api/* to the daemon, so everything lives on one domain and the daemon is never exposed to the internet. To self-host VERT anywhere else you would rebuild the frontend to point at your own daemon, because its address is compiled into the bundle — this template does that rewrite from the domain Railway gives you.

Diagram of the VERT and vertd services on Railway

Getting Started with VERT on Railway

Open the deployed URL and you are on the upload page — no account, no login and no first-run wizard, because VERT keeps its settings in your browser. Drop a file onto the panel, or click to pick one, and you land on the Convert tab with a card per file. Each card has a format dropdown; pick a target and press Convert all. Images, audio and documents are converted locally as the WebAssembly worker runs. Choosing a video format shows a one-time warning that the file will be sent to a server — that server is your own vertd, not a public one. When a conversion finishes the card's download button lights up, and Download all as .zip collects a batch.

To confirm the deployment is healthy, check the four cards under "VERT supports…" on the home page: Images, Audio, Documents and Video should all read Status: ready, and Video only does so when the browser can reach your daemon. Settings → Video conversion shows the same thing directly, with an Instance box holding your own Railway domain.

VERT home page listing image, audio, document and video formats

A converted photo and video ready to download in VERT

VERT settings pointing video conversion at the self-hosted daemon

About Hosting VERT

Most online file converters are the same trade: you hand a stranger your document and hope it is deleted afterwards. VERT removes that trade for everything except video. A team self-hosts it to give staff a converter that keeps files inside the organisation, or to put a fast, ad-free one on an intranet.

Key features:

  • Over 250 formats across images, audio, documents and video
  • Local conversion for images (ImageMagick), audio (FFmpeg) and documents (Pandoc)
  • Batch conversion with per-file targets and a zip download
  • Quality, sample-rate and metadata controls per category
  • Server-side video conversion through your own FFmpeg daemon

The template deploys two services. vert is nginx serving the compiled interface, the only service with a public domain, and it proxies the conversion API. vertd accepts an upload, transcodes it, streams progress over a WebSocket and deletes the result once downloaded; its volume holds files only while a job is in flight.

Why Deploy VERT on Railway

Railway removes the two hard parts: rebuilding the frontend for your own domain, and wiring the video daemon to it.

  • The frontend is rebuilt and repointed at your daemon automatically on every deploy
  • One public domain covers the app and the conversion API
  • The FFmpeg daemon stays on the private network, unreachable from outside
  • A persistent volume holds in-flight conversions
  • Upload size and rate limits are variables, not a config file
  • Optional password protection with two variables

Common Use Cases

  • An internal converter for a team that cannot upload client files to a public site
  • A HEIC, AVIF and JPEG XL converter for photographers handling formats desktop tools refuse
  • Turning Markdown, DOCX and EPUB into each other with Pandoc
  • Batch re-encoding screen recordings to MP4 or WebM before publishing

Dependencies for VERT

  • vert — built from VERT-sh/VERT with Bun, served by nginx:stable-alpine. Holds the interface and the WebAssembly converters, and proxies /api/* to the daemon.
  • vertd — built on ghcr.io/vert-sh/vertd:latest, an FFmpeg wrapper written in Rust. Needs a volume and no database.

There is no database, cache or object storage. Settings live in the browser and conversions are transient by design.

Environment Variables Reference

VariableServicePurpose
VERT_PUBLIC_URLvertOrigin compiled into the bundle; set it for a custom domain
MAX_UPLOAD_SIZEvertLargest video accepted, default 512M
UPLOAD_RATEvertPer-client upload rate limit, default 30r/m
VERT_USERNAME / VERT_PASSWORDvertSet both to put the site behind basic auth
PUB_PLAUSIBLE_URLvertPlausible instance for analytics; rebuilds the image
VERTD_FORCE_GPUvertdEncoder backend, cpu on Railway
VERTD_FFMPEG_THREADSvertdOverrides the thread cap derived from the CPU quota

Deployment Dependencies

  • Source repository: VERT-sh/VERT (AGPL-3.0)
  • Video daemon: VERT-sh/vertd (GPL-3.0)
  • Documentation: vert.sh and the repository's docs/ directory
  • Runtime: Bun and nginx for the web service, Rust and FFmpeg for the daemon

Hardware Requirements for Self-Hosting VERT

ResourceMinimumRecommended
CPU1 vCPU4+ vCPU — FFmpeg is the only heavy consumer
RAM512 MB2 GB+ — the daemon buffers each upload in memory
Storage1 GB volume5 GB+ for larger or concurrent video jobs
Runtimenginx + Rust/FFmpegSame; no database or cache

The web service is static files and stays small; everything else scales with video. Raising MAX_UPLOAD_SIZE means raising memory to match, because the daemon reads an upload into memory before writing it to disk.

Self-Hosting VERT

Running the published web image is one command, but it sends video to the project's public daemon — that URL is baked in at build time:

docker run -d -p 3000:80 --name vert ghcr.io/vert-sh/vert:latest

To use your own daemon you have to build the frontend yourself and pass the address as a build argument. The following builds both halves and runs them together:

git clone https://github.com/VERT-sh/VERT && cd VERT
docker build -t vert \
  --build-arg PUB_ENV=production \
  --build-arg PUB_HOSTNAME=convert.example.com \
  --build-arg PUB_VERTD_URL=https://vertd.example.com \
  --build-arg PUB_PLAUSIBLE_URL= \
  --build-arg PUB_DISABLE_ALL_EXTERNAL_REQUESTS=false .
docker run -d -p 3000:80 vert
docker run -d -p 24153:24153 -e VERTD_FORCE_GPU=cpu ghcr.io/vert-sh/vertd:latest

The daemon detects an NVIDIA, AMD, Intel or Apple GPU and falls back to software encoding when there is none, which is what happens here — the template sets VERTD_FORCE_GPU=cpu and caps FFmpeg's threads to the container's CPU quota.

Is VERT Free to Self-Host?

VERT is free and open source — the interface is AGPL-3.0, the daemon GPL-3.0 — with no paid tier, license key or account. Hosting costs only the Railway resources the two services use, and the web service serves static files. The daemon is idle until someone converts a video, so the bill tracks video use rather than page views.

FAQ

What is VERT?

VERT is an open-source file converter that runs in your browser. Image, audio and document conversions are done locally by WebAssembly builds of ImageMagick, FFmpeg and Pandoc, so those files are never uploaded anywhere.

What does this Railway template deploy?

Two services: vert, the web interface behind nginx with a public domain, and vertd, the FFmpeg daemon on the private network with a volume. The web service proxies the conversion API to the daemon, so both share one URL.

Why does the template include a separate video service?

Video transcoding in WebAssembly is too slow to be usable. VERT sends video to a daemon running a native FFmpeg binary instead, and the template gives you your own rather than pointing at the public one operated by the project.

Are my files uploaded when I self-host VERT?

Only video. Everything else is converted inside the tab. A video is uploaded to your vertd service, transcoded, downloaded back, and then deleted — inputs expire after an hour, outputs 30 seconds after they are fetched.

How do I password-protect a self-hosted VERT deployment?

Set VERT_USERNAME and VERT_PASSWORD on the vert service and the whole site moves behind HTTP basic auth. Setting only one of the two fails the deploy rather than leaving the site open.

How do I raise the maximum video size?

Increase MAX_UPLOAD_SIZE on the vert service, and give vertd more memory at the same time — it reads each upload into memory before writing it to disk.


Template Content

More templates in this category

View Template
Rocky Linux
Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀

codestorm
47
View Template
Foundry Virtual Tabletop
A Self-Hosted & Modern Roleplaying Platform

Lucas
71
View Template
Letta Code Remote
Run a Letta Code agent 24/7. No inbound ports, just deploy.

Letta
51