# Deploying to VMs & Bare Metal > Source: `src/content/docs/deploy/vm-and-bare-metal.mdx` > Canonical URL: https://rivet.dev/docs/deploy/vm-and-bare-metal > Description: Deploy your RivetKit app to any Linux VM or bare metal host. --- ## Steps ### Prerequisites - A Linux VM or bare metal server with SSH access - Your RivetKit app - If you don't have one, see the [Quickstart](/docs/actors/quickstart) page or our [Examples](https://github.com/rivet-dev/rivet/tree/main/examples) - Access to the [Rivet Cloud](https://dashboard.rivet.dev/) or a [self-hosted Rivet Engine](/docs/general/self-hosting) ### Upload Your App - Build your RivetKit app locally - Copy the build output to your server (example): ```bash scp -r ./dist user@server:/opt/rivetkit-app ``` Place the files somewhere readable by the service user, such as `/opt/rivetkit-app`. ### Set Environment Variables After creating your project on the Rivet dashboard, select VM & Bare Metal as your provider. You'll be provided `RIVET_ENDPOINT` and `RIVET_PUBLIC_ENDPOINT` environment variables to use in the next step. ### Create the systemd Service Create `/etc/systemd/system/rivetkit-app.service`: ```ini [Unit] Description=RivetKit App After=network.target [Service] Type=simple WorkingDirectory=/opt/rivetkit-app ExecStart=/usr/bin/node server.js Restart=on-failure Environment=RIVET_ENDPOINT= Environment=RIVET_PUBLIC_ENDPOINT= [Install] WantedBy=multi-user.target ``` Replace the environment values with those from the Rivet dashboard and adjust paths to match your deployment. ### Start the Service Reload systemd units and start the service: ```bash sudo systemctl daemon-reload sudo systemctl enable --now rivetkit-app.service ``` ### Connect to Rivet 1. Ensure your server is accessible via a public URL (e.g. `https://my-app.example.com`) 2. On the Rivet dashboard, paste your URL with the `/api/rivet` path into the connect form (e.g. `https://my-app.example.com/api/rivet`) 3. Click "Done" If you front your app with a reverse proxy or load balancer (NGINX, HAProxy, Caddy, AWS ALB/NLB, etc.), raise its idle / read timeout to at least 1 hour (`3600` seconds). Rivet envoys connect to your app over long-lived WebSockets, and clients (browsers, SDKs) do the same. Default proxy timeouts (typically 30 to 60 seconds) drop these connections and cause reconnect storms. Examples: - **NGINX**: `proxy_read_timeout 3600s;` and `proxy_send_timeout 3600s;` in the relevant `location` block. - **HAProxy**: `timeout client 1h` and `timeout server 1h` in the matching frontend / backend. - **AWS ALB / NLB**: set the load balancer attribute `idle_timeout.timeout_seconds = 3600`. ## Operating ### Restart Restart the service after deploying new builds or environment changes: ```bash sudo systemctl restart rivetkit-app.service ``` ### Logs Follow realtime logs when debugging: ```bash sudo journalctl -u rivetkit-app.service -f ``` _Source doc path: /docs/deploy/vm-and-bare-metal_