Run Your Own Node

Deploy a flebop node on your own server. Full control over your data, your users, and your corner of the federation.

⚠️

Early test version. flebop is in active development. Bugs, rough edges, and breaking changes between releases are expected. Federation in particular is still stabilising — take backups and don't rely on this for anything critical yet. Feedback and bug reports are very welcome.

⚠️

Source code not currently available. I got eager and pushed a preview release before it was ready. It's been pulled — there are some significant bugs that need fixing first. The self-hosting guide below is kept for reference but won't work until the repository is re-released. See the roadmap for the current status.

Quickest path. The setup script handles configuration, keypair generation, and starting all services. You just need Docker and a domain pointing at your server.

Prerequisites

Server

A VPS or dedicated server running Linux. 1 GB RAM minimum, 2 GB recommended.

Domain

A domain or subdomain with DNS pointing at your server. Required for TLS and federation.

Docker

Docker Engine with the Compose plugin (v2). Install via docs.docker.com.

Reverse Proxy

nginx or Caddy on the host for TLS termination. The containers only listen on port 80.

Janus WebRTC

Required for voice and video channels. Run your own instance or leave JANUS_URL unset to disable voice/video.

1. Get the Code

The public repository is temporarily unavailable. This guide will be updated with installation instructions when the source is re-released.

2. Run the Setup Script

The setup script walks you through configuration, generates your node keypair, writes a .env file, and starts everything in Docker.

chmod +x setup.sh ./setup.sh

You will be prompted for:

The script generates an ECDSA P-256 keypair and saves it to ./node.key (chmod 600). It is mounted read-only into the containers. Keep this file safe — it authenticates your node to the rest of the federation.

Keep node.key secret. Never commit it to git or copy it to a world-readable location. If it is compromised, regenerate it with docker compose exec gunicorn python manage.py generate_node_keypair --force --private-key-path /app/node.key and re-register with all federated nodes.

Voice and video require Janus. After setup, add JANUS_URL=wss://your-janus-host/janus to your .env and restart (docker compose restart gunicorn daphne). Without it, text channels and federation work fine — only voice/video channels are unavailable. See janus.conf.meetecho.com for setup instructions.

3. Set Up TLS

The containers listen on port 80. Your host reverse proxy handles TLS and forwards traffic to it.

Option A — Caddy (simplest)

Caddy handles certificate issuance automatically.

sudo apt install caddy
# /etc/caddy/Caddyfile chat.example.com { reverse_proxy localhost:80 }
sudo systemctl reload caddy

Option B — nginx + Certbot

sudo apt install nginx certbot python3-certbot-nginx
# /etc/nginx/sites-available/flebop server { listen 80; server_name chat.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name chat.example.com; ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem; location / { proxy_pass http://127.0.0.1:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400; } }
sudo ln -s /etc/nginx/sites-available/flebop /etc/nginx/sites-enabled/ sudo certbot --nginx -d chat.example.com sudo systemctl reload nginx

4. Create an Admin Account

docker compose exec gunicorn python manage.py createsuperuser

5. Verify

Joining the Federation

If you didn't enter a seed node during setup, you can join the federation at any time:

docker compose exec gunicorn python manage.py register_node https://other.example.com # Ping all registered nodes to verify connectivity docker compose exec gunicorn python manage.py ping_nodes

New registrations are inactive by default on the receiving node. The receiving node admin must approve them before cross-node traffic is accepted:

# List pending nodes docker compose exec gunicorn python manage.py approve_node # Approve a specific node docker compose exec gunicorn python manage.py approve_node https://other.example.com

Updating

git pull docker compose up --build -d

Migrations and static file collection run automatically on container start via the entrypoint.

Useful Commands

# View logs docker compose logs -f # Open a Django shell docker compose exec gunicorn python manage.py shell # Stop everything docker compose down # Stop and wipe all data (irreversible) docker compose down -v

More control. Run flebop directly on the host using a Python virtualenv, systemd services, and your own Redis and nginx setup.

Prerequisites

Server

A VPS or dedicated server running Linux. 1 GB RAM minimum, 2 GB recommended.

Domain

A domain or subdomain pointing at your server. TLS is required for federation.

Python 3.11+

Python 3.11 or newer. 3.12 recommended.

Redis

Redis 6+. Used for WebSocket channel layers and real-time messaging.

Nginx

Reverse proxy for TLS termination and static file serving.

Certbot

For obtaining a Let's Encrypt TLS certificate.

Janus WebRTC

Required for voice and video channels. Set JANUS_URL in .env to point at your instance.

1. Get the Code

The public repository is temporarily unavailable. This guide will be updated with installation instructions when the source is re-released.

# Once the repository is available: cd /srv/flebop # Create and activate virtualenv python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt

2. Configure the Environment

# Generate a secret key python -c "import secrets; print(secrets.token_urlsafe(50))"

Create a .env file in the project root:

DJANGO_SECRET_KEY=your-generated-secret-key DEBUG=False # Your domain ALLOWED_HOSTS=chat.example.com CSRF_TRUSTED_ORIGINS=https://chat.example.com # Redis REDIS_HOST=127.0.0.1 # Node identity NODE_URL=https://chat.example.com NODE_NAME=My Node # Path to your ECDSA private key (generated in step 4) NODE_PRIVATE_KEY_PATH=/home/user/flebop/node.key # Janus WebRTC — required for voice/video channels JANUS_URL=wss://janus.example.com/janus # Optional — restrict signups to people with this code # BETA_INVITE_CODE=your-invite-code

NODE_URL must be the full public HTTPS URL of your node. It becomes part of every user's global ID and cannot be changed once you have registered with other nodes.

3. Run Migrations

python manage.py migrate

4. Generate the Node Keypair

Each flebop node authenticates with other nodes using an ECDSA P-256 keypair. The private key stays on your server and is never transmitted.

# Generate the keypair python manage.py generate_node_keypair --private-key-path ~/flebop/node.key # Confirm it's readable only by your user ls -la ~/flebop/node.key # Should show: -rw------- 1 user user ...

Keep this file secret. Never commit it to git or copy it to a world-readable location. If it is compromised, regenerate it and re-register with all federated nodes. Add *.key to your .gitignore.

Set NODE_PRIVATE_KEY_PATH in your .env to the full path, then verify:

python manage.py init_local_node # Should print: Node keypair: configured

5. Collect Static Files

python manage.py collectstatic --no-input

6. Create an Admin Account

python manage.py createsuperuser

7. Set Up Redis

sudo apt install redis-server sudo systemctl enable --now redis-server # Verify redis-cli ping # PONG

8. Set Up Gunicorn & Daphne

flebop uses two processes: Gunicorn for HTTP and Daphne for WebSockets. Create a systemd service for each.

Gunicorn

sudo nano /etc/systemd/system/flebop-gunicorn.service
[Unit] Description=flebop Gunicorn After=network.target [Service] User=your-user WorkingDirectory=/srv/flebop EnvironmentFile=/srv/flebop/.env ExecStart=/srv/flebop/venv/bin/gunicorn \ --workers 3 \ --bind 127.0.0.1:8000 \ voip_project.wsgi:application Restart=on-failure [Install] WantedBy=multi-user.target

Daphne (WebSockets)

sudo nano /etc/systemd/system/flebop-daphne.service
[Unit] Description=flebop Daphne After=network.target redis.service [Service] User=your-user WorkingDirectory=/srv/flebop EnvironmentFile=/srv/flebop/.env ExecStart=/srv/flebop/venv/bin/daphne \ -b 127.0.0.1 \ -p 8001 \ voip_project.asgi:application Restart=on-failure [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable --now flebop-gunicorn flebop-daphne

9. Configure Nginx

sudo nano /etc/nginx/sites-available/flebop
server { listen 80; server_name chat.example.com; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name chat.example.com; ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem; client_max_body_size 10M; location /static/ { alias /srv/flebop/staticfiles/; expires 30d; add_header Cache-Control "public, immutable"; } location /media/ { alias /srv/flebop/media/; } location /ws/ { proxy_pass http://127.0.0.1:8001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 86400; } location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 60; } }
sudo ln -s /etc/nginx/sites-available/flebop /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx

10. TLS Certificate

sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d chat.example.com

11. Verify

Joining the Federation

python manage.py register_node https://other.example.com # Ping all registered nodes to verify connectivity python manage.py ping_nodes

New registrations are inactive by default on the receiving node. The receiving node admin must approve them before cross-node traffic is accepted:

# List pending nodes python manage.py approve_node # Approve a specific node python manage.py approve_node https://other.example.com

Updating

cd /srv/flebop git pull source venv/bin/activate pip install -r requirements.txt python manage.py migrate python manage.py collectstatic --no-input sudo systemctl restart flebop-gunicorn flebop-daphne
← Federation Guide Roadmap →