> ## Documentation Index
> Fetch the complete documentation index at: https://docs.boat.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Always-on services

> Make a process come back by itself after stop, resume and fork, and restart your work in a repeatable way.

## What comes back after a resume or fork

`boat stop` makes a snapshot of the file system. `boat resume` restores that file system. `boat fork` makes a new sandbox from the latest snapshot. A resume takes a few seconds, for any amount of data in the sandbox.

For what a snapshot saves, restore behavior, retention, and how to look at or download a snapshot, see [Snapshots](/snapshots).

A stop and resume is the same as a server reboot:

| Process | After a resume |
| - | - |
| A systemd service that you enabled | Starts again by itself. |
| A process that you started by hand: a dev server, a background job, a tunnel, a browser session | Does not come back. Start it again, or make it a systemd service. |

## Run an always-on service

To make a process come back after stop, resume and fork with no action from you, run it as an enabled systemd service. The unit file is under `/etc`, which is in the snapshot. Thus a resumed or forked sandbox starts the service by itself.

```bash theme={null}
sudo tee /etc/systemd/system/my-app.service >/dev/null <<'UNIT'
[Unit]
Description=My app
After=network.target

[Service]
User=user
WorkingDirectory=/home/user/my-app
ExecStart=/usr/bin/npm run start
Restart=always

[Install]
WantedBy=multi-user.target
UNIT

sudo systemctl daemon-reload
sudo systemctl enable --now my-app
```

* `Restart=always` also starts the process again if it crashes.
* To check the service, run `systemctl status my-app`.
* To read its logs, run `journalctl -u my-app`.

Run these commands inside the sandbox. Use `boat ssh`, the [command endpoint](/api/reference/agent/execute-sandbox-command), or the `command` method of the SDKs.

If the service serves HTTP, expose it with `host <port>`. After a resume, `host` on the same port gives the same URL and token. Thus links that you gave out continue to work. See [Hosting](/hosting).

## Resume or fork

To continue earlier work, resume the sandbox. To branch earlier work, fork it. Both use the latest snapshot.

<CodeGroup>
  ```bash CLI theme={null}
  boat resume bx_f7k2q9hd
  boat fork bx_f7k2q9hd
  ```

  ```bash curl theme={null}
  curl -sS -X POST "$BOAT_API_BASE/sandboxes/bx_f7k2q9hd/resume" \
    -H "Authorization: Bearer $BOAT_API_KEY"

  curl -sS -X POST "$BOAT_API_BASE/sandboxes/bx_f7k2q9hd/fork" \
    -H "Authorization: Bearer $BOAT_API_KEY"
  ```

  ```ts TypeScript theme={null}
  await sandbox.resume({ sandboxId: "bx_f7k2q9hd" });
  const forked = await sandbox.fork({ sandboxId: "bx_f7k2q9hd" });
  ```

  ```python Python theme={null}
  sandbox.resume("bx_f7k2q9hd")
  forked = sandbox.fork("bx_f7k2q9hd")
  ```
</CodeGroup>

## Repeatable setup

For repeatable workflows, make your setup and start commands idempotent:

<CodeGroup>
  ```bash CLI theme={null}
  boat ssh "$sandbox_id" -- bash -s < ./setup.sh
  boat ssh "$sandbox_id" "cd /home/user/ariana-ide-private && npm run dev"
  ```

  ```bash curl theme={null}
  curl -sS -X POST "$BOAT_API_BASE/sandboxes/$BOAT_ID/commands" \
    -H "Authorization: Bearer $BOAT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"command":"bash ./setup.sh","cwd":"ariana-ide-private"}'

  curl -sS -X POST "$BOAT_API_BASE/sandboxes/$BOAT_ID/commands" \
    -H "Authorization: Bearer $BOAT_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"command":"npm run dev","cwd":"ariana-ide-private"}'
  ```

  ```ts TypeScript theme={null}
  await sandbox.command({ sandboxId, command: "bash ./setup.sh", cwd: "ariana-ide-private" });
  await sandbox.command({ sandboxId, command: "npm run dev", cwd: "ariana-ide-private" });
  ```

  ```python Python theme={null}
  sandbox.command(sandbox_id, CommandRequest(command="bash ./setup.sh", cwd="ariana-ide-private"))
  sandbox.command(sandbox_id, CommandRequest(command="npm run dev", cwd="ariana-ide-private"))
  ```
</CodeGroup>

For command timeouts and retries, see [Background commands](/long-running-tasks/background-commands#timeouts-and-retries).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.