Steps
-
Make sure secrets are not in the repository
Run this on the laptop, in the project.
.envmust be ignored, and git must not track it. If the second command prints a file, it is already tracked: take it out of git, and treat every key in it as leaked.$ git check-ignore -v .env $ git ls-files | grep -i env
-
Commit and push the code
Everything that is not a secret and not a generated file goes through git. Keep
node_modules,.venvand build output out of it.$ git status $ git add -A && git commit -m "ready to move" $ git push
-
Clone the project on the server
Log in as a normal user, not root. For a private repository, create a key on the server and add the public half to the repository as a read-only deploy key (on GitHub: Settings, Deploy keys).
$ ssh [email protected] $ sudo apt install -y git $ ssh-keygen -t ed25519 -C "server" $ cat ~/.ssh/id_ed25519.pub $ git clone [email protected]:you/your-project.git && cd your-project
-
Copy the secrets by hand
Run this on the laptop. The file travels over SSH and lands readable only by its owner. Do not paste keys into chats or tickets.
$ scp .env [email protected]:~/your-project/.env $ ssh [email protected] 'chmod 600 ~/your-project/.env'
-
Copy the data git does not hold
Uploads, local files and databases come next. Add
-nfor a dry run first: it lists what would be copied and changes nothing. A slash at the end of the source copies the contents of the folder, not the folder itself.$ rsync -avzn --progress ./uploads/ [email protected]:~/your-project/uploads/ $ rsync -avz --progress ./uploads/ [email protected]:~/your-project/uploads/
A Postgres database moves as a dump. Create an empty database with the same name on the server first.
$ pg_dump -Fc mydb > mydb.dump $ scp mydb.dump [email protected]:~ $ ssh [email protected] 'pg_restore -d mydb ~/mydb.dump'
-
Install the dependencies from the lockfile
Use the lockfile, so the server gets the same versions as your laptop. Check that the runtime matches too: compare
node -vorpython3 --versionon both machines.# Node $ npm ci # Python $ sudo apt install -y python3-venv $ python3 -m venv .venv && . .venv/bin/activate $ pip install -r requirements.txt
-
Start the app and open its port
On your laptop the app listens on
localhost. On a server it must listen on0.0.0.0, or only the server itself can reach it. Start it, look at the listening sockets, then open the port in the firewall. Allow SSH first, or you lock yourself out.$ npm start # the app must listen on 0.0.0.0:3000 $ ss -tlnp | grep 3000 $ sudo ufw allow OpenSSH $ sudo ufw allow 3000/tcp $ sudo ufw enable
To keep it running after you close SSH, put it in tmux or a service: the next guide shows both.
Check that it works
Ask for the page from the laptop, not from the server. If this prints HTTP/1.1 200, the project is live at the server's address.
$ curl -I http://203.0.113.10:3000Then close the laptop and request it again. It still answers, because the app now runs on the server.
The short way: a computer with root and an agent that does the chores
An Uno computer is ordinary Linux with root, so the same commands work on it. Or skip the typing: tell the agent in Uno Work to clone the repository, install the dependencies and start the app, and watch every command it runs. Plus and above come with 1 public address; a static site goes to a free https address from a folder.
Small: $5 a month
Where to move: Uno against a classic VPS
The same 1 vCPU class. What you pay, and what you get with it.
| Uno Small | Budget VPS Hetzner, OVH, Contabo | Cloud VPS DigitalOcean, Vultr, Linode | |
|---|---|---|---|
| Price a month | $5 | $4.5–6.5 | $5–7 |
| Root and Docker | yes | yes | yes |
| Who sets it up | an AI agent, or you | you, over SSH | you, over SSH |
| When idle | asleep, memory kept, earns boosts | runs and bills all month | runs and bills all month |
| Cloud storage | 25 GB included | separate product | separate product |
| Sites and forms | free, one message | set up a web server | set up a web server |
| AI in the plan | 5 h a month, Uno AI optional | no | no |
Prices checked 2026-10-01. Budget hosts sell memory cheaper per GB. If all you need is a lot of RAM and nothing else, they are the better deal.
Pick the size of the server you move to
Every plan is a real Linux computer with root and Docker. Start small; move up in the console, your files come with you.
Small
A Telegram bot, a VPN, a small backend
$5/ month
- 1 vCPU · 1 GB
- 15 GB disk
- 25 GB cloud storage
- 5 boosts a month
Plus
Agents that work with your laptop closed
$20/ month
- 4 vCPU · 4 GB
- 40 GB disk
- 100 GB cloud storage
- Uno Work in the cloud
Pro
A product in production, a second MacBook
$70/ month
- 16 vCPU · 16 GB
- 120 GB disk
- 300 GB cloud storage
- Speed of a MacBook Air M4
Max
A team and many agents at once
$200/ month
- 32 vCPU · 48 GB
- 300 GB disk
- 1,024 GB cloud storage
- 5 public IPv4
Add Uno AI to any plan: 40 h of AI work a month on Small, 100 h on Plus, unlimited on Max. Today: GLM-5.3 Flash and MiMo v2.6 Pro. Or sign in with your own Claude or ChatGPT.
What this guide does not cover
- It moves a project to one server. It sets up no load balancer, no second copy and no staging.
- A reverse proxy and an https certificate are a separate step. Without them the app answers on plain
httpand a port number. - MySQL, MongoDB and others have their own dump tools. Only Postgres is shown here.
Common problems
It works on my laptop and fails on the server
.env, a different runtime version, or a file git ignores. Compare node -v or python3 --version, and read the first error line, not the last."Permission denied (publickey)" on git clone
cat ~/.ssh/id_ed25519.pub and add it as a deploy key, or clone over https with a token.The app answers on the server, but not from my laptop
127.0.0.1: bind it to 0.0.0.0. Or the firewall blocks the port: check sudo ufw status, and the provider's own firewall if it has one.rsync created a folder inside a folder
./uploads/ copies the contents, ./uploads copies the folder by name. Use the dry run to see the result before you copy.