Technical detail

Run AI-built apps on the Kubernetes you already operate

Install Portainer-Run, point it at your Portainer Business instance and a Git repository, and your builders can deploy AI-generated apps with no Dockerfile, no registry, and no platform-engineering ticket. This page covers setup, the deployment flow, supported runtimes, and the technical detail behind it.

Before you start

What you need

Portainer-Run is a thin self-service layer on top of Portainer Business. It deploys nothing itself; it drives your Portainer instance, which drives your clusters.

Step 1

Install Portainer-Run on Kubernetes

Deploy it into your cluster using the Kubernetes manifest provided in the GitHub repository at deploy/kubernetes.yaml. Set your Portainer URL and an encryption key, apply it, and reach it over HTTPS.

# Set PORTAINER_URL and ENCRYPTION_KEY (and optionally an AI key)
# in the manifest's env or a Secret, then apply it:
kubectl apply -f deploy/kubernetes.yaml

PORTAINER_URL and ENCRYPTION_KEY are the only required values. The encryption key protects stored Git credentials at rest and must be at least 32 characters (generate one with openssl rand -hex 32). Add ANTHROPIC_API_KEY or OPENAI_API_KEY to enable the Assistant. On first start it generates a self-signed certificate, so your browser warns once; accept it, or provide real certificates with SSL_CERT and SSL_KEY. Expose the service the way your cluster does, NodePort, LoadBalancer, or Ingress, and open it over HTTPS.

Prefer Docker or Compose?

Portainer-Run also runs as a standalone container, and the Docker, Compose, and local development instructions are in the GitHub repository. That is only how you host Run itself. The apps it deploys always run on your Kubernetes clusters.

Step 2

Connect with a Portainer token

Portainer-Run has no user database of its own. Access is your Portainer RBAC, carried by a personal access token.

  1. Generate a token in Portainer

    In Portainer Business, go to Account, then Access Tokens, and create one. OAuth-only logins still generate a token here.

  2. Open Portainer-Run and paste it

    Navigate to https://your-host and enter the token. The environments and namespaces you can see and act on are exactly what your Portainer role grants. Admins additionally see Cluster Readiness and environment enable/disable controls.

Step 3

Configure a Git target

A Git target is an encrypted, stored connection to the repository Portainer-Run commits to. It is the system of record for every deployment.

Under Git Targets, add the provider (GitHub, GitLab, Gitea, or other), the repository in owner/repo form, a personal access token, a default branch, and an optional path prefix. Credentials are encrypted at rest with your encryption key. The Test button reports read and write access separately; a read-only token will fail at the commit step.

Step 4

Deploy an AI-built app with Vibe Deploy

Drop the files an AI tool produced. No Dockerfile, no image, no CI. Portainer-Run detects the runtime, installs dependencies, commits to Git, and lets Portainer deploy it.

  1. Provide the source

    Upload the folder of files directly, or point Portainer-Run at an existing repository with a target, branch, and optional subfolder.

  2. Choose where it runs

    Pick the environment, namespace, and Git target from the options your token can reach, and the exposure type. If a .env.example is present, its keys appear as an editable environment-variable list, with secret-looking keys masked.

  3. Deploy

    Portainer-Run commits and triggers the deployment. When it is live, the running status and access address (IP:port or FQDN) surface back to you.

Optional

Deploy from your AI tool with MCP

Builders who work inside Claude or another MCP-capable assistant can deploy without opening Portainer-Run at all. Run exposes an MCP server, and the same governed Git and GitOps pipeline runs underneath, scoped by your Portainer RBAC.

Prerequisite

Node.js must be installed on the developer's machine, since the connection runs through npx.

  1. Open the config

    In Claude Desktop, go to File, then Settings, then Developer, then Edit Config.

  2. Add the Portainer-Run MCP server

    Add the block below, pointing it at your Portainer-Run MCP endpoint and using a Portainer personal access token as the Bearer token. Your RBAC applies exactly as it does in the UI.

  3. Restart Claude Desktop

    The Portainer-Run tools become available. Ask Claude to deploy an app and it runs through the same pipeline as the UI: committed to Git, deployed as a GitOps stack, governed by your rules.

"mcpServers": {
  "portainer-run": {
    "command": "npx",
    "args": [
      "-y",
      "mcp-remote@latest",
      "https://<your-portainer-run-host>/mcp",
      "--header",
      "Authorization: Bearer <your-portainer-access-token>"
    ],
    "env": {
      "NODE_TLS_REJECT_UNAUTHORIZED": "0"
    }
  }
}

Under the hood

How Vibe Deploy works

Everything is committed to Git and reconciled by Portainer, so each deployment is governed and fully repeatable.

Runtime detection

Portainer-Run inspects the file structure and matches a runtime in priority order, first match wins. A package.json means Node.js, requirements.txt or .py means Python, .php means PHP, a Gemfile or .rb means Ruby. If everything is static assets it defaults to nginx.

Manifest and init containers

Portainer-Run generates a Kubernetes Deployment manifest for the detected runtime, with three init containers that run in sequence before the app starts:

Once the init containers complete, the main container starts against the pre-populated volume using a stock public runtime image. Git credentials are held in a Kubernetes Secret and injected by reference, so the token never appears in the pod spec.

GitOps commit and reconciliation

Source files are committed to {environment}/{namespace}/{app}/src/ and the manifest to {environment}/{namespace}/{app}.yaml, keeping environments and namespaces cleanly separated in one repo. Portainer-Run then calls the Portainer API to create a GitOps stack pointed at that manifest. Portainer polls the repository on a set interval (five minutes by default) and applies any change.

Updates

An update takes the same path. Drop the revised files, Portainer-Run commits the change, and Portainer reconciles it on the next poll. The PersistentVolume keeps its state across restarts, so uploaded files and anything the app wrote to disk survive the update.

Reference

Supported runtimes

Detection is automatic and runs in priority order. If nothing matches, Portainer-Run falls back to nginx.

package.json

Node.js 22

Start command from the start script, else node server.js / index.js / npm start.

Default port 3000
requirements.txt / .py

Python 3.12

Targets main.py, app.py, server.py, or run.py, else python app.py.

Default port 8000
.php

PHP 8.3

Served with Apache (php:8.3-apache).

Default port 80
Gemfile / .rb

Ruby 3.3

Rack apps use bundle exec rackup, else app.rb or server.rb.

Default port 9292
static assets

Static (nginx)

HTML, CSS, JS, images, and so on, on nginx:alpine. A single non-index.html file is renamed on commit.

Default port 80

Know before you go

Limitations

Reference

Key environment variables

VariableRequiredDescription
PORTAINER_URLYesFull URL of your Portainer instance, e.g. https://portainer.example.com:9443
ENCRYPTION_KEYYesEncrypts stored Git credentials. At least 32 characters. Generate with openssl rand -hex 32.
ANTHROPIC_API_KEYNoEnables the Assistant and AI triage using Claude.
OPENAI_API_KEYNoEnables the Assistant using GPT-4o. Set one provider, not both.
TEMPLATE_URLNoURL of a custom application catalogue JSON file.
SSL_CERT / SSL_KEYNoPaths to real TLS certificate and key. Self-signed is used if unset.
PORT / HTTP_PORTNoListen ports inside the container. Default 443 and 80.

Go deeper

Full documentation and source

The repository has the complete reference: the deployment form, the application catalogue and template format, the Assistant, the aggregated status architecture, and every environment variable.