A container is just a program running inside Docker. Nothing about it is special: if your app starts and listens on a port, it works here. The two things people most often get wrong are both about that port, so this walkthrough is built around it.
1. Create the service
Register, then claim a plan from the client area. Provisioning takes under a minute. Once it is live you land on the service page, which has these tabs:
Console · Files · Databases · Schedules · Users · Backups · Network · Startup
You will spend most of your time in Console, Files and Startup.
2. Find your port
Open the Startup tab. It shows the container port your app is expected to bind to, plus your startup command and environment variables. Write that port down — every runtime article here refers to it.
3. Mistake one: binding to localhost
This is the single most common reason a fresh deployment shows as “offline” even though the console says the app started. Your app must listen on 0.0.0.0, not 127.0.0.1.
Binding to 127.0.0.1 means “only connections from inside this machine”. The proxy that forwards your subdomain sits outside your process, so it can never reach a port that refuses anything but loopback traffic. The container looks healthy from the console and is completely unreachable from outside.
# Correct — reachable from outside
app.listen(3000, "0.0.0.0")
# Wrong — only reachable from inside the container
app.listen(3000, "localhost")
The same rule applies to every runtime: host="0.0.0.0" in Flask, --host 0.0.0.0 for Uvicorn, and :port rather than localhost:port in Go.
4. Mistake two: the wrong start command
The Startup tab runs a specific command, not whatever your package.json happens to suggest. If your project starts with npm start but the startup command is node index.js, that mismatch is the cause. Set the startup command to match your actual entry point, and install dependencies as part of it.
Installing on every start is fine for a first deployment and wasteful once you are restarting often, but it removes a whole class of “works on my machine” failures. Move to a proper build later if restarts become frequent.
5. Upload and start
Use the Files tab to upload a project archive, or connect over SFTP. Then press start and watch the Console. You are looking for one clear line: your app saying which address and port it is listening on.
[INFO] listening on http://0.0.0.0:3000
That line is your confirmation that step 3 is right. If you see 127.0.0.1 or localhost in it, the container is not reachable yet and no amount of waiting will change that.
6. Attach your subdomain
Every plan includes a free custom subdomain. Once the app answers on its port, point the subdomain at it — this is a field on the service rather than a DNS record you manage yourself. There is nothing to renew and nothing to keep paying for.
Where to look when something fails
Work in this order, because each step rules out a layer:
- Console output — a crash reports a stack trace here, which tells you the failure is in your code.
- Container status — running but unreachable points at binding or port, not at your code.
- Startup command — “command not found” means the entry point is wrong, not the app.
Full symptom-to-cause breakdown in Troubleshooting.