App Deployment
Vibora includes a complete deployment platform for running your applications on your own infrastructure. Deploy Docker Compose projects with automatic domain routing, DNS configuration, and real-time build logs.
Why Self-Hosted Deployment?
Full control. Your code runs on your hardware. No vendor lock-in, no surprise bills, no wondering where your data lives.
- Open source — The entire platform is open source. Inspect, modify, and contribute.
- Your infrastructure — Deploy to any server you control. A $5/month VPS, a dedicated server, or your home lab.
- Complete lifecycle — From development in isolated worktrees to production deployment, all from one tool.
- Docker Compose — Use standard Docker Compose files. No proprietary configuration.
How It Works
- Add a repository with a
docker-compose.ymlfile - Create an app from the repository
- Configure domains for services you want to expose
- Deploy — Vibora builds and runs your containers
Vibora uses Traefik as a reverse proxy to route traffic to your containers based on domain names. If you have a Cloudflare API token configured, DNS records are created automatically.
Prerequisites
Before deploying apps, you need:
- Docker — Running on your server
- Traefik — Vibora can start its own Traefik container, or use an existing one (e.g., from Dokploy)
- A domain — For exposing services (optional for local-only deployments)
- Cloudflare API token — For automatic DNS configuration or tunnel access (optional)
Check your setup:
vibora doctorCreating an App
From the UI
- Navigate to Apps in the sidebar
- Click New App
- Select a repository
- Enter an app name
- Click Create App
The app is created but not yet deployed. You'll see the app's detail page where you can configure domains and environment variables.
What Gets Created
- App record — Stored in Vibora's database
- Services — Parsed from your
docker-compose.yml - No containers yet — Containers are only created when you deploy
Configuring Services
Each service from your Compose file appears in the app's settings. For each service, you can configure:
Domain
Enter a domain to expose the service to the internet:
myapp.example.comRequirements:
- The service must have a port mapping in the Compose file (e.g.,
ports: ["3000:3000"])
When setting a domain, choose an exposure method:
- DNS — Direct traffic to your server (requires public IP)
- Tunnel — Route through Cloudflare (works behind NAT)
See Domain Configuration for details on each method.
Port Mapping
Ports are read from your Compose file. If a service doesn't have a port mapping, you cannot expose it.
# In your docker-compose.yml
services:
web:
build: .
ports:
- "3000:3000" # Required for exposureEdit your Compose file to add or modify port mappings. Changes sync automatically when you save.
Environment Variables
Set environment variables that are available during build and runtime:
DATABASE_URL=postgres://user:pass@db:5432/myapp
API_KEY=your-secret-key
# Comments are supportedEnvironment variables are:
- Available during
docker compose build - Available inside your containers at runtime
- Stored encrypted in Vibora's database
Deploying
Click Deploy to start a deployment. You'll see real-time progress:
- Pulling — Fetches latest code from the repository
- Building — Runs
docker compose build - Starting — Runs
docker compose up - Configuring — Sets up Traefik routing and DNS
Build Options
- No-cache — Force a fresh build without Docker cache
- Autodeploy — Automatically deploy when commits or merges land on the repository's default branch
- Notifications — Get notified when deployments complete
Deployment History
View the last 10 deployments with their status and build logs. Click any deployment to see the full log output.
Domain Configuration
Vibora supports two methods for exposing services to the internet:
Exposure Methods
When configuring a domain for a service, you can choose between:
| Method | How it works | Best for |
|---|---|---|
| DNS | Creates an A record pointing to your server's public IP. Traffic goes directly to your server. | Servers with public IPs, full control over traffic |
| Tunnel | Creates a Cloudflare Tunnel. Traffic routes through Cloudflare's network without exposing your server's IP. | Home labs, servers behind NAT, enhanced security |
DNS Method
With the DNS method:
- An A record is created pointing your domain to your server's IP
- Traffic flows directly from the internet to your server
- Traefik handles routing and HTTPS
Requirements:
- Your server must have a public IP address
- Port 80/443 must be accessible
Tunnel Method
With the Tunnel method:
- Vibora creates a Cloudflare Tunnel for your app
- A
cloudflaredcontainer runs alongside your app - Traffic routes through Cloudflare's network to your containers
- A CNAME record points to the tunnel
Benefits:
- No public IP required — Works behind NAT, firewalls, or on home networks
- No exposed ports — Your server doesn't need ports 80/443 open
- DDoS protection — Traffic is filtered by Cloudflare
- Hidden origin IP — Your server's IP is never exposed
Cloudflare Setup
To use automatic DNS or tunnels, configure your Cloudflare credentials:
- Go to Settings > Deployment
- Enter your Cloudflare API token
- For tunnels, also enter your Cloudflare Account ID
API Token Permissions
Create a token with these permissions:
| Scope | Permission | Access |
|---|---|---|
| Account | Cloudflare Tunnel | Edit |
| Zone | SSL and Certificates | Edit |
| Zone | DNS | Edit |
To create a token:
- Go to Cloudflare API Tokens
- Click Create Token
- Select Create Custom Token
- Add the three permissions listed above
- Set zone resources to your domain (or "All zones" for convenience)
Your Account ID is visible in the Cloudflare dashboard URL or on the right sidebar of any zone's overview page.
Manual DNS
Without Cloudflare integration, create DNS records manually. Point your domain to your server's public IP:
myapp.example.com. A 203.0.113.42HTTPS Certificates
Traefik automatically provisions Let's Encrypt certificates for DNS-exposed domains. Tunnel-exposed services get HTTPS automatically through Cloudflare.
Stopping and Deleting
Stop
Click Stop to stop all containers without deleting the app. You can deploy again later.
Delete
Click Delete to:
- Stop all containers
- Remove the Docker stack
- Delete Traefik configuration
- Remove the app from Vibora
The repository and source code are not affected.
Architecture
Docker Swarm
Vibora deploys apps using Docker Swarm mode. This provides:
- Service orchestration
- Automatic container restart
- Rolling updates
- Network isolation
Each app runs as a Docker stack with its own overlay network.
Traefik Integration
Traefik is configured via file providers. For each exposed service, Vibora creates a YAML configuration file:
http:
routers:
myapp-web:
rule: "Host(`myapp.example.com`)"
service: myapp-web
tls:
certResolver: letsencrypt
services:
myapp-web:
loadBalancer:
servers:
- url: "http://myapp_web:3000"Network Architecture
Internet
│
▼
Traefik (reverse proxy)
│
├── myapp-network ──► myapp_web:3000
│
└── otherapp-network ──► otherapp_api:8080Each app gets its own Docker network. Traefik connects to all app networks to route traffic.
Troubleshooting
Build Fails
Check the deployment logs for error messages. Common issues:
- Missing dependencies in Dockerfile
- Invalid Compose syntax
Port Conflicts
If a container fails to start with "port already in use" or "bind: address already in use":
Find what's using the port:
bashsudo lsof -i :3000 # or sudo ss -tlnp | grep 3000Common conflicts:
- Another app deployed with the same host port
- A service running directly on the host (Node dev server, database, etc.)
- A previous deployment that didn't stop cleanly
Solutions:
- Change the host port in your Compose file:
"3001:3000"instead of"3000:3000" - Stop the conflicting service
- Use only container ports without host binding when exposing via Traefik (Traefik routes traffic through Docker networks, not host ports)
- Change the host port in your Compose file:
Tip: When exposing services through Traefik, you don't need host port mappings. Instead of ports: ["3000:3000"], you can use expose: ["3000"] to only expose the port to other containers on the same network.
Service Not Accessible
- Check that the domain is configured in the app
- Verify DNS points to your server:
dig myapp.example.com - Check Traefik logs:
docker logs traefik - Verify the container is running:
docker ps
DNS Not Created
- Verify your Cloudflare API token is set in Settings
- Check that the token has Zone → DNS → Edit permission
- Look for errors in the deployment log
Tunnel Not Working
- Verify both API token and Account ID are set in Settings
- Check that the token has Account → Cloudflare Tunnel → Edit permission
- Look for the
cloudflaredcontainer indocker ps - Check tunnel status in the Cloudflare Zero Trust dashboard
