A clean, step-by-step guide to install Marzban on Ubuntu 22.04 with Docker, Nginx, SSL, VLESS, and VMess — without the common mistakes that break most setups.
Table of Contents
Most Marzban installs don’t fail because of complexity. They fail because of wrong setup order.
I’ve worked on multiple VPS fixes where:
- Panel loads but keeps spinning
- VLESS shows timeout
- VMess configs don’t connect
- Ports are exposed incorrectly
- Client links are broken
The problem is not Marzban. It’s the way it’s installed.
This guide shows you how to install Marzban properly from the start so you don’t have to debug it later. It’s based on real fixes, not theory.
Tested only on Ubuntu 22.04.
What You’ll Get After This Setup
By the end, you’ll have:
- Working Marzban panel (no loading issues)
- Proper HTTPS setup with SSL
- VLESS + VMess over WebSocket
- Clean domain-based configs (no IP problems)
- Production-ready Nginx configuration
Requirements
Before starting:
- Ubuntu 22.04 VPS
- Domain pointing to your server IP
- Root or sudo access
Prepare the Server
Run:
apt update && apt upgrade -y
apt install -y curl git nginx certbot python3-certbot-nginx docker.io docker-compose
systemctl enable docker
systemctl start docker
This sets up everything Marzban depends on.
Install Marzban
mkdir -p /opt/marzban
cd /opt/marzban
git clone https://github.com/Gozargah/Marzban.git .
cp .env.example .env
Edit config:
nano .env
Add these lines immediately after the line that says UVICORN_PORT = 8000 near top of the file.
XRAY_SUBSCRIPTION_URL_PREFIX = "https://yourdomain.com"
XRAY_VLESS_WS=true
XRAY_VLESS_WS_PATH=/vless
XRAY_VLESS_WS_HOST=yourdomain.com
Avoid over-configuring here. Most issues start in this file.
Start the service:
docker-compose up -d
Create Admin User
docker exec -it marzban_marzban_1 python3 /code/marzban-cli.py admin create
Follow onscreen instructions to create the admin user. You’ll need admin user to login to Marzban dashboard later.

Configure Nginx (Where Most People Mess Up)
nano /etc/nginx/sites-available/marzban
Paste:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /vless {
proxy_pass http://127.0.0.1:10000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
location /vmess {
proxy_pass http://127.0.0.1:10001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
}
Enable it:
ln -s /etc/nginx/sites-available/marzban /etc/nginx/sites-enabled/
nginx -t
systemctl restart nginx
Enable SSL
certbot --nginx -d yourdomain.com
Choose redirect → YES
Configure Core (Critical Step)
Login:
https://yourdomain.com/dashboard/
Go to Core Settings, delete everything and add:
{
"log": {
"loglevel": "warning"
},
"routing": {
"rules": [
{
"ip": [
"geoip:private"
],
"outboundTag": "BLOCK",
"type": "field"
}
]
},
"inbounds": [
{
"tag": "Shadowsocks TCP",
"listen": "0.0.0.0",
"port": 1080,
"protocol": "shadowsocks",
"settings": {
"clients": [],
"network": "tcp,udp"
}
},
{
"tag": "VLESS WS",
"listen": "127.0.0.1",
"port": 10000,
"protocol": "vless",
"settings": {
"clients": [],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/vless"
}
}
},
{
"tag": "VMess WS",
"listen": "127.0.0.1",
"port": 10001,
"protocol": "vmess",
"settings": {
"clients": []
},
"streamSettings": {
"network": "ws",
"security": "none",
"wsSettings": {
"path": "/vmess"
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "DIRECT"
},
{
"protocol": "blackhole",
"tag": "BLOCK"
}
]
}
Refresh the dashboard.
Host Settings (This Fixes Client Configs)
Common settings for VLESS and VMESS:
Since the data is routed through nginx, we should use port 443. The Nginx configuration we added earlier will handle both VLESS and VMESS correctly based on the path you set here. So everything except Path setting should be identical here.
- Address: yourdomain.com
- Port: 443
- SNI: yourdomain.com
- Request Host: yourdomain.com
- Security Layer: TLS
And for the path setting, type /vless for VLESS and /vmess for VMESS.

Create a User
Refresh the Marzban dashboard one more time and it should be ready to accept new users.

Why Most Installations Fail
From real VPS fixes, the common mistakes are:
- Using IP instead of domain
- Skipping Host Settings
- Wrong WebSocket path
- Opening internal ports publicly
- Over-editing .env
- Incorrect Nginx routing
Avoid these, and Marzban works smoothly.
🔧 Don’t Want to Deal With This?
If you’d rather skip the setup and just have it working:
I fix real VPS issues daily, including:
- Broken Marzban installs
- Nginx misconfigurations
- SSL / DNS issues
- Performance tuning
Conclusion
Marzban isn’t hard to install. What matters is doing it in the right order.
Set up Docker → configure Nginx → enable SSL → then configure WebSocket properly.
Do that, and everything just works.
