
Deploy MoneyPrinterTurbo
Generate short videos from a topic with AI
Just deployed
/data
proxy
Just deployed
Deploy and Host MoneyPrinterTurbo on Railway
MoneyPrinterTurbo turns a topic or a keyword into a finished short video. It writes the script with an LLM, pulls matching stock footage, generates a voiceover and subtitles, adds background music, and renders a high-definition vertical or landscape clip — through a web UI, a REST API, or in batches.
About Hosting MoneyPrinterTurbo
This template deploys two services. app runs the Streamlit WebUI and the
FastAPI service side by side in one container, backed by a 5 GB volume that
holds config.toml and every generated video. proxy is a Caddy instance that
serves both on a single public domain and guards them with a login prompt, since
MoneyPrinterTurbo ships no authentication of its own and the WebUI would
otherwise expose your API keys to anyone with the URL. The first deploy pulls a
multi-GB image, so give it several minutes. Rendering is CPU-bound: expect a
minute or more per video, and longer if you switch subtitles to Whisper, which
downloads a model on first use.
Common Use Cases
- Spinning up a private, always-on video generator for TikTok, Reels, or YouTube Shorts without keeping a machine running at home
- Producing short explainer or promo clips in bulk from a list of topics
- Driving video generation programmatically from another service through the REST API
Dependencies for MoneyPrinterTurbo Hosting
- An LLM API key — required to write scripts. The default provider is Kimi/Moonshot; OpenAI, Gemini, DeepSeek, Qwen, Ollama, and others are supported. Set it at deploy time or later in the WebUI.
- A stock footage API key — required unless you upload your own material. Pexels and Pixabay are free.
- A volume — included, and required: it is the only place config and rendered videos survive a redeploy.
- Voice, subtitles, and music need nothing extra. The default Edge TTS provider is free and keyless.
Deployment Dependencies
- MoneyPrinterTurbo upstream repository
- Prebuilt image:
ghcr.io/harry0703/moneyprinterturbo - Pexels API · Pixabay API
- Kimi / Moonshot platform (default LLM provider)
- Caddy (the proxy service)
Implementation Details
Two upstream containers became one service. Upstream's compose file runs the
WebUI and API as separate containers sharing one bind mount, and both need the
same config.toml and storage/. A Railway volume attaches to exactly one
service, so both processes run in a single service instead:
python3 main.py &
exec streamlit run ./webui/Main.py --server.port=8501 ...
Config persistence works around an in-place rewrite. config.toml has to sit
inside the app directory — app/config/config.py derives its path from the
package location — but that directory is recreated from the image on every
deploy. A symlink to the volume does not survive either, because save_config()
rewrites the file with os.replace(), which would replace the symlink itself. So
the boot script copies the file in and mirrors edits back:
cp -f /data/config.toml /MoneyPrinterTurbo/config.toml
( while true; do sleep 10; cp -f /MoneyPrinterTurbo/config.toml /data/config.toml; done ) &
storage/ has no such problem and is a plain symlink to /data/storage.
Template variables like LLM_API_KEY seed config.toml on first boot only;
after that the volume's copy wins, because the WebUI writes to it.
The security model. Caddy applies basic auth to everything except its own healthcheck path, which must stay open or the deploy never goes healthy:
@protected not path /proxy-healthz
basic_auth @protected {
{$WEBUI_USERNAME} {$WEBUI_PASSWORD_HASH}
}
WEBUI_PASSWORD is a secret, kept as plaintext and hashed at start by
caddy hash-password, so no one has to produce a bcrypt hash by hand. This is
transport-level auth in front of a single-user app — it keeps strangers out, but
everyone who logs in shares one config and one set of API keys.
Two ports that must line up. Railway probes the healthcheck on PORT, not on
the domain's port, and Streamlit binds a fixed 8501 rather than reading $PORT —
so app sets PORT=8501 to make the probe and the app agree. Streamlit also
rejects the websocket unless the origin it expects matches the browser's, hence
PUBLIC_DOMAIN=${{proxy.RAILWAY_PUBLIC_DOMAIN}}; this keeps CORS and XSRF
protection on rather than disabling them.
Omitted upstream options. Redis-backed task state is off, so no Redis service
is included: enable_redis lives in config.toml with no environment override,
and the API's in-memory task state is fine for a single instance. See
VARIABLES.md for the rest.
Why Deploy MoneyPrinterTurbo on Railway?
Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.
By deploying MoneyPrinterTurbo on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.
Template Content
proxy
caddy:2-alpineWEBUI_PASSWORD
Password for the login prompt.
WEBUI_USERNAME
Username for the login prompt guarding the app.
