Try the demo

Need a quick overview? Try the OpenWISP Demo.

Deploy it in production

An automated installer is available at ansible-openwisp2.

Create a virtual environment

Please use a python virtual environment. It keeps everybody on the same page, helps reproducing bugs and resolving problems.

We highly suggest to use virtualenvwrapper, please refer to the official virtualenvwrapper installation page and come back here when ready to proceed.

# create virtualenv
mkvirtualenv radius


If you encounter an error like Python could not import the module virtualenvwrapper, add VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 and run source again :)

Install required system packages

Install packages required by Weasyprint for your OS:

Install stable version from pypi

Install from pypi:

# REQUIRED: update base python packages
pip install -U pip setuptools wheel
# install openwisp-radius
pip install openwisp-radius

Install development version

Install tarball:

# REQUIRED: update base python packages
pip install -U pip setuptools wheel
# install openwisp-radius
pip install

Alternatively you can install via pip using git:

# REQUIRED: update base python packages
pip install -U pip setuptools wheel
# install openwisp-radius
pip install -e git+git://

If you want to contribute, install your cloned fork:

# REQUIRED: update base python packages
pip install -U pip setuptools wheel
# install your forked openwisp-radius
git clone<your_fork>/openwisp-radius.git
cd openwisp-radius
pip install -e .

Setup (integrate in an existing django project)

The file of your project should have at least the following modules listed INSTALLED_APPS:

    # openwisp admin theme
    # all-auth
    # admin
    # rest framework
    # registration
    # openwisp radius

These modules are optional, add them only if you need the social login feature:

    # social login

Add media locations in

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
PRIVATE_STORAGE_ROOT = os.path.join(MEDIA_ROOT, 'private')


AUTH_USER_MODEL = 'openwisp_users.User'

Add allowed freeradius hosts in


Add the URLs to your main

from openwisp_radius.urls import get_urls

urlpatterns = [
    # ... other urls in your project ...

    # django admin interface urls
    # openwisp-radius urls
    path('api/v1/', include('openwisp_utils.api.urls')),
    path('api/v1/', include('openwisp_users.api.urls')),
    path('accounts/', include('openwisp_users.accounts.urls')),
    path('', include('openwisp_radius.urls'))

Then run:

./ migrate

Migrating an existing freeradius database

If you already have a freeradius 3 database with the default schema, you should be able to use it with openwisp-radius (and extended apps) easily:

  1. first of all, back up your existing database;

  2. configure django to connect to your existing database;

  3. fake the first migration (which only replicates the default freeradius schema) and then launch the rest of migrations normally, see the examples below to see how to do this.

./ migrate --fake openwisp-radius 0001_initial_freeradius
./ migrate

Automated periodic tasks

Some periodic commands are required in production environments to enable certain features and facilitate database cleanup. There are two ways to automate these tasks:

2. Crontab (Legacy Method)

Edit the crontab with:

crontab -e

Add and modify the following lines accordingly:

# This command deletes RADIUS accounting sessions older than 365 days
30 04 * * * <virtualenv_path>/bin/python <full/path/to>/ delete_old_radacct 365

# This command deletes RADIUS post-auth logs older than 365 days
30 04 * * * <virtualenv_path>/bin/python <full/path/to>/ delete_old_postauth 365

# This command closes stale RADIUS sessions that have remained open for 15 days
30 04 * * * <virtualenv_path>/bin/python <full/path/to>/ cleanup_stale_radacct 15

# This command deactivates expired user accounts which were created temporarily
# (eg: for en event) and have an expiration date set.
30 04 * * * <virtualenv_path>/bin/python <full/path/to>/ deactivate_expired_users

# This command deletes users that have expired (and should have
# been deactivated by deactivate_expired_users) for more than
# 18 months (which is the default duration)
30 04 * * * <virtualenv_path>/bin/python <full/path/to>/ delete_old_radiusbatch_users

Be sure to replace <virtualenv_path> with the absolute path to the Python virtual environment.

Also, change <full/path/to> to the directory where is.

To get the absolute path to when openwisp-radius is installed for development, navigate to the base directory of the cloned fork. Then, run:

cd tests/


More information can be found at the management commands page.

Installing for development

Install python3-dev and gcc:

sudo apt install python3-dev gcc

Install sqlite:

sudo apt install sqlite3 libsqlite3-dev libpq-dev

Install mysqlclient:

sudo apt install libmysqlclient-dev libssl-dev


If you are on Debian 10 or 9 you may need to install default-libmysqlclient-dev instead

Install xmlsec1:

sudo apt install xmlsec1

Install your forked repo:

git clone git://<your_username>/openwisp-radius
cd openwisp-radius/
pip install -e .[saml,openvpn_status]

Install test requirements:

pip install -r requirements-test.txt

Create database:

cd tests/
./ migrate
./ createsuperuser

Launch development server:

./ runserver

You can access the admin interface at

Run tests with:


Celery Usage

To run celery, you need to start redis-server. You can install redis on your machine or install docker and run redis inside docker container:

docker run -p 6379:6379 --name openwisp-redis -d redis:alpine

Run celery (it is recommended to use a tool like supervisord in production):

# Optionally, use ``--detach`` argument to avoid using multiple terminals
celery -A openwisp2 worker -l info
celery -A openwisp2 beat -l info


If you encounter any issue during installation, run:

pip install -e .[saml] -r requirements-test.txt

instead of pip install -r requirements-test.txt