Web Hosting
Last updated: September 2026
panel.javer.pro runs your app in a container — good for apps you're actively building and iterating on, where you want visibility into logs, environment variables, and resource usage. If you just want to point at a repo and have it work with zero configuration, Simple Hosting is the simpler option.
Deploying an app
There are three ways to get code onto Javer, all from the Deploy button on your dashboard:
- Connected GitHub repository — connect your account once, then pick a repo and branch. Pushing to GitHub does not redeploy your app. The code is pulled once, at the moment you press deploy. To ship a change, push it to GitHub and then deploy again.
- Public Git URL — paste any public GitHub or GitLab repository URL. No account connection needed.
- Direct upload — drop in a
.zipof your project, a single.jsfile, or a single.htmlfile.
You can also deploy from the command line with the javer CLI (npm install -g javer-cli).
Javer inspects what you sent and works out how to run it. If your project is a zip containing one folder, that folder is unwrapped automatically. It looks for these, in this order:
- Procfile — a
web:orworker:line such asworker: python bot.pyorweb: node server.js. Javer runs that file. - Node.js — a
package.jsonwith a"start"script or a"main"field. Without either, the first ofserver.js,app.js,index.js,main.jsorbot.js. Dependencies are installed withnpm install. - Python — the first of
app.py,main.py,server.py,wsgi.py,application.pyorbot.py. Dependencies inrequirements.txtare installed into a virtualenv for you. - Static site — an
index.htmlwith no server.
If none of these is found, the deploy stops with a message listing exactly what Javer looked for.
Deploys with dependencies take time. A static site is ready in seconds; a Node app with a large package.json can take a minute or more while npm install runs. Keep the tab open until you see the URL.
Your app must listen on PORT
This is the single most common reason a deploy succeeds but the site shows an error. Javer assigns your app a port and passes it in as the PORT environment variable. Your app must read it rather than hardcoding a number.
In Node.js:
const port = process.env.PORT || 3000;
app.listen(port);
In Python:
import os
port = int(os.environ.get("PORT", 8080))
If you hardcode 3000 and ignore PORT, your app starts, appears healthy, and returns 502 Bad Gateway when visited — because nothing is listening where Javer is routing traffic. Static sites are unaffected; this applies to anything that runs a server.
Discord bots and other background workers
A Discord bot connects out to Discord and serves no web page, so it does not need to listen on PORT. Javer runs it as a background worker and never expects a web page from it — no keep-alive script, and no “not responding” warnings.
An app is a background worker when its Procfile has a worker: line, or, without a Procfile, when it depends on a Discord library (discord.js, discord.py, py-cord, nextcord, disnake, hikari, Eris, Oceanic or Discordeno) and no web framework. A bot that also serves a web page, such as a dashboard, is treated as a web app and checked like one.
Background workers are never put to sleep for being idle, on any plan. If one crashes it restarts on its own, and the dashboard shows why it stopped. Put your bot token in an environment variable, not in your code. More on the Discord bot hosting page.
Keeping files between deploys
Each deploy replaces your app's code directory completely, so anything your app writes there is gone after the next deploy. For files that must survive — uploads, a SQLite database, generated files — use the storage directory Javer gives every app.
Its path is in the JAVER_STORAGE environment variable (/app/storage). It is kept across redeploys and rollbacks, and removed only when you delete the app.
const path = require('path');
const dbFile = path.join(process.env.JAVER_STORAGE, 'data.sqlite');
Custom domains
Every app gets a free *.javer.pro subdomain the moment it deploys, with HTTPS already working — you do not need to configure SSL, request a certificate, or renew anything.
Your domain has to be on Cloudflare DNS. The address we give you only resolves inside Cloudflare. A domain sitting at GoDaddy, Namecheap, Route 53 or your registrar's default nameservers cannot be connected — move it to a free Cloudflare account first.
Then, on the Domains page, under Use a domain you already own:
- Type the domain, choose the app it should show, and press Add. This only claims the name — no traffic moves yet.
- Javer shows you a TXT record. Add it in Cloudflare.
- Press Verify. Nothing is routed until this passes.
- Add the CNAME record Javer shows you, and make sure the cloud icon beside it is orange (proxied), not grey.
HTTPS is issued for you once that is done. If your domain still shows nothing hours later, go back and check the TXT step — an unverified domain never starts working, however long you wait.
Would rather not deal with DNS at all? Buy a domain from the Domains page instead: it is registered, set up and connected for you, with HTTPS, and none of the steps above apply — see Domains.
Environment variables
Open your app's detail page and use the Environment tab to add, edit, or remove variables. Names must be letters, numbers, and underscores.
Saving restarts your app straight away. Javer rebuilds the container with the new values and starts it again, so there is a short outage of a few seconds. Do not edit variables on a live app at a busy moment unless you mean to restart it. You do not need to press restart afterwards.
Deploy history & rollback
The last 5 successful deploys are kept. Anything older is deleted permanently and cannot be brought back. If a change breaks something, open the app's Deploy History tab and promote an earlier version in one click — no need to revert your code or redeploy from Git first. If you deploy six or seven times chasing a bug, this morning's known-good build is already gone, so keep your source in Git.
Rollback restores the application code. It does not roll back environment variables or database contents, so if a bad deploy also changed those, fix them separately.
Managed databases
Postgres and MySQL are available as managed resources, created from the Databases tab. Javer generates the password for you and shows the full connection details once, at creation time. Copy them then — they are stored encrypted and cannot be displayed again. If you lose them, create a new database.
A database counts against the same account allowance as your apps and VMs, so a 1 GB database uses 1 GB of your plan's memory budget.
Reaching it from your own computer. Turn on Public access on the database's page to connect from TablePlus, DBeaver, psql or a local dev server. It is off unless you turn it on, and it only ever accepts connections from the addresses you list (an IP, or a range like 203.0.113.0/24). Connections are encrypted with a real certificate, so sslmode=verify-full works; use psql 16 or newer. The connection string, with its password, is shown once when you turn it on. Your apps keep using the private address either way.
Backups. Every database is backed up every hour, and the backups are kept on a different machine. Open the database from your apps list and go to Backups & recovery to restore one — restoring replaces everything in the database with the contents of that backup. When the panel offers Point in time, you can instead wind the database back to an exact moment, down to the second — useful after a dropped table or a migration run against the wrong database. The database is briefly unavailable while it rewinds, and its current state is backed up first, so a rewind can itself be undone.
VMs
When an app is the wrong shape — you need a full Linux machine, a custom runtime, system packages, or a long-running background process — create a VM from the Virtual Machines page.
Getting in. Every VM has a browser terminal on its page, with nothing to set up. You can also SSH from your own computer: when a VM is created you are shown its private key once — copy it then, it is never stored — and the user is javer. Add a firewall rule allowing TCP port 22 (ideally only from your own address) and connect to the VM's public IPv6 address.
Its public address. Every VM gets its own public IPv6 address, shown on its card. It is reachable on the ports your firewall rules allow — nothing is open until you add a rule. Most networks can reach IPv6; IPv4-only networks cannot. For a website or API that everyone can reach, publish a web address instead: it gives a port on the VM an https://…javer.pro address with a certificate, over IPv4 and IPv6. Web addresses carry websites and APIs only, so a game server, a database or SSH uses the IPv6 address. A Minecraft server that must be reachable over IPv4 is what Game Hosting is for.
Size, snapshots and recovery. Resize a VM after creating it (shut it down first). Take a snapshot while it runs and revert to it later, or turn on automatic snapshots — daily or weekly, keeping as many as you choose; snapshots you take by hand are never removed automatically. If a VM stops booting, rescue mode starts it from a rescue system with your disk attached as a second drive, so you can mount it and repair it without losing work. Try that before reverting a snapshot, which throws away everything since the snapshot. Each VM's page also shows its CPU, memory and network use over time.
A GPU add-on is available for workloads that need one, subject to availability — there is a single GPU in the pool, so if another customer holds it, GPU requests are declined until it frees up.
Is my port reachable? After starting a game server, database or anything else people connect to, check it: GET /api/vms/<id>/check-port?port=25565 (add &protocol=udp for UDP). It connects to your VM from outside Javer's network and says whether that worked. If it did not, it says why and how to fix it: nothing is listening on the port; your server listens only on 127.0.0.1; it listens on IPv4 only (0.0.0.0) while the VM's public address is IPv6, so use :: instead; the VM's own firewall (ufw) is on; or no Javer firewall rule allows the port. Ports 80 and 443, and UDP, cannot be tested from outside; for those the check looks at everything else and says so. Any API key can use it, and AI agents get it as the check_port tool.
From the API. Everything above can be done with an API key, which is how scripts and AI agents run VMs: GET /api/vms lists them and POST /api/vms creates one; each VM has /start, /stop, /restart, /resize, /stats, /stats/history, /snapshots, /snapshot-schedule, /rescue and /public-ports under /api/vms/<id>, and DELETE /api/vms/<id> removes it.
Running a command. POST /api/vms/<id>/exec with {"command": "..."} runs one command on a running VM and returns stdout, stderr and exitCode — no terminal to drive, which makes it the easiest way for a script or an AI agent to set a machine up. It runs as javer, who can use sudo. Optional: input (sent to the command's standard input) and timeoutSec (1–90, default 60; a command still running then is stopped and the reply says timedOut). For anything longer — starting a server, a big install — start it in the background and check on it with further commands:
curl -X POST https://panel.javer.pro/api/vms/<id>/exec \
-H "Authorization: Bearer jvr_live_..." -H "Content-Type: application/json" \
-d '{"command": "tmux new -d -s mc \"cd ~/server && ./start.sh\""}'
A Standard API key can run commands; every command a key runs is shown under its ACTIVITY. Up to 30 commands a minute.
Network
Your account has its own private network with a dedicated subnet. VMs placed on it can talk to each other privately, and stay separated from every other customer's machines.
Under Network you can add firewall rules. Each has a direction, a priority (the lower number wins), allow or deny, a protocol and ports, and the address ranges it covers.
Rules are aimed at machines using tags. You label a machine with a tag, and the rule applies to every machine carrying that tag, including ones you create later. A rule whose tag matches nothing applies to nothing — the panel will tell you when that happens.
Two rules are always in force at the lowest priority and cannot be removed: deny everything inbound, and allow everything outbound. Your rules are what you carve out of that. Leave a rule's address ranges and tags empty and it applies to traffic from anywhere.
The Activity view is traffic volume only. Its "dropped" number is network-card statistics, not blocked connections, and it will normally read zero even when your firewall is working perfectly. Do not use it to judge whether a rule is working.
This applies to VMs. Apps are not configured from this tab.
Web addresses. Under Network → Web addresses, pick a machine and the port its web server listens on, and it gets a public https://…javer.pro address with a certificate, reachable from everywhere over IPv4 and IPv6. Your server has to listen on 0.0.0.0, not 127.0.0.1 — on 127.0.0.1 it only accepts connections from inside the machine, and the address looks broken. Web addresses carry websites and APIs only.
Team accounts
A team lets several people manage the same apps, VMs, and databases under one bill. Create one from Settings → Teams and invite members by email address.
An invited person does not need a Javer account yet — the invite resolves automatically the first time they sign in with that email. Invites are free; you are billed per seat, meaning per member who has actually joined.
A team has its own resource pool sized by seat count, separate from each member's personal account. Personal apps stay private and are never visible to your team.
API keys
Create an API key on the API Keys page (in the menu under Domains & API) to use Javer's REST API from scripts, CI or an AI agent. The key is shown once when created — copy it immediately, as only a hash is stored.
Send it as a bearer token on any API request:
curl -H "Authorization: Bearer jvr_live_..." \
https://panel.javer.pro/api/apps
Each key has a level, chosen when you create it:
- Read only — can look at everything, change nothing.
- Standard (the default) — can deploy, start and stop, resize, change settings and run commands in your machines, but cannot delete anything or overwrite data.
- Full — can also delete apps, machines and databases, restore or import a database over its current contents, and revert a machine to a snapshot.
Some things no key can do at any level: create or revoke keys, change billing or teams, change your password or two-factor settings, buy or renew a domain, get a domain transfer code, or delete the account. Those need you, signed in to the panel. A refused request returns HTTP 403 with a code of api_key_read_only, api_key_needs_full or api_key_not_allowed, and a message saying what to do instead.
Giving a key to an AI agent? Start with Standard: it can build and fix things but cannot delete them. Every request a key makes is recorded for 90 days — press ACTIVITY next to the key to see what it did and whether it was allowed.
Keys do not expire. Revoking one takes effect immediately. To rotate, create the replacement first, switch your scripts over, then revoke the old key.
Connecting an AI agent
AI tools that support MCP — Claude, Claude Code, Cursor and others — can run your hosting directly. Give the tool this address and one of your API keys:
https://panel.javer.pro/api/mcp
For example, in Claude Code:
claude mcp add --transport http javer https://panel.javer.pro/api/mcp \
--header "Authorization: Bearer jvr_live_..."
The agent can then list and create VMs, run commands on them, take snapshots, publish web addresses, deploy and restart apps, read logs, set environment variables, create databases and change firewall rules. The key's level still decides what it may do: with a Standard key, a request to delete something is refused, and the agent is told why. Everything it does shows up under the key's ACTIVITY, including the commands it ran.
Writing your own tool instead? The same operations are described as an OpenAPI map at https://panel.javer.pro/api/openapi.json.
Plan limits
Every plan includes every app feature above — paying more buys capacity, not unlocked functionality. The one exception is virtual machines, which need a paid plan.
| Plan | Memory | Storage | Items |
|---|---|---|---|
| Free Dev | 512 MB | 2 GB | 1 |
| Nano | 1 GB | 20 GB | 3 |
| Pro | 3 GB | 50 GB | 5 |
| Ur Rich, We Know It | 6 GB | 100 GB | 8 |
"Items" counts apps, VMs, and databases together. Memory and storage are a shared pool — a Pro account can run one 3 GB app or three 1 GB ones. Downgrading never deletes anything: existing resources keep running, but you cannot create new ones until you are back within the smaller plan's budget.
Troubleshooting
My site shows 502 Bad Gateway. Your app almost certainly is not listening on PORT. See the section above.
The deploy said it failed, but the app exists in my dashboard. Long builds can time out in the browser while finishing successfully on our side. Check your dashboard before retrying — if the app is there, it deployed.
"You already have an app with that name." That name is taken by an existing app, including one from a deploy you thought had failed. Delete it or choose a different name.
I hit my plan limit. Delete something you are not using, or upgrade under Settings → Billing. Limits apply to your total across apps, VMs, and databases.
Still stuck? The quickest route is the Support tab in your panel — the assistant there can already see your plan and your apps, so you do not have to explain your setup. If it cannot solve something it opens a ticket with a case number and a human replies on that ticket. Not logged in? Use javer.pro/support, and if you are locked out of your account entirely you can pull up an existing ticket there with your case number and the email you used. You can still email [email protected] if you prefer with your app name and roughly when the problem started.