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 setsPORT 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 aGemfile, 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 theGemfile, under the source line, so the build doesn’t change when a new Ingot release moves its default:
Gemfile
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
-
On the Deployments tab, click the deployment. Its Build log shows Ingot’s build plan: Ruby 4.0 from the
Gemfile, Sinatra fromGemfile.lock, and the start command fromconfig.ru.Build log - Wait for the deployment’s status to change to Deployed. The application’s status next to its name changes to Running.
-
Click the domain under the application’s name, for example
storefront-x7k2m.sevalla.app. The page showsHello from Sinatra on Sevalla.


Listening on with the address it binds.
Check from a terminal
These checks need no dashboard. The API calls useAPI, H, APP_ID and DEPLOYMENT_ID as set in Deploy with the API.
-
The deployment’s status, from Get deployment (
getDeploymentV3): -
Puma’s start, from Get application runtime logs (
getApplicationRuntimeLogsV3), which searches the last hour by default: -
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 fromconfig/puma.rb, so first make it listen on PORT there, with Puma’s own default for your computer:
config/puma.rb
Dockerfile and a .dockerignore to the root of the repository:
Dockerfile
.dockerignore
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.
📦 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 withbundle add, commit Gemfile.lock with it. See Deployments.
Use environment variables
Read settings withENV.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 asshop.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
400and a message that starts withCannot access repositoryand says where to connect one. curlandjq.
1
Choose the location
List clusters (CLI:
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:sevalla resources clusters. MCP: get_platform_options.2
Look up the size
List process resource types (CLI:
listProcessResourceTypesV3) gives the ID of H1:sevalla resources process-types. MCP: get_platform_options.3
Create the application
Create application (Sevalla adds the domain about 2 seconds after it creates the application, so the loop waits for it.CLI:
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 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 (CLI:
listProcessesV3) finds it, and Update process (updateProcessV3) sets H1: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 (CLI:
triggerDeploymentV3):sevalla apps deployments trigger $APP_ID --branch $BRANCH. MCP: trigger_deployment.6
Wait for the deployment
Poll Get deployment (On
getDeploymentV3) until the status is final: success, failed, cancelled or skipped. The loop keeps polling through a failed request and stops after 30 minutes: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 (To build from the Dockerfile instead of Ingot, send
updateApplicationV3):{"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.https://$APP_HOST as the domain.