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

# 1. Prepare the server

# 1. Prepare the server

> **In short.** You install Docker and some tools, and open only the ports that the app
> needs. You point your domain to the server and create your deploy and signing keys. Then
> you install the small scripts that run each deploy. At the end, the server accepts only
> releases that you signed, and only through your deploy key. You do this page once.

Log in to the server with your own administrator account. Use the provider's web console or
SSH. The [overview page](index.md) explains the words and the placeholders, for example
`<your-domain>`.

Each command block says where to type it: on **the server** or on **your computer**.

## Step 1. Check that Polymarket allows the server's location

1. On **the server**, ask Polymarket if it permits this location:

   ```sh theme={null}
   curl -s https://polymarket.com/api/geoblock
   ```

   If the server says `curl: command not found`, type `sudo apt install curl` and try again.

2. Read the answer. It must contain `"blocked":false`.

3. If the answer contains `"blocked":true`, stop. This server cannot trade. Rent a server in
   a different region.

4. On **the server**, make sure that no proxy is set. Type each command. Each command must
   show nothing:

   ```sh theme={null}
   env | grep -i _proxy
   ```

   ```sh theme={null}
   grep -i proxy /etc/environment
   ```

   ```sh theme={null}
   sudo systemctl show docker --property=Environment | grep -i proxy
   ```

   ```sh theme={null}
   sudo grep -s proxies /root/.docker/config.json
   ```

## Step 2. Install the software

1. On **the server**, install Docker. Follow Docker's own instructions:
   [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/). You need Docker Engine 27 or later, with the
   compose and buildx plugins. Docker's instructions install the two plugins.

2. On **the server**, install git, age, rsync and the firewall:

   ```sh theme={null}
   sudo apt install git age rsync ufw
   ```

3. On **the server**, turn on the automatic clock sync:

   ```sh theme={null}
   sudo timedatectl set-ntp true
   ```

**Is it working?**

| Command on the server | Expected result |
| - | - |
| `sudo docker version` | The `Server:` part shows version 27 or later |
| `sudo docker compose version` | A version number |
| `timedatectl \| grep synchronized` | `System clock synchronized: yes` |
| `command -v rrsync` | `/usr/bin/rrsync` |

## Step 3. Open only the ports the app needs

Ports 80 and 443 serve the site. Port 22 is SSH. Only your computer and the backup machine
can use port 22.

CAUTION: Make sure that `<your-ip>` is correct before you type `sudo ufw enable`. An
incorrect address locks you out of SSH. If this occurs, use the provider's web console to
correct the rule.

On **the server**, type these commands in this order:

```sh theme={null}
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from <your-ip> to any port 22 proto tcp
sudo ufw allow from <backup-ip> to any port 22 proto tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp
sudo ufw enable
```

If your provider has a firewall in its control panel, set the same rules there.

**Is it working?** On the server, `sudo ufw status` shows `Status: active` and the `ALLOW`
rules for ports 22, 80 and 443.

## Step 4. Point your domain at the server

At your DNS provider, add these two records for `<your-domain>`:

| Type | Value |
| - | - |
| `A` | `<server-ip>` |
| `CAA` | `0 issue "letsencrypt.org"` |

Add an `AAAA` record only if these two conditions are true:

* The server has an IPv6 address.
* You will do the IPv6 check (S6) in the [security checklist](advanced.md#security-checklist).

**Is it working?** On your computer, `dig +short <your-domain>` shows `<server-ip>`. A new
record can take up to 1 hour to show.

## Step 5. Create the two service accounts

The `deploy` account receives the deploy commands. The `sesame-backup` account lets the
backup machine read the encrypted backups.

On **the server**:

```sh theme={null}
sudo adduser --disabled-password --gecos "" --shell /bin/sh deploy
```

```sh theme={null}
sudo adduser --system --group --home /var/lib/sesame-backup --shell /bin/sh sesame-backup
```

WARNING: Do not add `deploy` to the `docker` group. Access to Docker gives full control of
the server.

## Step 6. Move SSH keys to root-owned files

After this step, no account can add a key for itself.

Your own login must use an SSH key, because Step 11 turns off password logins. If you log
in with a password now, type `ssh-copy-id <admin>@<server-ip>` on **your computer** first.

On **the server**:

```sh theme={null}
sudo install -d -o root -g root -m 0755 /etc/ssh/authorized_keys
for u in <admin> deploy sesame-backup; do
  sudo install -o root -g root -m 0644 /dev/null "/etc/ssh/authorized_keys/$u"
done
sudo sh -c 'cat /home/<admin>/.ssh/authorized_keys > /etc/ssh/authorized_keys/<admin>'
sudo rm -rf /home/deploy/.ssh
```

The `cat` line copies your own key, so your login continues to work after Step 11.

## Step 7. Create the deploy key

1. Put the security key into **your computer**.

2. On **your computer**, create the deploy key:

   ```sh theme={null}
   ssh-keygen -t ed25519-sk -O verify-required -C sesame-deploy -f ~/.ssh/sesame_deploy
   ```

   If you do not have a security key, use the command below. Set a passphrase when it asks.

   ```sh theme={null}
   ssh-keygen -t ed25519 -C sesame-deploy -f ~/.ssh/sesame_deploy
   ```

3. On **your computer**, show the public key. Copy the line that it shows:

   ```sh theme={null}
   cat ~/.ssh/sesame_deploy.pub
   ```

4. On **the server**, open the key file of the deploy account:

   ```sh theme={null}
   sudoedit /etc/ssh/authorized_keys/deploy
   ```

5. Write one line: the start below, then a space, then the public key that you copied.

   ```text theme={null}
   restrict,verify-required,from="<your-ip>",command="/usr/local/sbin/sesame-deploy-shell" sk-ssh-ed25519@openssh.com AAAA... sesame-deploy
   ```

   For a key with a passphrase, remove `verify-required,` from the start. That public key
   starts with `ssh-ed25519`.

6. Save the file and close the editor.

The `from="<your-ip>"` part accepts the key only from your computer's address. If that
address changes, change it in this file.

WARNING: Do not load this key into an ssh-agent (`ssh-add`). The deploy script refuses a
key that has no passphrase and is not on a security key.

## Step 8. Set up release signing and sign the first release

The server installs only release tags that you signed. Do all of this step on **your
computer**.

1. Create a signing key. Set a passphrase when it asks:

   ```sh theme={null}
   ssh-keygen -t ed25519 -C sesame-release -f ~/.ssh/sesame_release
   ```

2. Tell git to sign with this key:

   ```sh theme={null}
   git config --global gpg.format ssh
   git config --global user.signingkey ~/.ssh/sesame_release.pub
   ```

3. Create your list of allowed signers. Keep it outside the repository:

   ```sh theme={null}
   mkdir -p ~/.config/sesame
   echo "<your-email> namespaces=\"git\" $(cat ~/.ssh/sesame_release.pub)" > ~/.config/sesame/allowed_signers
   ```

4. Show the list and copy the line. The server needs it in Step 9:

   ```sh theme={null}
   cat ~/.config/sesame/allowed_signers
   ```

5. Go to your copy of the repository. Sign a tag on the reviewed commit that you want to
   run. Each release tag name must start with `release-`:

   ```sh theme={null}
   git tag -s <tag> <commit> -m "<tag>"
   ```

6. Send the tag to the repository:

   ```sh theme={null}
   git push origin <tag>
   ```

## Step 9. Create the server's deploy settings

1. On **the server**, create the settings folders and files:

   ```sh theme={null}
   sudo install -d -o root -g root -m 0755 /opt/sesame /etc/sesame
   sudo install -o root -g root -m 0644 /dev/null /etc/sesame/deploy.conf
   sudo install -o root -g root -m 0644 /dev/null /etc/sesame/allowed_signers
   ```

2. Open the list of allowed signers:

   ```sh theme={null}
   sudoedit /etc/sesame/allowed_signers
   ```

3. Paste the line from Step 8, item 4. Save the file and close the editor.

4. Open the deploy settings:

   ```sh theme={null}
   sudoedit /etc/sesame/deploy.conf
   ```

5. Write these four lines with your values. Save the file and close the editor.

   ```text theme={null}
   DOMAIN=<your-domain>
   ACME_EMAIL=<your-email>
   REPO_URL=<repo-url>
   VERIFY_TAGS=yes
   ```

| Line | What it is |
| - | - |
| `DOMAIN` | The name of the site. The app answers only at `https://<DOMAIN>` |
| `ACME_EMAIL` | Your email address, for the free HTTPS certificate from Let's Encrypt |
| `REPO_URL` | The repository that the server gets the releases from |
| `VERIFY_TAGS` | `yes` installs only the tags that you signed. Keep it `yes` |

For a private repository, see [Private repository](advanced.md#private-repository).

## Step 10. Install the server scripts

These commands get your signed tag and check its signature. Then they install the three
parts that the deploy uses:

| Part | What it does |
| - | - |
| `sesamectl` | Runs each deploy command as root |
| `sesame-deploy-shell` | Accepts only a short list of commands from the deploy key |
| The backup timer | Encrypts new backups each hour. You turn it on in [3. Backups](3-backups.md) |

1. On **the server**, become root:

   ```sh theme={null}
   sudo -i
   ```

2. Get the tag and check its signature:

   ```sh theme={null}
   git init -q --bare /opt/sesame/repo.git
   git -C /opt/sesame/repo.git fetch --no-tags <repo-url> refs/tags/<tag>:refs/tags/<tag>
   oid=$(git -C /opt/sesame/repo.git rev-parse --verify refs/tags/<tag>)
   git -C /opt/sesame/repo.git -c gpg.ssh.allowedSignersFile=/etc/sesame/allowed_signers verify-tag "$oid"
   ```

   The last line must show `Good "git" signature`. If it does not, stop. Do Step 8 and
   Step 9 again.

3. Install the scripts and the timer:

   ```sh theme={null}
   mkdir /tmp/sesame-setup && git -C /opt/sesame/repo.git archive "$oid" deploy | tar -x -C /tmp/sesame-setup
   install -o root -g root -m 0755 /tmp/sesame-setup/deploy/sesamectl /usr/local/sbin/sesamectl
   install -o root -g root -m 0755 /tmp/sesame-setup/deploy/sesame-deploy-shell /usr/local/sbin/sesame-deploy-shell
   install -m 0644 /tmp/sesame-setup/deploy/systemd/sesame-seal-backups.* /etc/systemd/system/
   systemctl daemon-reload
   ```

4. Open the access rule for the deploy account:

   ```sh theme={null}
   visudo -f /etc/sudoers.d/sesame
   ```

5. Paste these two lines. They are the content of `deploy/sudoers.example`. Save the file
   and close the editor.

   ```text theme={null}
   Defaults:deploy env_reset, !setenv, secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
   deploy ALL=(root) NOPASSWD: /usr/local/sbin/sesamectl
   ```

6. Remove the temporary files and leave the root shell:

   ```sh theme={null}
   rm -rf /tmp/sesame-setup
   exit
   ```

**Is it working?** On the server, `sudo -l -U deploy` shows `/usr/local/sbin/sesamectl` and
no other command.

## Step 11. Lock down SSH

This step turns off password logins and root logins. It also limits each of the two service
accounts to its one task.

1. On **the server**, copy the SSH settings from the tag:

   ```sh theme={null}
   sudo install -o root -g root -m 0644 /dev/null /etc/ssh/sshd_config.d/50-sesame.conf
   sudo sh -c 'git -C /opt/sesame/repo.git show refs/tags/<tag>:deploy/sshd-sesame.conf.example > /etc/ssh/sshd_config.d/50-sesame.conf'
   ```

2. Open the file:

   ```sh theme={null}
   sudoedit /etc/ssh/sshd_config.d/50-sesame.conf
   ```

3. On the `AllowUsers` line, replace `admin` with `<admin>`. Save the file and close the
   editor.

4. Check the settings and load them:

   ```sh theme={null}
   sudo sshd -t && sudo systemctl reload ssh
   ```

5. Keep your current session open. Open a new terminal on **your computer** and log in to
   the server again. Close the first session only after the new login works.

**Is it working?** On the server, `sudo sshd -T | grep -i '^passwordauthentication'` shows
`passwordauthentication no`. If it shows `yes`, a different file in `/etc/ssh/sshd_config.d/`
turns password logins on. Remove that line from that file and do item 4 again.

## Step 12. Record the server's fingerprint

1. In the provider's **web console**, not over SSH, show the server's fingerprint:

   ```sh theme={null}
   ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub
   ```

2. Write down the part that starts with `SHA256:`.

3. On **your computer**, connect to the server by its domain name:

   ```sh theme={null}
   ssh <admin>@<your-domain>
   ```

4. ssh shows an `ED25519 key fingerprint` and asks if you want to continue. Compare it with
   the fingerprint from item 2.

5. If the two fingerprints are the same, type `yes`. If they are different, type `no` and
   stop. Do not deploy to this server.

6. Type `exit` to close the connection.

After this step, the deploy refuses a server with a different fingerprint. The backup
machine does the same comparison in [3. Backups](3-backups.md).

## Is it working?

On **your computer**, send a command that the server must refuse. When ssh asks, type the
PIN of the security key and touch the key. For a key file, type the passphrase.

```sh theme={null}
ssh -i ~/.ssh/sesame_deploy -o IdentityAgent=none deploy@<your-domain> id
```

The result is `sesame-deploy-shell: refused: not an allowed sesamectl command`. If you see a
different message, see [Troubleshooting](troubleshooting.md#deploy-commands-fail).

Previous: [Overview](index.md) · Next: [2. First deploy](2-first-deploy.md)


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