Deployment guide

OpenWISP Ubuntu 24.04

Overview

OpenWISP Controller is the flagship module of OpenWISP, the open-source network management system. It is a centralised, multi-tenant platform for provisioning and managing the configuration of network devices such as routers and wireless access points. You define reusable configuration templates and apply them to devices with automatic per-device variable substitution. The controller then compiles each device's exact configuration and serves it.

This SecureAnyCloud image runs OpenWISP Controller 1.2.3 on Ubuntu 24.04 LTS, fully installed and reverse proxied behind nginx. The gunicorn application server, a Celery worker and scheduler, PostgreSQL 16 with the PostGIS spatial extension, and Redis 7 are already configured and managed by systemd, so a working controller is operational within minutes of launch.

What you get:

  • OpenWISP Controller 1.2.3 installed from PyPI into a dedicated Python virtual environment at /opt/openwisp
  • An integrated x509 PKI for certificate authorities and certificates
  • VPN provisioning for OpenVPN, WireGuard, ZeroTier and VXLAN over WireGuard
  • Device connection and credential management, plus automatic subnet division and IP address management
  • A complete REST API for automation
  • PostgreSQL 16 + PostGIS 3 as the primary spatial database and Redis 7 as the Celery broker, cache and channels layer
  • gunicorn serving the Django application on 127.0.0.1:8001, fronted by nginx on port 80
  • A Celery worker (openwisp-celery.service) and a Celery beat scheduler (openwisp-celery-beat.service) for background and periodic controller tasks
  • Six systemd units, enabled and active: postgresql, redis-server, openwisp, openwisp-celery, openwisp-celery-beat and nginx
  • Secure by default: no administrator account and no shared secret ship in the image. On first boot, a unique Django secret key, a unique database password, a unique administrator account and a REST API token are generated and written to a root-only file
  • An Ubuntu 24.04 LTS base, patched at build time, with a swapfile for the recommended size and unattended security upgrades enabled
  • 24/7 SecureAnyCloud support

Prerequisites

You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.

Standard_B2s (2 vCPU / 4 GiB RAM) is the recommended size for evaluation and small fleets. For larger fleets, or if you add the OpenWISP monitoring module, choose a size with more memory.

Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp for the admin interface. OpenWISP serves plain HTTP on port 80. For production or shared access, terminate TLS in front of it with your own domain (see Step 11).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for OpenWISP by SecureAnyCloud, and select Create.

On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).

Select Review + create, then Create.

Step 2 - Deploy from the Azure CLI

# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:openwisp-ubuntu-24-04:default:latest
az vm create \
  --resource-group your-rg \
  --name openwisp \
  --image sac1647283583153:openwisp-ubuntu-24-04:default:latest \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name your-vnet --subnet your-subnet \
  --public-ip-sku Standard
# Open the HTTP port so you can reach the admin interface
az vm open-port --resource-group your-rg --name openwisp --port 80 --priority 900

Step 3 - Retrieve the per-VM admin credentials

Nothing secret is baked into the image. On the first boot, a one-shot service (openwisp-firstboot.service) generates a fresh Django secret key, a fresh database password, a unique administrator account and a REST API token. All of them are unique to your instance. The service writes them to /root/openwisp-credentials.txt, which only root can read. SSH in as azureuser and read the file:

$
sudo cat /root/openwisp-credentials.txt
# OpenWISP Controller - generated on first boot by openwisp-firstboot.service.
# These credentials are unique to THIS VM. Store them somewhere safe. openwisp.url=http://20.55.10.42/admin/ openwisp.admin.user=admin openwisp.admin.pass=Xq7pR2mK9wU4nZ8vB3hL6yD1 openwisp.api.token=8f3c1e0a9b2d4c6e8f0a1b2c3d4e5f60718293a4
# Canonical keys consumed by the sac smoke verifier + guide substitution: OPENWISP_ADMIN_PASSWORD=<set-at-first-boot> OPENWISP_API_TOKEN=<set-at-first-boot>

openwisp-firstboot.service is ordered before the application services, so the admin UI starts only after every per-VM secret has been generated. The values above are an example. Your instance has its own unique credentials.

Step 4 - Confirm the services are running

Check that PostgreSQL, Redis, the OpenWISP application, the Celery worker, the Celery beat scheduler and nginx are all active:

sudo systemctl is-active postgresql redis-server openwisp openwisp-celery openwisp-celery-beat nginx

All six report active. gunicorn binds to loopback only (127.0.0.1:8001), and nginx publishes the interface on port 80. Confirm the listeners:

sudo ss -tlnp | grep -E ':80 |:8001 '

Step 5 - Confirm the web endpoints

The admin sign-in page returns 200. OpenWISP requires authentication for everything else. An anonymous request to the application is redirected to the login page, and the REST API returns 401 without a token. This is the secure default. Request the three URLs:

curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/admin/login/
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/
curl -s -o /dev/null -w 'HTTP %{http_code}\n' http://localhost/api/v1/controller/device/

Step 6 - Sign in to the admin UI

Browse to http://<vm-ip>/admin/ and sign in as admin with the password from /root/openwisp-credentials.txt.

After you sign in, you land on the OpenWISP dashboard. Its charts summarise configuration status, geographic positioning, device models and firmware versions across your fleet.

The screenshots in this guide show OpenWISP populated with a small set of example objects. A freshly deployed instance starts empty, ready for you to model your own network.

Step 7 - Define a template and add devices

OpenWISP Controller manages device configuration through templates and devices.

Under Configurations > Templates, define a reusable configuration, for example a set of network interfaces and a wireless radio, using the NetJSON/OpenWrt backend. Under Devices, register each router or access point and apply one or more templates to it. The controller then compiles each device's final configuration from its templates and per-device variables.

Open a device to see its managed configuration. The device change page has Overview, Configuration, Map and Credentials tabs. The Preview configuration button shows the compiled output. The Download configuration button produces the archive a device fetches when it checks in.

Step 8 - See the controller generate a device configuration

The controller compiles each device's configuration from its templates. Render a device's configuration from the command line to see exactly what the controller serves. The manage.py command is wrapped as sudo openwisp-manage:

echo "from swapper import load_model D = load_model('config','Device') d = D.objects.first() print(d.config.backend_instance.render()) if d and hasattr(d,'config') else print('no devices yet - add one in the admin UI')" | sudo openwisp-manage shell

On the example instance, the command renders a full OpenWrt UCI configuration for the access point. It includes the hostname, the eth0 interface and the wlan0 wireless interface in access point mode:

Step 9 - Use the REST API

OpenWISP exposes a complete REST API under /api/v1/. To call any endpoint, send the token from /root/openwisp-credentials.txt in the Authorization: Bearer <token> header. Read the token into a shell variable, then list your devices and templates:

TOKEN=$(sudo grep '^OPENWISP_API_TOKEN=' /root/openwisp-credentials.txt | cut -d= -f2-)
curl -s -o /dev/null -w 'devices HTTP %{http_code}\n' -H "Authorization: Bearer $TOKEN" http://localhost/api/v1/controller/device/
curl -s -o /dev/null -w 'templates HTTP %{http_code}\n' -H "Authorization: Bearer $TOKEN" http://localhost/api/v1/controller/template/

Both return 200 with your data. Without the token, or with a wrong one, the API returns 401, so your network data is never readable anonymously. The interactive API documentation is available in the admin under the API section.

Step 10 - Add the other OpenWISP modules

This image ships the OpenWISP Controller core: configuration management, PKI, geo, connections, subnet division, users and IP address management. OpenWISP is modular, so you can add the other modules to the same instance, in the same Python virtual environment:

  • openwisp-monitoring: device metrics, health checks and alerts
  • openwisp-firmware-upgrader: mass firmware upgrades
  • openwisp-radius: a full RADIUS stack for captive portals and 802.1x
  • openwisp-network-topology: live network topology collection and visualisation

Install each module with sudo /opt/openwisp/venv/bin/pip install <module>. Add it to INSTALLED_APPS and urls.py in /opt/openwisp/project/openwisp2/, then activate it with sudo openwisp-manage migrate and a restart. The monitoring module in particular benefits from a larger VM size. Our support team can help you plan and roll out these modules.

Step 11 - Enable HTTPS with your own domain

OpenWISP ships on plain HTTP on port 80 so that it works immediately. For production, point a DNS record at the VM's public IP. Add the hostname to ALLOWED_HOSTS and CSRF_TRUSTED_ORIGINS in /opt/openwisp/project/openwisp2/local_settings.py, and terminate TLS with a certificate.

A common approach is to obtain a certificate with certbot and reverse proxy through nginx, or to place Azure Application Gateway in front of the VM. Restart the application after editing the configuration:

$
sudo systemctl restart openwisp openwisp-celery openwisp-celery-beat

Administration and support

The OpenWISP manage.py command is wrapped for convenience. Run sudo openwisp-manage <command>, for example sudo openwisp-manage createsuperuser to add another administrator or sudo openwisp-manage changepassword admin to reset a password.

The Django settings live in /opt/openwisp/project/openwisp2/. Restart OpenWISP and its Celery services with sudo systemctl restart openwisp openwisp-celery openwisp-celery-beat.

This image is a repackaged open-source software product with additional charges for SecureAnyCloud support services. Our engineers provide 24/7 support for deployment, upgrades, TLS termination, adding the OpenWISP monitoring, firmware, RADIUS and topology modules, VPN and PKI setup, API automation and scaling. OpenWISP is a trademark of its respective owner. The name is used here only to identify the software this image packages.

Deploy on Azure

Launch OpenWISP Controller on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.

View this image

Need Help?

Our support team is available 24/7.

sales@secureanycloud.com

Deploy on Azure