Skip to main content
A Sinatra application runs on Sevalla as an application: Ingot, Sevalla’s builder, installs the gems from your Git repository with Bundler, finds the config.ru file, and starts the web process with Puma on the port that Sevalla sets in the PORT environment variable.

At a glance

Environment variables

The application reads no environment variables of its own. Sevalla sets PORT to the web process port, and Ingot sets RACK_ENV to production.

Before you begin

  • A Sevalla company with a payment method, and a GitHub, GitLab or Bitbucket account for the repository. See Git providers.
  • Ruby 4.0 on your computer.

Create the project

Create a folder with a Gemfile, then add Sinatra and Puma, the web server:
bundle add installs Sinatra 4.2 and Puma 8.0 and writes Gemfile.lock. Create the application as a class, so config.ru can run it:
app.rb
config.ru

Prepare the project for Sevalla

Ingot builds on Ruby 4.0, its default line, unless the project sets a version. Pin the line in the Gemfile, under the source line, so the build doesn’t change when a new Ingot release moves its default:
Gemfile
Then run bundle install to record the Ruby version in Gemfile.lock. See Pin the Ruby version. Ingot finds config.ru and Puma in Gemfile.lock, and starts the web process with bundle exec puma --bind "tcp://0.0.0.0:$PORT": Puma listens on all network interfaces and on the port in PORT, which Sevalla sets to the web process’s port (8080 by default). Ingot sets RACK_ENV=production, so Sinatra runs in production mode. Puma runs up to 5 threads in 1 process; on a larger size, set the WEB_CONCURRENCY environment variable to the number of processes, for example 2. The project needs no other configuration. Run bundle exec puma and open http://localhost:9292 to check the application locally. Then commit everything and push it to your Git provider:

Deploy to Sevalla

These steps build with Ingot. To build from your own Dockerfile instead, see Deploy with a Dockerfile.
1

Create the application

In the sidebar, click Applications, then click Create > Application. Under Source, click Private repository, then choose the Git provider, the Repository and the Branch. Under Location, choose a Data center. Keep the Size at H1 or choose a larger one, then click Create application. The application opens on its Overview tab with the status Not deployed yet: creating an application doesn’t deploy it.
2

Deploy

Click the Overview tab, then click Deploy now under Recent deployments. Check the Branch and click Deploy.
3

Turn on auto-deploy

To deploy every push to the branch automatically, click the Settings tab, then click Update auto-deploy in the Auto-deploy section. Turn on Auto-deploy and click Update auto-deploy. See Deployments.

Verify the deployment

  1. On the Deployments tab, click the deployment. Its Build log shows Ingot’s build plan: Ruby 4.0 from the Gemfile, Sinatra from Gemfile.lock, and the start command from config.ru.
    Build log
  2. Wait for the deployment’s status to change to Deployed. The application’s status next to its name changes to Running.
  3. Click the domain under the application’s name, for example storefront-x7k2m.sevalla.app. The page shows Hello from Sinatra on Sevalla.
The application header with its name, Running status, repository, branch and the domain that opens the applicationThe application header with its name, Running status, repository, branch and the domain that opens the application
If the deployment fails, read its build log, then see Troubleshoot Ingot builds. If it deploys but the domain doesn’t respond, read the application’s runtime logs: Puma prints Listening on with the address it binds.

Check from a terminal

These checks need no dashboard. The API calls use API, H, APP_ID and DEPLOYMENT_ID as set in Deploy with the API.
  1. The deployment’s status, from Get deployment (getDeploymentV3):
  2. Puma’s start, from Get application runtime logs (getApplicationRuntimeLogsV3), which searches the last hour by default:
  3. The application, with your domain:

Deploy with a Dockerfile

Ingot needs no Dockerfile. Use one when you want full control of the image: the base image, the system packages and every layer. Puma reads its settings from config/puma.rb, so first make it listen on PORT there, with Puma’s own default for your computer:
config/puma.rb
Then add a Dockerfile and a .dockerignore to the root of the repository:
Dockerfile
.dockerignore
Commit and push the three files. Ingot doesn’t use the Dockerfile, and it applies the .dockerignore patterns to its own build, so the repository still builds with Ingot. Then switch the application to the Dockerfile build strategy:
1

Choose the Dockerfile build strategy

On the application’s Settings tab, in the Build strategy section, click Update build strategy. Click Dockerfile, keep the Dockerfile path Dockerfile and the Docker context ., then click Update build strategy.
2

Deploy

Click the Overview tab, then click Deploy now under Recent deployments. Check the Branch and click Deploy.
The build log shows 📦 Building and pushing docker image using Dockerfile... instead of Ingot’s build plan. The application’s domain shows Hello from Sinatra on Sevalla, and the deployment’s Dockerfile tab shows the file the image was built from. See Dockerfile.

Deploy changes

With Auto-deploy on, every push to the branch starts a deployment; otherwise, click Deploy now for each change. Each deployment builds the image, then replaces the web process’s instances. When you add a gem with bundle add, commit Gemfile.lock with it. See Deployments.

Use environment variables

Read settings with ENV.fetch("NAME"), for example an API key or a database URL. Add them on the application’s Environment variables tab: they apply at the next deployment. To connect a Sevalla database, add an internal connection with Add environment variables to the application turned on, and read DB_URL or REDIS_URL. See Environment variables.

Add a custom domain

To serve the application from your own domain, such as shop.example.com, add the domain on the application’s Domains tab and create the DNS records that Sevalla shows. Custom domains need a web process larger than H1, so scale the web process first. See Custom domains.

Deploy with the API

The same deployment as Deploy to Sevalla, as calls to the Sevalla API that a script or an AI agent runs in order. Each step names the matching CLI command and Sevalla MCP server tool. The sequence needs:
  • An API key with the Company developer role, or the capabilities to create, read and update applications, in SEVALLA_API_KEY.
  • The repository pushed to GitHub, and a GitHub account with access to it connected to Sevalla. Connecting one is a dashboard step, and the API has no call that reports it: if no connected account can read the repository, the step that creates the application fails with 400 and a message that starts with Cannot access repository and says where to connect one.
  • curl and jq.
Set the base URL, the authorization header and the repository:
1

Choose the location

List clusters (listClustersV3) returns every location your company can use, with its region ID in location. Pick one by region ID, here Frankfurt, Germany (eu-frankfurt-1); Locations lists the others. Display names differ between environments, so don’t select by them:
CLI: sevalla resources clusters. MCP: get_platform_options.
2

Look up the size

List process resource types (listProcessResourceTypesV3) gives the ID of H1:
CLI: sevalla resources process-types. MCP: get_platform_options.
3

Create the application

Create application (createApplicationV3) creates it with a web process and doesn’t deploy it. List application domains (listApplicationDomainsV3) returns its sevalla.app domain as the primary one, for the checks:
Sevalla adds the domain about 2 seconds after it creates the application, so the loop waits for it.CLI: sevalla apps create --name storefront --cluster $CLUSTER_ID --source privateGit --git-type github --repository $REPO_URL --branch $BRANCH, then sevalla apps domains list --app-id $APP_ID. MCP: create_application with deploy: false, then get_application.
4

Size the web process

The API creates the web process at S1, not the dashboard’s H1. List processes (listProcessesV3) finds it, and Update process (updateProcessV3) sets H1:
CLI: sevalla apps processes update $WEB_ID --app-id $APP_ID --resource-type $H1_ID. MCP: scale_process with size_id and apply_now: false.
5

Deploy

Trigger deployment (triggerDeploymentV3):
CLI: sevalla apps deployments trigger $APP_ID --branch $BRANCH. MCP: trigger_deployment.
6

Wait for the deployment

Poll Get deployment (getDeploymentV3) until the status is final: success, failed, cancelled or skipped. The loop keeps polling through a failed request and stops after 30 minutes:
On failed, read the build log with Get application deployment logs and see Troubleshoot Ingot builds. CLI: sevalla apps deployments get $DEPLOYMENT_ID --app-id $APP_ID and sevalla apps deployments logs $DEPLOYMENT_ID --app-id $APP_ID. MCP: get_deployment and get_deployment_logs.
7

Turn on auto-deploy

Update application (updateApplicationV3):
To build from the Dockerfile instead of Ingot, send {"build_type": "dockerfile", "dockerfile_path": "Dockerfile", "docker_context": "."} with the same call before you deploy. CLI: sevalla apps update $APP_ID --data '{"auto_deploy": true}'. MCP: sevalla_api_update with updateApplicationV3 and the same body.
Then run the checks in Check from a terminal, with https://$APP_HOST as the domain.