[metadata]
viewport: width=device-width, initial-scale=1.0

[document-links]
API tokens: /dashboard#tokens
Billing: /billing
Dashboard: /dashboard
Developer API docs: /docs/api
Distribute: /
Explore: /explore
Home: /
MCP server: /docs/api#mcp
REST API: /docs/api

[content]
Documentation · Distribute
Distribute Docs
v3.0 · Self-hosted platform
Getting Started
Introduction
Installation
Authentication
Deploying
Deploy Apps
.distributeignore
App Lifecycle
Automation
Pipelines (CI/CD)
Functions
API Gateway
Tunnels
HTTP Tunnel
TCP/TLS Tunnel
Features
Terminal
PWA Builder
Custom Domains
Reference
CLI Reference
Troubleshooting
Programmatic
REST API
MCP server
API tokens
Open Dashboard
Distribute
›
Documentation
Documentation
Everything you need to deploy apps, expose local servers, manage infrastructure, and ship PWAs · from your terminal.
Quick start
v1.0
Install the CLI, log in once, and deploy from any project folder. The platform handles containerization, SSL, and routing automatically.
Copy
$
curl -fsSL https://distribute.app/install.sh | sh
$
distribute login
$
distribute .
What's included
✓ Deploy any stack
✓ HTTP / TCP / TLS tunnels
✓ Browser terminal
✓ PWA builder
✓ Custom domains + SSL
✓ Start / stop / restart
✓ Admin panel
Introduction
Distribute is a self-hosted application deployment platform. You run it on your own server; your team uses the CLI or web dashboard to deploy, manage, and debug apps. It uses Docker for containerization and built-in reverse proxy for routing and SSL.
There are four main workflows:
Deploy
· package a local folder and deploy it as a Docker container with a public URL and SSL certificate.
Tunnel
· expose a local server (running on your laptop) to the internet via a secure public URL, without deploying it. Works for HTTP apps, databases, and any TCP/TLS service.
Terminal
· open a browser-based shell inside any deployed container to run commands, debug, or inspect logs.
PWA Builder
· analyze any deployed web app and generate a PWA package (manifest, service worker, icons) plus Android and iOS builds.
Building on Distribute? Use the API.
The CLI shown on this page is one client of the public REST API. If you're scripting deployments from CI, integrating with Claude Desktop / Cursor via MCP, or building your own SDK, see the
Developer API docs
for the
/api/v1/*
endpoints, scoped Bearer tokens, and the zero-dependency MCP server.
Installation
macOS / Linux
Copy
$
curl -fsSL https://distribute.app/install.sh | sh
The installer detects your OS, downloads the latest CLI from your Distribute server, installs it to
/usr/local/bin/distribute
, and saves your server URL to
~/.distribute/config.json
.
Manual install
# Download CLI directly
$
curl -fsSL https://distribute.app/cli/distribute -o distribute
$
chmod +x distribute && sudo mv distribute /usr/local/bin/
Requires:
Python 3.8+, curl. The CLI is a single Python script with no external dependencies beyond the standard library and
requests
.
Authentication
Copy
$
distribute login
Running
distribute login
opens a browser window to your Distribute server. After signing in with Google, GitHub, or username/password, the tab closes automatically and the CLI stores a Bearer token in
~/.distribute/config.json
.
The token is persisted on the server across restarts · you only need to log in once.
Token security:
Your token is stored locally at
~/.distribute/config.json
. Keep this file private. To revoke access, delete the token from your dashboard under Account Settings.
Deploying Apps
Interactive deploy
Run
distribute .
from your project folder. The CLI connects to the server, lists your existing apps, and lets you redeploy one or create a new deployment.
Copy
$
distribute .
Connected. 3 app(s) deployed.
1. ● my-api
2. ● storefront
3. + Deploy as new app
Select [1-3]:
Deploy with a specific name (skips picker)
$
distribute . --name my-awesome-api
Supported stacks (auto-detected)
Docker Compose, Node.js, Python/Flask/Django, PHP, React, Vue, Angular, Next.js, Vite, Static HTML. If a
docker-compose.yml
or
Dockerfile
is present it takes precedence.
.distributeignore
Create a
.distributeignore
file in your project root to exclude files and directories from packaging. One pattern per line. Reduces upload size significantly.
# .distributeignore
node_modules
.next
dist
public/videos
.env.local
*.log
coverage
The CLI also automatically skips:
node_modules
.git
__pycache__
.next
.nuxt
venv
android
ios
Pods
and files over 50 MB.
App Lifecycle
Each deployed app can be started, stopped, restarted, or deleted from the dashboard. These actions control the underlying Docker container directly.
Action
Effect
Start
Starts the Docker container. built-in reverse proxy begins routing traffic to it.
Stop
Stops the container. built-in reverse proxy stops routing · no traffic reaches the app.
Restart
Restarts the container in place. Brief interruption (~1-2s).
Delete
Removes the container and all app metadata. Cannot be undone.
Domain uniqueness:
No two apps can share the same custom domain. Attempting to configure a domain already used by another app returns a 409 error.
HTTP Tunnel
Expose a local HTTP server to the internet. Useful for sharing dev builds, testing webhooks, or demoing to clients without deploying.
Copy
$
distribute http 3000
Tunnel open
────────────────────────────────────────────
Public URL → https://distribute.app/t/a3f82c1b
Forwarding → localhost:3000
Press Ctrl+C to stop
GET / → 200
POST /api/login → 201
How it works
The CLI opens a persistent long-polling connection to the server. Incoming HTTP requests to your public URL are forwarded to the CLI, which makes the request locally and returns the response. The server rewrites HTML responses to fix asset paths,
fetch()
calls, and redirects so that SPAs work correctly end-to-end.
Framework compatibility
Framework
Notes
React CRA
Works. Static assets rewritten automatically.
Vite (React/Vue)
Works.
/assets/
paths rewritten.
Angular
Works.
<base href>
injected, absolute paths rewritten.
Next.js
Works.
/_next/
paths rewritten.
Vue CLI
Works. Static assets rewritten.
Any HTML server
Works. Plain HTTP proxied as-is.
HMR / live reload:
WebSocket-based hot module reload is neutralized (replaced with a no-op) because it cannot be proxied through HTTP polling. Pages load correctly · they just won't auto-reload on file changes.
Tunnels auto-expire after 1 hour. Ctrl+C closes the tunnel immediately.
TCP / TLS Tunnel
Expose any raw TCP or TLS service · databases, SSH, message brokers · via a public HTTP-based proxy. The tunnel bridges raw byte streams over HTTP polling.
TCP (plain)
# PostgreSQL
$
distribute tcp 5432
TCP Tunnel open
Public URL → https://distribute.app/tcp/f1c90a22
Forwarding → localhost:5432
↔ Connection c3a8b1f0 opened → localhost:5432
TLS (SSL-wrapped)
# HTTPS local server
$
distribute tls 8443
TLS Tunnel open
Public URL → https://distribute.app/tcp/9d2e4b1a
Forwarding → localhost:8443 (TLS wrapped)
Common use cases
Command
Service
distribute tcp 5432
PostgreSQL
distribute tcp 3306
MySQL / MariaDB
distribute tcp 6379
Redis
distribute tcp 27017
MongoDB
distribute tcp 22
SSH
distribute tls 8443
Local HTTPS server
distribute tls 5671
AMQPS (RabbitMQ)
distribute tls 8883
MQTTS (MQTT broker)
Browser Terminal
Every deployed app has a built-in terminal accessible from the dashboard. Click the
>_
button on any app card to open a shell inside that container.
✓ Connected to distribute-my-api
$
python manage.py migrate
Applying sessions.0001_initial... OK
$
cat .env | grep DATABASE
DATABASE_URL=postgres://...
$
pip install psycopg2-binary
Successfully installed psycopg2-binary-2.9.9
The terminal starts in the app's working directory (typically
/app
). It uses HTTP polling so it works reliably behind proxies, CDNs, and restrictive firewalls · no WebSocket required.
Press
Ctrl+C
to interrupt a running process. Close the modal to end the session.
PWA Builder
Navigate to
Dashboard → PWA Builder
and paste the URL of any web app. Distribute analyzes the site and generates a complete PWA package in seconds.
What gets generated
Output
Description
manifest.json
Web App Manifest with name, icons, theme color, display mode
sw.js
Service worker with offline-first cache strategy
Icons (6 sizes)
192×192, 512×512, Apple touch icons, favicon
Android APK
Installable APK for sideloading on Android devices
iOS project
Capacitor project ready for Xcode build and App Store submission
The builder auto-detects the framework (React, Vue, Angular, Next.js, plain HTML) and adjusts the service worker caching strategy accordingly.
Custom Domains
Each app can have one or more custom domains. Add them from the dashboard by clicking
Domains
on any app card.
DNS setup
Point your domain to your server with an A record:
# In your DNS provider
myapp.com A → YOUR_SERVER_IP
www.myapp.com CNAME → myapp.com
SSL is issued automatically via Let's Encrypt TLS-ALPN-01 challenge. No port 80 required. Certificate issuance typically completes within 2 minutes of DNS propagation.
Domain uniqueness:
Each domain can only be assigned to one app. Attempting to use a domain already assigned elsewhere returns an error. Contact an admin to reassign.
CLI Reference
Command
Description
distribute login
Authenticate via browser (device flow). Stores token locally.
distribute .
Package current directory, pick app interactively, deploy.
distribute . --name <n>
Deploy current directory with a specific app name (skips picker).
distribute /path
Package and deploy a specific directory.
distribute http <port>
Open an HTTP tunnel to localhost:<port>.
distribute tcp <port>
Open a TCP tunnel (databases, SSH, etc.).
distribute tls <port>
Open a TLS tunnel (SSL-wrapped services).
distribute ls
List your deployed apps with status.
distribute logs <app>
Tail container logs.
distribute delete <app>
Delete an app and its container.
distribute open <app>
Open the app URL in your browser.
Config file
Stored at
~/.distribute/config.json
:
{
"base_url": "https://distribute.app",
"token": "your-auth-token",
"username": "acme_corp"
}
Pipelines (CI/CD)
Pipelines auto-deploy your app on every git push. Connect your repository from the Pipelines panel or the CLI and choose a branch trigger.
Connect via dashboard
Go to
Pipelines
in the sidebar, click
Connect a provider
, authorize GitHub/GitLab/Bitbucket, then click
Deploy
or
Link to app
next to a repository.
A webhook is automatically created on the repository. No manual configuration needed.
Deploy from a repo (CLI)
distribute repo owner/myproject distribute repo owner/myproject --name my-api distribute repo owner/myproject --trigger main
Link an existing app to a repo (CLI)
distribute pipeline my-api link owner/myproject distribute pipeline my-api link owner/myproject --trigger main distribute pipeline my-api link owner/myproject --trigger any
Trigger options
Value
Behaviour
manual
Only via dashboard button or
distribute pipeline <app> trigger
main
Auto-deploy on push to
main
master
Auto-deploy on push to
master
any
Auto-deploy on push to any branch
Pipeline commands (CLI)
distribute pipeline my-api # show status + recent builds distribute pipeline my-api trigger # trigger manual build distribute pipeline my-api link o/repo # link to repo distribute pipeline my-api unlink # remove pipeline
Build flow
Each build:
git clone --depth=1
→
docker build
(no cache) → image tagged with commit SHA → old container replaced → new container started with same built-in reverse proxy labels. No downtime for built-in reverse proxy routing.
Functions (Serverless)
Functions let you deploy lightweight event-driven code without managing containers. Each function runs in isolation and is invoked via HTTP.
Create a function
Go to
Functions
in the sidebar and click
New function
. Write your handler code in the editor. Functions support Python and Node.js.
Invoke a function
POST https://distribute.app/function/<name> Content-Type: application/json {"key": "value"}
CLI commands
distribute fn ls # list functions distribute fn logs my-fn # view logs distribute fn invoke my-fn # invoke (empty payload) distribute fn invoke my-fn --data '{"user": "alice"}'
Expose a function as an API endpoint
Go to
APIs
and click
New endpoint
. Select type
Function
, pick your function, configure auth and the public URL. The endpoint will appear in the endpoints list.
API Gateway
The API Gateway lets you register, document and secure your deployed apps and functions as named API endpoints. Each endpoint can have rate limiting, API key auth and a custom URL.
Create an endpoint
Go to
APIs
and click
New endpoint
. Choose a type:
Type
Use case
App
Expose a deployed Docker app
Function
Expose a serverless function
External
Proxy to an external URL or internal service
Set a custom endpoint name, choose a domain (subdomain or custom domain) and optional path prefix. Auth can be set to Public or API key required.
API Keys
Generate named API keys from the
APIs
panel or via CLI. Keys are shown once on creation.
distribute api keys # list keys distribute api key create mobile-app # generate new key distribute api key delete <id> # delete key
Rate limiting
Click
Configure
on any endpoint to set requests-per-second and burst limits. Rate limiting is enforced by built-in reverse proxy and applied immediately.
CLI commands
distribute api ls # list your endpoints
Environment Variables
Manage environment variables for your apps from the CLI or dashboard (Applications → app card → Settings).
distribute env my-api set DATABASE_URL=postgres://... SECRET=abc distribute env my-api ls
Variables are injected into the container at runtime. The app will restart automatically after an update.
Troubleshooting
SSL certificate error on upload
✗ SSLError: certificate verify failed
# Fix:
$
pip3 install --upgrade certifi
Upload fails with SSL EOF
✗ SSLEOFError: EOF occurred in violation of protocol
# Caused by large package or slow upload. The CLI uses curl
# automatically. If curl is missing, install it:
$
brew install curl # macOS
# Then reduce package size with .distributeignore
Tunnel assets return 404 (Angular/React)
This happens when the app uses absolute paths like
/styles.css
which don't include the tunnel prefix. The CLI server rewrites HTML automatically, but if you see 404s on assets try adding a
<base href="/">
tag explicitly in your
index.html
· the tunnel proxy will replace it with the correct prefix.
Command not found
distribute: command not found
# Fix:
$
export PATH="/usr/local/bin:$PATH"
$
source ~/.zshrc # or ~/.bashrc
Already logged in but CLI says "not logged in"
The server was restarted and a previous version lost the in-memory token. Since v1.0 tokens are persisted to disk · after a fresh deploy this should not occur. If it does, simply run
distribute login
again.
Crafted with Intention · Distribute Platform
Home
Billing
Explore
Dashboard
