Self-hosted Sturdy

Run Sturdy anywhere, in your own datacenter or on your own workstation.

Self-hosted Sturdy in Docker

The easiest way to run Sturdy is to run the one-liner bundle. getsturdy/server contains the full Sturdy server and all of it's dependencies in a single container.

The container supports both linux/amd64 and linux/arm64 out of the box.

  1. Start Sturdy in Docker
    docker run --interactive \
        --pull always \
        --publish 30080:80 \
        --volume "$HOME/.sturdydata:/var/data" \
  2. Download and install the Sturdy app for macOS or Windows
  3. Start the app
  4. From the tray icon, switch to connect to the self-hosted instance of Sturdy running on your computer

  5. The Sturdy app will auto-detect instances running locally on the default ports 30080 and 30022
  6. ℹ️ Don't see your server? Restart the Sturdy app and try again.
  7. Follow the instructions in the app to setup your account and configure your server!

Optional: Setup GitHub Integration

Setup tunnel to localhost

GitHub integration heavily unilizes webhooks. To make that work, we have to ensure that self-hosted Sturdy instance can receive HTTP requests over the Internet.

ℹ️ If you have your own way of setting up a tunnel, you can skip this step.

Internally, at Sturdy, we are using ngrok to setup a tunnel to localhost. It's a free and easy to use service that allows you to expose your local Sturdy instance to the Internet in no time. Here is how to set it up:

  1. Install ngrok client following instructions on their Download page
  2. Run it like so:
    ngrok http 30080

Now your local port 30080 is exposed to the Internet, and in console, you will see a URL to access it. It would look something like this:

Create a GitHub App

  1. Go to
  2. Set the app name, for example sturdy-self-hosted
  3. Set the homepage to https://localhost:30080
  4. Callback URLs
    • sturdy:///setup-github
  5. Untick Expire user authorization tokens
  6. Tick Request user authorization (OAuth) during installation
  7. Tick Redirect on update
  8. Make sure that webhooks are active
  9. Set the webhook URL to ${YOUR_LOCAL_TUNNEL_HOSTNAME}/api/v3/github/webhook
    It should look something like this:
    ℹ️ If you use ngrok, keep in mind that every time it is started, it will generate a new URL. So don't forget to update it later, when ngrok is restarted.
  10. Permissions
    • Contents - Read & Write
    • Metadata - Read only
    • Pull Requests - Read & Write
    • Commit statuses - Read-only
    • Workflows - Read & Write
  11. Subscribe to events
    • Pull Request
    • Pull request review
    • Push
    • Status
    • Workflow job
  12. Click Create GitHub App - a new app will be created

Generate a client secret and a private key

Within the "General" tab of the newly created app:

  1. Take note of your App ID — you will use it later
  2. Take note of your Client ID — you will use it later
  3. Click Generate a new Client secret and take note of it — you will use it later
  4. At the bottom of the page, click Generate a private key which will also download it — you will use it later
  5. Move the private key file from your downloads folder to $HOME/.sturdydata/github-private.key.
     mv ~/Downloads/sturdy-self-hosted.TODAY.private-key.pem ~/.sturdydata/github-private.key
    This will make the private key accessible from within the docker container.

That's a lot of configuration! But now we are almost ready to start using Sturdy with a GitHub integration.

Restart Sturdy with GitHub configuration

To finish the configuration, we need to restart Sturdy with some of the configuration from the app we've just created:

docker run --interactive \
    --pull always \
    --publish 30080:80 \
    --volume "$HOME/.sturdydata:/var/data" \
    --env STURDY_GITHUB_APP_ID=<id> \
    --env STURDY_GITHUB_APP_CLIENT_ID=<client_id> \
    --env STURDY_GITHUB_APP_SECRET=<secret> \
    --env STURDY_GITHUB_APP_PRIVATE_KEY_PATH=/var/data/github-private.key \


  • STURDY_GITHUB_APP_ID — The "App ID" from GitHub (example: "170000")
  • STURDY_GITHUB_APP_CLIENT_ID — The "Client ID" from GitHub (example: "Iv1.36afeeee456ff123")
  • STURDY_GITHUB_APP_SECRET — Generate a new client secret from GitHub (example: "aaa655ad971xxxxxxxxxxxxxxxxxxxxxxxx88e4b")
  • STURDY_GITHUB_APP_PRIVATE_KEY_PATH — The path to the GitHub App private key. Note that this is the path from inside the container. Copy the file to $HOME/.sturdydata/github-private.key on the host (outside of Docker) and access the file as /var/data/github-private.key.

Congratulations! You are now ready to use Sturdy with GitHub integration.

ℹ️ To learn more about how to use GitHub integration, see How to setup Sturdy on GitHub

Next steps

For a getting started guide, refer to the Using Sturdy page.

Read more

Debugging your server

If you have a problem setting up Sturdy, please follow the troubleshooting guide below, or reach out on the Sturdy Discord for Community Support.

Trouble connecting

Make sure that the server is up and running, once the server has started it will print a message like

[api] The server is ready, open the Sturdy App to get started! 🐣

If you don't see this message, something might be wrong with the setup.

It's important to not run Sturdy behind a TLS or HTTPS proxy. Sturdy uses both HTTP(s) (for the GraphQL API) and SSH (for file transfers) on the same port, which many proxies can't handle, and will very likely interfere with the SSH connections.

To setup TLS with Sturdy set the SSL_CERT and SSL_KEY environment variables when running Sturdy (example).

Setup CORS

When running Sturdy on non-localhost, you need to configure the CORS-header. Set the STURDY_API_ALLOW_CORS_ORIGINS environment variable to the host that you're running Sturdy on (example:

Debug API connectivity

To validate API connectivity run the command below. The server will respond with a 200 OK if everything is is working as it should.

curl -v "https://your-server:443/api/readyz"

Debug syncer connectivity

To validate SSH connectivity run run the command below (replace 443 with the port number that Sturdy is running on). If everything is working, the server will print ping! before closing the connection

ssh ping@your-server -p 443


The published Docker image getsturdy/server contains Sturdy Enterprise, and is licensed under the Sturdy Enterprise License.