Deploy an existing image
Last updated
Run any published image — an official database, a self-hosted tool, or your own from a private registry. This is the fastest path for anything you didn't write.
Create it
Create application → Advanced → Existing Image. You set everything at creation time, which avoids the add-then-restart dance:
- Image and tag — pin a version rather than
latest, so a restart doesn't quietly upgrade you - Run command — see the warning below
- Registry credentials — if it's private
- Under Advanced: environment variables, volumes, and ports
There's also a Copy share link button, which produces a URL that pre-fills this form. Handy for documenting a setup, or for sharing "deploy this like I did" with someone else.
The run command trips people up
Your run command becomes the container's command. The image's ENTRYPOINT still runs, with your command passed to it as arguments.
For an image whose entrypoint is already the program, the command is only its arguments:
# image: binwiederhier/ntfy (ENTRYPOINT is "ntfy")
serve ✅ runs: ntfy serve
ntfy serve ❌ runs: ntfy ntfy serve
If a third-party image fails instantly with a confusing argument error, this is almost always the cause. Leave the command empty to use whatever the image specifies.
Tell the app its own URL
Most self-hosted tools generate links — for emails, redirects, clone URLs, webhooks — and can't work out their public address by themselves, because TLS is terminated at the edge and the container sees plain HTTP.
So nearly every tool has a setting for this, and it's the most common silent misconfiguration:
| Tool | Setting |
|---|---|
| ntfy | NTFY_BASE_URL |
| Gitea | GITEA__server__ROOT_URL |
| Most others | Something ending in BASE_URL, ROOT_URL, SITE_URL or PUBLIC_URL |
The hostname doesn't exist until the app does, so the sequence is: create the app, read its URL, set the variable, restart.
Persistence and exposure
Two things to decide before you start it:
- Add a volume for the tool's data directory. Without one, everything it stores is discarded on the next restart. Check the image's documentation for the path —
/dataand/var/lib/...are common. - Every port you bind is public. Many self-hosted tools ship with open registration or no authentication by default, which is fine on a home network and not fine here. Turn registration off, set a password, and do it before the app is first reachable — see Networking.
Sizing
Start small and raise on evidence. Most single-purpose tools are comfortable on a modest allocation; anything with a bundled database or a JVM has a higher floor. An out-of-memory kill shows as exit code 137 in the app's events.