Your First Hop3 Deployment: From Zero to Production¶
Remember the first time you deployed something to Heroku? git push heroku main and suddenly your side project was live on the internet. Hop3 brings that same feeling of "wait, it just... works?"
The difference: your code runs on your own server, with the same simplicity and full control.
Let's deploy a Flask app from scratch. An application with a database, custom domain, and SSL, on a server you own.
What You'll Need¶
- A server running Ubuntu 24.04+ or Debian 12+ (a $5/month VPS works fine)
- SSH access to that server
- A domain name (optional, but satisfying)
Don't have a server yet? Hetzner, Scaleway, DigitalOcean, Linode... can have you running in minutes. Hop3 isn't picky.
Setting Up the Server¶
First, let's install Hop3 on your server. SSH in and run the installer:
The installer takes a few minutes. It creates a hop3 user, installs Python, Node, nginx, and sets up the hop3-server service. When it finishes, you'll see a success message.
Installing the CLI¶
Now switch to your local machine. The CLI is how you'll interact with your server:
Verify it works:
Connecting to Your Server¶
Tell the CLI where your server lives:
Test the connection:
You should see an empty list.
Building a Flask App¶
Let's create something simple but real: an app that tracks page visits. It'll exercise the full deployment pipeline.
Create app.py:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello from Hop3!"
@app.route("/health")
def health():
return "OK"
if __name__ == "__main__":
app.run()
Create requirements.txt:
Create a Procfile (yes, like Heroku):
And a hop3.toml for Hop3-specific configuration:
All told, about 30 lines across four files.
The Moment of Truth¶
Deploy:
-> Uploading source (3 files, 1.2 KB)
-> Detecting toolchain: python (found requirements.txt)
-> Creating virtual environment...
-> Installing dependencies...
-> Starting application...
-> App deployed successfully!
URL: http://your-server.com:5000
Open that URL. See "Hello from Hop3!"? You just deployed an application.
Adding Your Domain¶
Running on an IP address and port is fine for testing, but let's make this look professional.
Update hop3.toml:
Point your DNS to the server:
Redeploy:
Hop3 automatically:
- Configures nginx with your domain
- Requests a Let's Encrypt SSL certificate
- Sets up HTTPS redirects
Visit https://myapp.example.com. That padlock icon means your SSL certificate was provisioned automatically.
Adding a Database¶
Most real apps need a database. Let's add PostgreSQL:
You now have a PostgreSQL database. Hop3 automatically injects DATABASE_URL into your app's environment.
Let's use it. Update app.py:
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get("DATABASE_URL")
db = SQLAlchemy(app)
class Visit(db.Model):
id = db.Column(db.Integer, primary_key=True)
timestamp = db.Column(db.DateTime, default=db.func.now())
@app.route("/")
def hello():
visit = Visit()
db.session.add(visit)
db.session.commit()
count = Visit.query.count()
return f"Hello! Visit count: {count}"
@app.route("/health")
def health():
return "OK"
Update requirements.txt:
And tell Hop3 to create the database tables on deploy. Update hop3.toml:
[metadata]
id = "myapp"
[env]
HOST_NAME = "myapp.example.com"
[run]
before-run = "flask db upgrade"
[healthcheck]
path = "/health"
Redeploy:
Refresh your browser. Each visit increments the counter. Your app now has persistent state.
Day-to-Day Operations¶
Now that your app is running, here's how you'll interact with it:
Check what's happening:
See your apps:
Get details:
App: myapp
Status: running
URL: https://myapp.example.com
Workers: 1 x web
Addons: myapp-db (postgres)
Last deployed: 2026-03-21 10:30:00
Need more capacity?
Now three gunicorn workers handle requests.
When Things Go Wrong¶
When they do, here's how to debug.
App won't start? Check the logs:
Common culprits:
- Missing dependency in
requirements.txt - Typo in
Procfile - Port not binding to
$PORT
502 Bad Gateway? Nginx is running but can't reach your app:
Make sure you're binding to 0.0.0.0:$PORT, not 127.0.0.1 or a hardcoded port.
Database connection failed? Check that the addon is attached:
Look for DATABASE_URL in the output.
Quick Reference¶
Commands you'll use constantly:
hop3 deploy myapp # Deploy changes
hop3 app logs myapp # View logs
hop3 app restart myapp # Restart
hop3 app stop myapp # Stop
hop3 app start myapp # Start
hop3 app destroy myapp # Delete (careful!)
hop3 env set --app myapp KEY=val # Set environment variable
hop3 env show --app myapp # View configuration
What's Next?¶
You've got a production application running. From here you might want to:
- Add background workers for async tasks
- Configure static file serving for CSS/JS
- Set up automated backups
- Add monitoring and alerting
Check our guides for details on each of these.
Code, deploy, iterate.
For deeper configuration options, see Designing hop3.toml. Questions? Hit a snag? Open an issue and we'll help you out.