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

# Deploy Apps with Sidekick

> Provision an Ubuntu VPS and deploy Dockerfile-based apps with Sidekick, Traefik, automatic TLS, and encrypted secrets.

Sidekick is an open-source deployment CLI that runs on your local computer. It builds an application from its `Dockerfile`, transfers the image to an Ubuntu VPS over SSH, and runs it behind Traefik with automatic HTTPS. It is a lightweight alternative to a web-based deployment panel.

Arct Cloud provides the unmanaged virtual machine. Sidekick and the applications it deploys are not preinstalled or managed by Arct Cloud; you remain responsible for server security, application data, backups, updates, and recovery.

## Requirements

| Basis                             |                          CPU |                          RAM |                      Storage | Operating system |
| --------------------------------- | ---------------------------: | ---------------------------: | ---------------------------: | ---------------- |
| **Official Sidekick minimum**     | No numeric minimum published | No numeric minimum published | No numeric minimum published | Ubuntu LTS       |
| **Practical Arct starting point** |                      2 vCPUs |                         4 GB |     40 GB NVMe (`cvm.micro`) | Ubuntu 24.04 LTS |

The practical recommendation is suitable for Sidekick, Traefik, and one lightweight application. Size the server for the applications you deploy, and allow additional storage for Docker images and application logs.

On your local computer, you also need:

* Homebrew, Sidekick, SOPS, and age
* A running Docker engine
* An SSH agent with the private key selected during server deployment
* `ssh`, `scp`, and `rsync`
* An application with a working `Dockerfile`
* A domain name, or Sidekick's default `sslip.io` hostname for testing

<Warning>
  Sidekick is best suited to stateless, single-container applications on one server. It generates its own Compose definition without persistent volumes. Use an external database and object storage for persistent state, or choose a platform with a documented stateful backup and restore workflow.
</Warning>

## Install Sidekick and Deploy an App

<Steps>
  <Step title="Deploy a fresh Ubuntu server">
    [Deploy a server](/compute/virtual-machines/deploy), select Ubuntu 24.04 LTS, and add an SSH key. Use a fresh VPS because `sidekick init` upgrades packages, installs Docker, and configures Traefik to own ports `80` and `443`.

    Do not install Nginx, Caddy, or another Traefik instance on the same server before initialization.
  </Step>

  <Step title="Restrict inbound access">
    Attach and verify a network-level firewall or ACL before running Sidekick:

    | Ports                   | Source                            | Purpose                                           |
    | ----------------------- | --------------------------------- | ------------------------------------------------- |
    | `22/tcp`                | Your current public admin IP only | SSH administration and deployments                |
    | `80/tcp`                | Any                               | HTTP redirect and ACME certificate issuance       |
    | `443/tcp`               | Any                               | HTTPS application traffic                         |
    | All other inbound ports | Deny                              | Open only when a workload explicitly requires one |

    Sidekick does not currently configure a firewall or rate limits. Application ports are routed inside Docker and should not be opened on the host.
  </Step>

  <Step title="Bootstrap the Sidekick account">
    Arct Cloud Ubuntu images use `ubuntu` as the default SSH user, while Sidekick initializes through either `root` or an existing `sidekick` account. Connect as `ubuntu` and create the account without enabling root SSH:

    ```bash theme={null}
    ssh ubuntu@YOUR_SERVER_IP

    sudo useradd -m -s /bin/bash -G sudo sidekick
    echo 'sidekick ALL=(ALL) NOPASSWD: ALL' \
      | sudo tee /etc/sudoers.d/sidekick >/dev/null
    sudo chmod 0440 /etc/sudoers.d/sidekick
    sudo visudo -cf /etc/sudoers.d/sidekick

    sudo install -d -o sidekick -g sidekick -m 0700 /home/sidekick/.ssh
    sudo install -o sidekick -g sidekick -m 0600 \
      /home/ubuntu/.ssh/authorized_keys \
      /home/sidekick/.ssh/authorized_keys
    exit
    ```

    From your local computer, verify both key access and passwordless sudo:

    ```bash theme={null}
    ssh sidekick@YOUR_SERVER_IP 'sudo -n true && echo "Sidekick account ready"'
    ```

    <Warning>The `sidekick` account receives passwordless sudo and later joins the Docker group. Either permission is effectively root-level access. Protect the SSH key and keep port `22` restricted.</Warning>
  </Step>

  <Step title="Prepare your local computer">
    Install the current release and its secret-management dependencies with Homebrew:

    ```bash theme={null}
    brew install sidekick sops age
    sidekick --version
    docker version
    ```

    Make sure Docker is running. Sidekick requires an SSH agent even when a key exists in the default `.ssh` directory:

    ```bash theme={null}
    ssh-add -l
    ssh-add ~/.ssh/id_ed25519
    ```

    Replace the key path when you use a different key. The first SSH connection records the server host key; verify its fingerprint before accepting it.
  </Step>

  <Step title="Initialize the VPS">
    Run the initializer on your local computer:

    ```bash theme={null}
    sidekick init
    ```

    Enter the VPS IPv4 address and an email address for ACME certificate notices. Current Sidekick versions may also ask you to name the VPS. The initializer connects as `sidekick`, updates Ubuntu, installs Docker and the server-side encryption tools, and starts Traefik.

    Sidekick stores the age private key in its local configuration. Restrict and back up that file immediately:

    ```bash theme={null}
    chmod 600 ~/.config/sidekick/default.yaml
    ```

    Keep an encrypted off-device copy. The matching age private key is required to decrypt the encrypted environment file stored on the VPS.
  </Step>

  <Step title="Verify the server">
    Start a new SSH session so Docker group membership takes effect, then inspect the installation:

    ```bash theme={null}
    ssh sidekick@YOUR_SERVER_IP
    docker version
    docker compose version
    docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
    ```

    Confirm that Traefik is running and only expected ports are published. Do not assume the initializer disabled root or password authentication. Keep this session open and add an early SSH configuration drop-in:

    ```bash theme={null}
    sudo tee /etc/ssh/sshd_config.d/00-sidekick-hardening.conf >/dev/null <<'EOF'
    PermitRootLogin no
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    EOF

    sudo chmod 0644 /etc/ssh/sshd_config.d/00-sidekick-hardening.conf
    sudo sshd -t
    sudo systemctl reload ssh
    sudo sshd -T | grep -E 'permitrootlogin|passwordauthentication|kbdinteractiveauthentication'
    ```

    Verify that all three effective values are `no`. From a second local terminal, confirm `ssh sidekick@YOUR_SERVER_IP` still works before closing the original session. Use the Arct Cloud VNC console if you lose SSH access.
  </Step>

  <Step title="Prepare DNS and the application">
    For a custom hostname such as `app.example.com`, create an `A` record pointing to the VPS public IPv4 address. Add an `AAAA` record only when IPv6 is configured and reachable.

    In the application directory, confirm that:

    * `Dockerfile` builds successfully on your local Docker engine
    * The application listens on `0.0.0.0`, not only `127.0.0.1`
    * You know the container's HTTP port
    * `.env` is excluded from Git

    Test the build before deploying:

    ```bash theme={null}
    docker build -t sidekick-test .
    ```
  </Step>

  <Step title="Launch the application">
    From the directory containing `Dockerfile`, run:

    ```bash theme={null}
    sidekick launch
    ```

    Provide these values when prompted:

    | Prompt           | Example           | Notes                                                                      |
    | ---------------- | ----------------- | -------------------------------------------------------------------------- |
    | Application name | `myapp`           | Use a URL-safe, unique name                                                |
    | Application port | `3000`            | The HTTP port inside the container, not a host port                        |
    | Domain           | `app.example.com` | Must resolve to this VPS; accept the generated `sslip.io` host for testing |
    | Environment file | `.env`            | Optional; Sidekick encrypts it with SOPS and age before transfer           |

    Sidekick builds the Linux image locally, transfers it directly to the VPS without a registry, creates the Compose service, and routes the hostname through Traefik. It writes deployment metadata to `sidekick.yml` in the project directory.
  </Step>

  <Step title="Verify HTTPS">
    Wait for DNS and certificate issuance, then check the public endpoint:

    ```bash theme={null}
    curl -I https://app.example.com
    ```

    Confirm the certificate hostname, application logs, and a representative request before sending production traffic.
  </Step>
</Steps>

## Deploy Updates and Previews

Run a normal update from the application directory:

```bash theme={null}
sidekick deploy
```

Sidekick rebuilds the image locally, transfers it over SSH, updates encrypted environment values when they changed, and replaces the running application. Test application-level health after every deployment; Sidekick cannot determine whether every business workflow is healthy.

Preview deployments require a clean Git worktree and use the current commit hash:

```bash theme={null}
sidekick preview
sidekick preview list
sidekick preview remove
```

Track `sidekick.yml` after reviewing it, but never commit `.env` or the global Sidekick configuration. With a custom application domain, preview URLs are subdomains of that hostname, so configure matching DNS records before relying on previews. Sidekick's generated `sslip.io` hostname is simpler for initial testing.

## Security, Data, and Maintenance

* Sidekick's firewall and rate-limiting support is not implemented. Keep the upstream network policy in place and review it whenever a workload changes.
* The `sidekick` account, Docker daemon, and Traefik's Docker socket are privileged infrastructure. A compromised deployment key can compromise every workload on the VPS.
* Sidekick-managed applications share the external `sidekick` Docker network. Do not treat that network as isolation between mutually untrusted applications.
* Store durable data in a separately backed-up service. Sidekick does not create or back up persistent volumes for the generated application service.
* Back up `~/.config/sidekick/default.yaml`, each project's `sidekick.yml`, DNS records, and all external data stores. Test restoration on a replacement VPS.
* Before `brew upgrade sidekick`, review the [release notes](https://github.com/MightyMoud/sidekick/releases) and keep a recoverable copy of configuration and application data. Patch Ubuntu and monitor `df -h` and `docker system df` regularly.

<Note>
  Sidekick's released documentation and current source can differ. Check `sidekick --help` for the commands installed on your workstation and review upstream changes before using it for a critical workload.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Sidekick cannot connect over SSH">
    Confirm port `22` allows your current public IP, `ssh sidekick@YOUR_SERVER_IP` succeeds, `ssh-add -l` lists the correct key, and `sudo -n true` works for the `sidekick` account. Resolve host-key warnings instead of disabling verification.
  </Accordion>

  <Accordion title="Initialization fails on ports 80 or 443">
    Run `sudo ss -lntp | grep -E ':(80|443) '` on the VPS. Stop or remove the conflicting reverse proxy before retrying; Sidekick's Traefik must own both ports.
  </Accordion>

  <Accordion title="HTTPS certificate issuance fails">
    Confirm the `A` record resolves to this VPS and ports `80` and `443` are reachable. Do not proxy the record through another service until the direct Sidekick route works.
  </Accordion>

  <Accordion title="Traefik returns 502 Bad Gateway">
    Confirm the port entered during `sidekick launch` matches the application's container port and the process listens on `0.0.0.0`. Inspect `docker ps` and the application container logs over SSH.
  </Accordion>

  <Accordion title="The local image build fails">
    Confirm Docker is running and build the same `Dockerfile` manually with `docker build -t sidekick-test .`. Fix the first build error before rerunning Sidekick.
  </Accordion>

  <Accordion title="A preview hostname does not resolve">
    Preview URLs prepend a commit hash to the application hostname. Add wildcard DNS for the custom hostname or use the generated `sslip.io` hostname while testing.
  </Accordion>
</AccordionGroup>

## Official Resources

<CardGroup cols={3}>
  <Card title="Sidekick Documentation" icon="book-open" href="https://www.sidekickdeploy.com/docs/introduction/what-is-sidekick/">
    Official concepts, commands, and design documentation.
  </Card>

  <Card title="Sidekick on GitHub" icon="github" href="https://github.com/MightyMoud/sidekick">
    Source code, roadmap, license, and issue tracker.
  </Card>

  <Card title="Sidekick Releases" icon="tag" href="https://github.com/MightyMoud/sidekick/releases">
    Release binaries and version history.
  </Card>
</CardGroup>

<Note>Sidekick is developed by the Sidekick project. Arct Cloud is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Sidekick.</Note>
