Deploy Your First App
This guide gets you from an installed CLI to one app running over HTTPS on your own server.
You need
- EasyRunner CLI installed
- A license file
- A GitHub repo for your app
- A domain or subdomain you control
- Either a Hetzner account or an existing Ubuntu 24.04 server
1. Install and Set Up EasyRunner
brew tap janaka/easyrunner # (1)!
brew install easyrunner-cli-beta # (2)!
er --version # (3)!
er license install ~/Downloads/easyrunner-license.jwt # (4)!
er setup --mode server # (5)!
- Adds the EasyRunner Homebrew tap.
- Installs the beta channel. Use the stable channel if you prefer conservative releases.
- Confirms the CLI is available as
er. - Installs your license file.
- Stores EasyRunner control-plane state on this machine.
What is server mode?
Server mode means this EasyRunner install stores the control-plane state: servers, apps, links, and secrets. For a first setup, your laptop is a good place for that state.
Checkpoint
er --help, er license status, and er config show should work before you prepare a web host.
2. Prepare a Web Host
```bash
er link hetzner default --api-key
- Stores a Hetzner API token in your keyring.
- Creates and registers a Hetzner server.
- Installs the EasyRunner web-host stack.
- Checks the server setup.
!!! info "What happens" EasyRunner handles the cloud provisioning step, then the server joins the same web-host lifecycle as any manually provisioned Ubuntu server.
```bash
er server add my-first-server
- Registers the Ubuntu server in EasyRunner and creates a dedicated SSH key.
- Prints the public key. Add it to
authorized_keysor your provider's SSH-key UI before initialization. - Installs the EasyRunner web-host stack.
- Checks the server setup.
!!! info "What happens" You own the provisioning step. EasyRunner takes over once its generated SSH key can access the server.
3. Link GitHub
- Starts GitHub device-flow auth and stores the token in your keyring.
- Confirms the integration links EasyRunner can use.
EasyRunner uses this link to create repository-specific deploy keys for Flow A deployments.
4. Add the App
er app add my-app my-first-server git@github.com:yourname/your-repo.git --custom-domain app.example.com
Use the SSH GitHub URL, not the HTTPS URL.
What happens
EasyRunner stores the app name, target web host, repo URL, domain, and default deploy-flow settings. It does not deploy yet.
5. Add App Configuration to Your Repo
Flow A expects your app repo to contain:
- A
DockerfileorContainerfile .easyrunner/docker-compose-app.yaml
Minimal Compose-format app configuration:
name: my-app # (1)!
services:
web: # (2)!
image: localhost/my-app:latest
environment:
- PORT=3000
restart: unless-stopped
networks:
- easyrunner_proxy_network
labels:
xyz.easyrunner.appNodeType: web # (3)!
xyz.easyrunner.appFramework: standardbackend
xyz.easyrunner.appContainerInternalPort: "3000" # (4)!
networks:
easyrunner_proxy_network:
name: easyrunner_proxy_network
external: true # (5)!
- Use an app-specific project name in the Compose-format file.
- This service entry is the public web process.
- Marks the service as publicly routable through Caddy.
- Must match the port your app listens on inside the container.
- Connects the service to EasyRunner's proxy network.
Commit and push these files before deploying.
6. Point DNS at the Server
Create an A record for app.example.com pointing at the web host IP.
If Cloudflare is linked and your domain is in that account, EasyRunner can create the record when you add the app.
DNS before certificates
Caddy can only issue the certificate after DNS points at the web host and ports 80 and 443 are reachable.
7. Deploy
EasyRunner clones the repo, builds the container image on the web host, generates systemd units, configures Caddy, and starts the app.
Check it:
- Checks the generated systemd/container status.
- Shows recent logs for the app's services.
Your app should be reachable at https://app.example.com.