Back to On-Premise
✓ Available now

On-Premise Installation Guide

Step-by-step guide to installing Captivo on your own server. With a Docker-ready Linux server, the entire process takes under 30 minutes.

1. Prerequisites

Make sure the following are installed on your server:

OSLinux x86_64 — Ubuntu 22.04+, Debian 12+, or RHEL 9+ recommended
RAMAt least 2 GB (4 GB recommended for production)
DiskAt least 10 GB (20 GB+ recommended for backups)
Docker Engine24+ — check with docker --version
Docker Compose v2docker compose version (space, not hyphen; v1 not supported)
opensslcheck with openssl version

Quick Docker install (Ubuntu/Debian):

curl -fsSL https://get.docker.com | sh

Required Ports

PortProtocolPurpose
3000TCPManagement panel (HTTP without TLS)
80 / 443TCPCaddy when TLS is enabled
1812UDPRADIUS authentication
1813UDPRADIUS accounting
A static LAN IP is sufficient for testing or internal use. A publicly accessible domain and TLS are recommended for production (see §4).

2. Installation (Single Command)

2.1 Get the Installation Files

The install package (docker/ folder) is provided to you. Place all files in the same directory:

docker/
├── docker-compose.onprem.yml
├── onprem/
│   ├── install.sh
│   ├── Caddyfile
│   ├── backup.sh
│   └── .env.onprem.example

2.2 Run the Install Script

chmod +x docker/onprem/install.sh
./docker/onprem/install.sh

The script:

  1. Checks for docker and openssl dependencies.
  2. If docker/.env.onprem does not exist, asks for your server address and auto-generates all secrets (POSTGRES_PASSWORD, AUTH_SECRET, DATA_ENCRYPTION_KEY, etc.) with openssl rand.
  3. Starts all services with docker compose up -d.
  4. Prints the panel URL when done.

Example output:

✓ Secrets generated (.env.onprem)

✓ Starting services...

✔ Container captivo-postgres Started

✔ Container captivo-migrator Exited

✔ Container captivo-radius Started

✔ Container captivo-web Started

✓ Installation complete!

Panel: http://localhost:3000

IMPORTANT — DATA_ENCRYPTION_KEY: The DATA_ENCRYPTION_KEY value in docker/.env.onprem is the encryption key for guest MAC addresses and other encrypted fields. Back up this file securely off-server (password manager, encrypted USB, etc.). If the key is lost, encrypted data becomes permanently unreadable.

3. First Launch — Setup Wizard

The first time you open the panel (http://<server-ip>:3000), you will be automatically redirected to the /setup wizard. It has 9 steps:

1

Admin Account

Set the super-admin email and password.

2

Organisation

Company/organisation name, logo, language preference.

3

Portal Design

Captive portal appearance (background, colours, heading).

4

RADIUS

RADIUS shared secret and NAS configuration.

5

Login Methods

Social login, SMS OTP, guest form options.

6

SMS

SMS provider (your own account: Netgsm, Twilio, etc.) — optional.

7

SMTP

Outbound email server (for notifications) — optional.

8

Licence

Upload a .lic file or start the 15-day free trial.

9

Done

Setup summary and sign in to the panel.

SMS and SMTP steps are optional — skip them and configure later from the Settings menu.

4. TLS / HTTPS (Recommended for Production)

The default http://localhost:3000 is for local testing only. HTTPS is required in production.

4.1 Configure Your Domain

Edit docker/.env.onprem:

NEXTAUTH_URL=https://wifi.company.com
SITE_DOMAIN=wifi.company.com

4.2 Start Caddy with the TLS Profile

docker compose -f docker/docker-compose.onprem.yml \
  --profile tls \
  --env-file docker/.env.onprem \
  up -d
Caddy uses the SITE_DOMAIN variable to reverse-proxy captivo-web:3000 via the Caddyfile and automatically obtains a TLS certificate from Let's Encrypt. Requirement: The domain's DNS must resolve to this server's public IP and ports 80/443 must be externally reachable.

5. RADIUS — Connecting Your NAS

The FreeRADIUS container starts automatically and listens on UDP 1812/1813. Configure the following on your NAS or gateway device:

SettingValue
RADIUS server IPThis server's LAN IP address
Authentication port1812 UDP
Accounting port1813 UDP
RADIUS methodPAP
Shared secretThe value generated in wizard Step 4 or shown at Settings → RADIUS
Add Captivo's server LAN IP to the “walled garden” or “unauthenticated pass-through” list on your NAS so guests can reach the portal before authentication.

Supported NAS/gateway models: pfSense, OPNsense, MikroTik, FortiGate, Cisco Meraki, and other devices supporting PAP/CHAP.

6. Licence

A 15-day free trial starts automatically after installation with all features enabled.

Once you have your licence file (.lic) from your vendor:

  1. Go to Settings → Licence in the panel.
  2. Upload the .lic file.
  3. Licence details (expiry date, quota) are displayed on screen.

When the trial or licence expires, the system winds down gradually: a warning first, then read-only mode (new guest registration stops, existing data is visible), and finally panel access is restricted until the licence is renewed.

No internet connection required for licence validation in air-gapped environments.

7. Backups

CRITICAL: Back up docker/.env.onprem securely off-server. Without the DATA_ENCRYPTION_KEY inside it, encrypted data in the database backup (MAC addresses, etc.) becomes permanently unreadable.

Database Backup

docker/onprem/backup.sh runs pg_dump from PostgreSQL, compresses the output and stores it (7-day rotation).

Run manually:

POSTGRES_USER=captivo BACKUP_DIR=/opt/captivo-backups \
  ./docker/onprem/backup.sh

Schedule with cron (daily at 03:15):

15 3 * * * POSTGRES_USER=captivo BACKUP_DIR=/opt/captivo-backups \
  /opt/captivo/docker/onprem/backup.sh >> /var/log/captivo-backup.log 2>&1
Local backups are lost if the server fails. Copy backups regularly to a secondary location — S3, R2, a NAS, or an encrypted external drive.

8. Air-Gapped (Offline) Installation

For networks with no internet access, Docker images can be pre-packaged.

Bundle on an internet-connected machine

# Bundle the latest release
./scripts/onprem/build-offline-bundle.sh

# For a specific version:
./scripts/onprem/build-offline-bundle.sh 1.0.0

Output: captivo-onprem-1.0.0.tar (includes web, RADIUS, postgres and caddy images)

Install on the target machine

# Load images into Docker
docker load -i captivo-onprem-1.0.0.tar

# Run the install script (no internet needed)
./docker/onprem/install.sh
Let's Encrypt certificates cannot be obtained in air-gapped environments. Use your corporate CA certificate or HTTP for internal networks.

9. Troubleshooting

Panel won't open

  • docker compose … ps — are all containers in the Up state?
  • Did the migrator service complete successfully (Exited (0))?
  • Is port 3000 open in your firewall?
  • Logs: docker compose … logs web

RADIUS connection error (guests can't log in)

  • Is the RADIUS server IP on the NAS correct? (This server's LAN IP)
  • Is UDP 1812/1813 reachable from the NAS?
  • Is the shared secret exactly the same on the NAS and in Captivo?
  • Is captivo-radius running? (docker logs captivo-radius)

SMS not arriving

  • Were SMS provider credentials entered in wizard Step 6?
  • Is this server's IP in the NAS walled garden list?

Email notifications not sent

  • Were SMTP settings configured in wizard Step 7?
  • Verify SMTP port and password in the container logs.

General log inspection

# All service logs (last 50 lines)
docker compose -f docker/docker-compose.onprem.yml \
  --env-file docker/.env.onprem \
  logs --tail=50

# FreeRADIUS logs
docker logs captivo-radius

Need help? Contact our support team.