Developers → Guides

Deploy an app with git push

A NameOcean App Server is a Linux server with your project in a git repository. You push, it runs. This guide takes a Flask app from the first push to its own domain with HTTPS; Django, Node.js and Next.js differ in one line.

How requests reach your app

request path
visitor ──HTTPS:443──▶ NameOcean load balancer ──HTTP:80──▶ nginx ──▶ your app on 127.0.0.1:8000

The load balancer holds the certificates, so the server only serves port 80. Your app listens on 127.0.0.1:8000 under supervisor, and nginx passes requests to it.

1. A server and your SSH key

nameocean
$ nameocean servers plans
$ nameocean servers create --plan starter --yes
$ nameocean servers ls
ID   NAME      STATUS   PLAN     DEFAULT DOMAIN          DOMAINS
812  3f9a1c2e  running  starter  3f9a1c2e.nameocean.org  -
$ nameocean servers ssh-keys add 3f9a1c2e

A server is billed monthly; servers create without --yes only shows the price. You can also create it under Dashboard → Hosting. ssh-keys add installs ~/.ssh/id_ed25519.pub, which git uses to push.

2. The project

app.py
import os

from flask import Flask

app = Flask(__name__)


@app.get("/")
def home():
    return f"Hello from {os.environ.get('SITE_NAME', 'NameOcean')}"
requirements.txt
flask
gunicorn
.nameocean/deploy.sh
#!/bin/bash
# runs on the server after every push, in /root/app, with your env variables
set -e
pip install -r requirements.txt

deploy.sh is where build steps go: installing packages, migrations, npm run build. Its output shows up in your terminal when you push.

3. First deploy

nameocean
$ git add . && git commit -m "First deploy"
$ nameocean deploy 3f9a1c2e

nameocean deploy adds a git remote named nameocean, pushes the current branch into /root/app on the server (the server deploys that branch from then on), pushes it to your own origin too, and restarts the apps.

4. Run it (once)

Tell supervisor how to start the app and nginx to pass requests to it. Both files are on the server with examples for each stack; you only uncomment.

ssh
$ nameocean servers info 3f9a1c2e   # the ssh line
$ ssh -p 2152 root@3f9a1c2e.nameocean.org
# vi /root/conf/supervisor.conf   # uncomment the Flask [program:app] and the shared settings
# supervisorctl reread && supervisorctl update
# vi /root/conf/nginx.conf        # remove the static "location /", uncomment the proxy one
# nginx -t && systemctl reload nginx
# curl -s http://127.0.0.1/
Hello from NameOcean

The [program:app] for Flask:

/root/conf/supervisor.conf
[program:app]
command=/root/.pyenv/versions/app/bin/gunicorn app:app --workers 2 --bind 127.0.0.1:8000
directory=/root/app
environment=PATH="/root/.pyenv/versions/app/bin:/usr/local/bin:/usr/bin:/bin"
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/app.log

For other stacks only command changes (the file has these examples too):

Django/root/.pyenv/versions/app/bin/gunicorn myproject.wsgi:application --workers 2 --bind 127.0.0.1:8000
FastAPI/root/.pyenv/versions/app/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --workers 2
Node.js/usr/bin/node server.js with environment=NODE_ENV="production",PORT="8000",HOST="127.0.0.1"
Next.js/usr/bin/npx next start -H 127.0.0.1 -p 8000 and npm ci && npm run build in deploy.sh
Go/root/app/server and go build -o server . in deploy.sh

Your app is now live at https://3f9a1c2e.nameocean.org.

5. Settings and secrets

nameocean
$ nameocean servers env set 3f9a1c2e SITE_NAME=Kahvebot SECRET_KEY=…

Every app, deploy.sh and SSH session gets them, and the apps restart to read them. They are kept on the server only, never in the repository or in NameOcean's database.

6. Your domain

nameocean
$ nameocean bind kahvebot.com 3f9a1c2e

The domain's DNS must be on NameOcean. NameOcean adds the DNS records, issues the certificate and sets up the load balancer (HTTP to HTTPS, and the bare domain to www); it usually takes a few minutes. Nothing changes on the server.

7. Every deploy after that

nameocean
$ git commit -am "New page"
$ nameocean deploy
$ nameocean servers logs 3f9a1c2e --app app -f   # if it does not come up

Each deploy sends a server.deployed webhook event with the commit and whether the apps came up. Backups, restarts and the rest of the API: App Server API. The server has a guide for AI agents in /root/AGENTS.md.