# Deploying Potato on Hetzner, Vultr or Linode

Source: https://www.potatoannotator.com/docs/deployment/deploy-vps

`potato deploy up --provider hetzner` puts an annotation study on a Hetzner Cloud virtual machine for about €6 a month, the lowest default price among Potato's paid VM targets. `--provider vultr` and `--provider linode` do the same on Vultr and Akamai's Linode for $10 and $12 a month. Each is an ordinary virtual machine with a disk that survives restarts, so a study runs on it for weeks without a backup service. Potato sets all three up the same way, with a firewall that opens only ports 22, 80 and 443, Docker, the Caddy web server with a Let's Encrypt certificate, and Potato running as a system service. This page needs Potato 2.10 or later and a config you have already run with `potato start`.

## Choosing among the three

The three differ in price, memory, billing currency and where the machine runs by default. The table gives the size Potato creates unless you pass `--size`, with the monthly price it prints:

| | `--provider hetzner` | `--provider vultr` | `--provider linode` |
|---|---|---|---|
| Default size | `cx23`, 2 vCPU and 4 GB | `vc2-1c-2gb`, 1 vCPU and 2 GB | `g6-standard-1`, 1 vCPU and 2 GB |
| Monthly price | about €6, with the IPv4 address | $10 | $12 |
| Default location | `nbg1`, Nuremberg | `ewr`, New Jersey | `us-east`, Newark |
| Token variable | `HCLOUD_TOKEN` | `VULTR_API_KEY` | `LINODE_TOKEN` |

Hetzner gives the most memory for the price, and Potato holds the item set in memory, so Hetzner suits a large corpus on a small budget. Hetzner bills in euros from a company in Germany, which some institutions' purchasing rules do not allow. Vultr and Linode bill in US dollars.

## Creating an API token

Each provider authenticates with an API token that you create in its console and put in your environment:

- **Hetzner.** In the Hetzner Cloud console, open the project's Security section and create an API token with read and write permission.
- **Vultr.** Create an API key in the Vultr dashboard and add your machine's IP address to the key's access-control list, or Vultr rejects every request.
- **Linode.** Create a personal access token with read and write access to Linodes, Firewalls and Volumes.

Install the deploy extra, export the token, and check that Potato can use it:

```bash
pip install 'potato-annotation[deploy]'
export HCLOUD_TOKEN=...
potato deploy providers --verify
```

## Deciding who can sign in

`potato deploy` does not change your sign-in settings, and the machine's address is public. If the config lets anyone register, the dry run below reports warning D003, "Anyone who finds the URL can register and annotate." For a crowdsourced study, open registration is usually intended. For named annotators, list them under `user_config.users` with `allow_all_users: false` ([Password Management](/docs/deployment/password-management)) or have them sign in with Google, GitHub or your institution ([SSO and OAuth](/docs/deployment/sso-oauth)) before you deploy.

## Checking the plan and deploying

A dry run needs no account and creates nothing. It prints every step, the estimated cost and any risky setting in the config:

```bash
potato deploy up myproject/config.yaml --provider hetzner --dry-run
potato deploy up myproject/config.yaml --provider hetzner
```

The second command deploys after you confirm the plan. It ends by printing the URL, an `https://` address on the machine's IP, and the path of the admin key file, `.potato/secrets.json` beside your config. The admin key opens the [admin dashboard](/docs/features/admin-dashboard) at `/admin`. Running `up` again after you edit the config uploads the new version to the same machine. During the study, `potato deploy logs myproject/config.yaml -f` follows the server log on all three providers.

`--region` and `--size` change the location and the machine, and `--volume-gb` adds a separate disk for the task's data. Hetzner sells its `cx` machines only in its European locations, so a deploy to its US locations, `ash` and `hil`, needs a `cpx` type passed with `--size`. If the type is not sold in the location you chose, Potato stops before creating anything and lists the locations that sell it.

## Certificates without a domain name

Without a domain name, Let's Encrypt issues the certificate for the machine's IP address. It lasts about six days and renews automatically. `potato deploy status` reports a renewal that fails, so check it every few days if the study runs unattended. To use your own domain, point a DNS A record at the machine's IP and redeploy with `--domain annotate.example.edu`. The Let's Encrypt account uses the address in your `git config user.email` as its contact, and `--acme-email` sets another one.

## Provider details

Linode requires a root password when a machine is created, even when SSH keys are supplied. Potato generates one, stores it in `.potato/secrets.json`, and turns off password login over SSH, so the password cannot be used to sign in. On Vultr, a separate disk from `--volume-gb` is attached after the machine starts, and the setup waits for the device to appear before formatting and mounting it.

## Ending the study

The annotations are on the machine's disk, which is deleted with the machine. Pull them to your machine first, check them, and then remove the server:

```bash
potato deploy pull myproject/config.yaml
potato deploy destroy myproject/config.yaml
```

`pull` writes everything the deployment collected into a new `potato-pull-<name>-<timestamp>` directory and copies the databases with SQLite's backup command. `destroy` will not run on a deployment that has never been pulled.

## Further reading

- [Running Potato Locally or in the Cloud](/docs/deployment/quick-deploy), for the other cloud targets, including DigitalOcean
- [Deploying an Annotation Server](/docs/guides/deploying-annotation-server), for choosing a host
- [VM providers reference](https://github.com/davidjurgens/potato/blob/master/docs/deployment/deploy-vps.md)
