Skip to content

Deploy your first app

In this tutorial, you deploy a web server to a device. Along the way you write a suta.yaml, review a plan, start a rollout and watch the device accept the change. It takes about ten minutes.

  • Complete the Quickstart, so you have a device that shows as Online. This guide calls it kitchen-pi; use your device’s name instead.
  • Sign in to the CLI with suta auth login. If you created the workspace, you’re an admin and have every permission you need. Otherwise, you need the Device manager role.
  • If the device runs Raspberry Pi OS, it needs Trixie. Podman, which runs your apps, is too old on Bookworm; move a Bookworm device to Suta OS first.
  1. Create a directory for your fleet’s configuration, and go to it:

    Terminal window
    mkdir my-fleet && cd my-fleet
  2. Create a file named suta.yaml with this content:

    suta.yaml
    # yaml-language-server: $schema=https://suta.dev/schema/suta.json
    project: my-fleet
    os: latest
    apps:
    hello:
    image: nginx:1.27
    ports: ["8080:80"]
    probe:
    http: /
    port: 80

Replace my-fleet with your project’s slug. You’ll find it in the dashboard on the project’s Overview, and with suta project list.

This describes one app, hello, that runs the public nginx image and serves it on port 8080 of the device. The probe tells the device how to check that the app works: it must answer HTTP requests on /.

Run:

Terminal window
suta plan --device kitchen-pi

The output shows what the device will get:

+ kitchen-pi · update to 3f2a9c1e0b7d
OS 2026.09.1
Apps: + hello
Plan: 1 to update, 0 unchanged, 0 pinned.
Plan 8c41…
Deploy it with suta deploy 8c41…

+ means the device will update, and the lines under it say what changes. The plan pinned nginx:1.27 to an exact image digest and recorded it in a new file, suta.lock. Planning hasn’t changed anything on the device yet.

Start a rollout of the plan you just reviewed, using the plan ID from the output, and follow it:

Terminal window
suta deploy PLAN_ID --wait

The device downloads the image, starts the app, and then watches it for a probation period of one minute. When the app has stayed healthy and the device has stayed connected for that long, the device accepts the change, and suta deploy exits.

  1. See what the device runs now:

    Terminal window
    suta device generations kitchen-pi

    Deploy #1 is accepted, and the hello app is running and healthy.

  2. Open http://DEVICE_ADDRESS:8080 in a browser on the same network as the device. You see the nginx welcome page. The device’s address is on its Overview tab in the dashboard, under Connection.

You can see the same information on the device’s Software tab in the dashboard, and the rollout under the project’s Deployments.

To see what happens when a change is broken, break the probe. In suta.yaml, change the probe path to one that doesn’t exist:

probe:
http: /does-not-exist
port: 80

Then plan and deploy again in one step:

Terminal window
suta deploy --device kitchen-pi --wait

suta deploy shows the plan and asks you to confirm. The device switches to a new generation as deploy #2, the probe fails, and the device puts the generation from deploy #1 back on its own. suta deploy exits with an error, and suta device generations shows deploy #2 as rolled back with the reason. In the dashboard, open the rollout under Deployments: the device’s row shows the same reason, with a link to the device’s logs around the time it failed. The device didn’t wait for Suta to tell it to roll back; it decided on its own.

Change the probe back to / before you go on.

Commit suta.yaml and suta.lock to version control. The lock file keeps image digests fixed, so the next plan changes only what you changed in suta.yaml, even if a tag like nginx:1.27 moves.