There's a story to this. Short version is a friend posted about netbox, an IP address management and data center infrastructure tool. Later I wanted to redo my virutal lab environment from scratch but with better documentation. I figured I'd set up an instance of netbox to document how my lab should be. So here goes.

SECOND ATTEMPT AND TROUBLESHOOTING

After following the documentation once and making notes, this is what I had going into my second attempt at installing netbox. I am not going to break this up, this is just raw text file that I have been working out of. We'll get into a bunch of troubleshooting as we go, and I'll point out my changes along the way. This is pretty close to the documentation, with a few changes to respond to issues I ran into on my first attempt.

sudo apt update ; sudo apt upgrade
sudo apt autoremove

sudo apt-get install -y postgresql libpq-dev
sudo -u postgres psql
CREATE DATABASE netbox;
CREATE USER netbox WITH PASSWORD 'XY,gTr6GP-Xy';
GRANT ALL PRIVILEGES ON DATABASE netbox TO netbox;
\q

sudo apt-get install -y python3 python3-dev python3-setuptools build-essential libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev
sudo apt install -y python3-pip

wget https://github.com/digitalocean/netbox/archive/v2.4.2.tar.gz
sudo tar -xzf v2.4.2.tar.gz -C /opt
cd /opt/
sudo ln -s netbox-2.4.2/ netbox
cd /opt/netbox/

pip3 install -r requirements.txt

cd /opt/netbox/netbox/netbox
sudo cp configuration.example.py configuration.py
python3 /opt/netbox/netbox/generate_secret_key.py > ~/secretkey

sudo vi configuration.py
ALLOWED_HOSTS = ['192.168.0.11']
DATABASE = {
    'NAME': 'netbox',
    'USER': 'netbox',
    'PASSWORD': 'XY,gTr6GP-Xy',
    'HOST': 'localhost',
    'PORT': '',
}

SECRET_KEY = 'J8g4+*aFfpV#2tGEPOSA%NriQx=Yvb_uWzKLy-U)0^w$Tl&5os'

cd /opt/netbox/netbox/
python3 manage.py migrate
python3 manage.py createsuperuser
sudo python3 manage.py collectstatic --no-input

sudo apt install -y nginx
sudo vi /etc/nginx/sites-available/netbox
server {
    listen 80;

    server_name 192.168.0.11;

    client_max_body_size 25m;

    location /static/ {
        alias /opt/netbox/netbox/static/;
    }

    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
    }
}

cd /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/netbox

cd ~
sudo pip3 install gunicorn --install-option="--install-scripts=/usr/bin" -t python_modules/
which gunicorn

sudo vi /opt/netbox/gunicorn_config.py

command = '/usr/bin/gunicorn'
pythonpath = '/opt/netbox/netbox'
bind = '127.0.0.1:8001'
workers = 3
user = 'www-data'

sudo apt install -y supervisor

sudo vi /etc/supervisor/conf.d/netbox.conf

[program:netbox]
command = gunicorn -c /opt/netbox/gunicorn_config.py netbox.wsgi
directory = /opt/netbox/netbox/
user = www-data

[program:netbox-rqworker]
command = python3 /opt/netbox/netbox/manage.py rqworker
directory = /opt/netbox/netbox/
user = www-data

Ends in 502 Bad Gateway. This is an expected error. From the documents, 'If you receive a 502 (bad gateway) error, this indicates that gunicorn is misconfigured or not running.'

Checking the status of supervisor confirms that gunicorn is not running.

malachite@netbox:~$ service supervisor status
● supervisor.service - Supervisor process control system for UNIX
   Loaded: loaded (/lib/systemd/system/supervisor.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-08-09 18:10:01 UTC; 9min ago
     Docs: http://supervisord.org
  Process: 51436 ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown (code=exited, status=0/SUCCESS)
 Main PID: 51437 (supervisord)
    Tasks: 1 (limit: 972)
   CGroup: /system.slice/supervisor.service
           └─51437 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf

Aug 09 18:10:06 netbox supervisord[51437]: 2018-08-09 18:10:06,610 INFO spawned: 'netbox' with pid 51468
Aug 09 18:10:06 netbox supervisord[51437]: 2018-08-09 18:10:06,614 INFO spawned: 'netbox-rqworker' with pid 51469
Aug 09 18:10:06 netbox supervisord[51437]: 2018-08-09 18:10:06,881 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 18:10:06 netbox supervisord[51437]: 2018-08-09 18:10:06,989 INFO exited: netbox (exit status 1; not expected)
Aug 09 18:10:09 netbox supervisord[51437]: 2018-08-09 18:10:09,995 INFO spawned: 'netbox' with pid 51475
Aug 09 18:10:09 netbox supervisord[51437]: 2018-08-09 18:10:09,998 INFO spawned: 'netbox-rqworker' with pid 51476
Aug 09 18:10:10 netbox supervisord[51437]: 2018-08-09 18:10:10,259 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 18:10:10 netbox supervisord[51437]: 2018-08-09 18:10:10,351 INFO gave up: netbox-rqworker entered FATAL state, too many start retries too quickly
Aug 09 18:10:10 netbox supervisord[51437]: 2018-08-09 18:10:10,368 INFO exited: netbox (exit status 1; not expected)
Aug 09 18:10:11 netbox supervisord[51437]: 2018-08-09 18:10:11,370 INFO gave up: netbox entered FATAL state, too many start retries too quickly

These workers exist because of the python scripts /etc/supervisor/conf.d/netbox.conf and /opt/netbox/gunicorn_config.py. We know that /etc/supervisor/conf.d/netbox.conf is working because supervisor is attempting to spawn the workers defined in the script.

/etc/supervisor/conf.d/netbox.conf is run first and reads:

[program:netbox]
command = gunicorn -c /opt/netbox/gunicorn_config.py netbox.wsgi
directory = /opt/netbox/netbox/
user = www-data

[program:netbox-rqworker]
command = python3 /opt/netbox/netbox/manage.py rqworker
directory = /opt/netbox/netbox/
user = www-data

/opt/netbox/gunicorn_config.py is run by the netbox worker defined in the first script.

command = '/usr/bin/gunicorn'
pythonpath = '/opt/netbox/netbox'
bind = '127.0.0.1:8001'
workers = 3
user = 'www-data'

So, looking back at the status, it runs netbox first, and then starts netbox-rqworker. When netboxrqworker fails, it closes and takes netbox with it. Either that or it is starting them both and they are both failing for the same reason. Although it has to do with php, this question at StackOverflow brings up what I've been thinking.

"I more assume that the file is located under your home directory and the root user is not able access and run it. So I would try to change the location of the script."

The first time I had to sudo to put something into /opt/ I figured this was going to become an issue, especially since both /etc/supervisor/conf.d/netbox.conf and /opt/netbox/gunicorn_config.py both specify user = www-data. So there are two potential problems. Either gunicorn isn't installed correctly, as the 502 Bad Gateway implies, or www-data is the user attempting to run the scripts and cannot access anything in /opt/.

Running which gunicorn shows that gunicorn exists at /usr/bin/gunicorn which is what we intended when we ran sudo pip3 install gunicorn --install-option="--install-scripts=/usr/bin" -t python_modules/. So let's make sure that the agent is able to use gunicorn.

malachite@netbox:~$ ls -alh /usr/bin | tail -5
-rwxr-xr-x  1 root   root    1.8K Jun 28  2017 xzless
-rwxr-xr-x  1 root   root    2.2K Jun 28  2017 xzmore
-rwxr-xr-x  1 root   root     31K Jan 18  2018 yes
-rwxr-xr-x  1 root   root     19K Apr 16 20:14 zdump
-rwxr-xr-x  1 root   root     48K Jul 18 14:21 zipdetails
malachite@netbox:~$ ls -alh /usr/bin/gunicorn
-rwxr-xr-x 1 root root 390 Aug  9 17:37 /usr/bin/gunicorn

The permissions are identical to the typical binaries in /usr/bin, so we can check that off. This means gunicorn itself isn't the issue, which makes the official documentation's implication that Gunicorn is 'misconfigured' a little frustrating. This is clearly a permissions issue.

Let's test something. I cannot su - www-data to see if it can see inside /opt/, but I made another user netbox with --logon-disabled to see if I can even see inside of /opt/.

malachite@netbox:~$ sudo su - netbox
[sudo] password for malachite:
netbox@netbox:~$ ls -alh /opt/netbox
lrwxrwxrwx 1 root www-data 13 Aug  9 17:23 /opt/netbox -> netbox-2.4.2/
netbox@netbox:~$ ls -alh /opt/netbox/
total 84K
drwxrwsr-x  6 root www-data 4.0K Aug  9 17:39 .
drwxr-xr-x  3 root root     4.0K Aug  9 17:23 ..
-rw-rwSr--  1 root www-data  492 Aug  8 13:16 base_requirements.txt
-rw-rwSr--  1 root www-data 5.5K Aug  8 13:16 CONTRIBUTING.md
drwxrwsr-x 10 root www-data 4.0K Aug  8 13:16 docs
-rw-rwSr--  1 root www-data   17 Aug  8 13:16 .gitattributes
drwxrwsr-x  3 root www-data 4.0K Aug  8 13:16 .github
-rw-rwSr--  1 root www-data  190 Aug  8 13:16 .gitignore
-rw-r-Sr--  1 root www-data  118 Aug  9 17:39 gunicorn_config.py
-rw-rwSr--  1 root www-data  10K Aug  8 13:16 LICENSE.txt
-rw-rwSr--  1 root www-data 2.3K Aug  8 13:16 mkdocs.yml
drwxrwsr-x 17 root www-data 4.0K Aug  9 17:32 netbox
-rw-rwSr--  1 root www-data   38 Aug  8 13:16 old_requirements.txt
-rw-rwSr--  1 root www-data 2.3K Aug  8 13:16 README.md
-rw-rwSr--  1 root www-data  458 Aug  8 13:16 requirements.txt
drwxrwsr-x  2 root www-data 4.0K Aug  8 13:16 scripts
-rw-rwSr--  1 root www-data  297 Aug  8 13:16 .travis.yml
-rwxrwsr-x  1 root www-data 1.8K Aug  8 13:16 upgrade.sh

The fact that www-data has group permissions was the result of me attempting to fix this permissions issue previously by using this method from StackOverflow.

sudo chown -R root:www-data /opt/netbox
sudo chmod -R g+s /opt/netbox
sudo chown -R root:www-data /opt/netbox-2.4.2/
sudo chmod -R g+s /opt/netbox-2.4.2/

Either way, a non-sudo user can peak inside. Can it read execute anything?

netbox@netbox:~$ ls -alh /opt/netbox/netbox
total 76K
drwxrwsr-x 17 root www-data 4.0K Aug  9 17:32 .
drwxrwsr-x  6 root www-data 4.0K Aug  9 17:39 ..
drwxrwsr-x  7 root www-data 4.0K Aug  9 17:32 circuits
drwxrwsr-x  7 root www-data 4.0K Aug  9 17:32 dcim
drwxrwsr-x  8 root www-data 4.0K Aug  9 17:32 extras
-rwxrwsr-x  1 root www-data  305 Aug  8 13:16 generate_secret_key.py
drwxrwsr-x  7 root www-data 4.0K Aug  9 17:32 ipam
-rwxrwsr-x  1 root www-data  249 Aug  8 13:16 manage.py
drwxrwsr-x  3 root www-data 4.0K Aug  8 13:16 media
drwxrwsr-x  3 root www-data 4.0K Aug  9 17:32 netbox
drwxrwsr-x  8 root www-data 4.0K Aug  8 13:16 project-static
drwxrwsr-x  2 root www-data 4.0K Aug  8 13:16 reports
drwxrwsr-x  9 root www-data 4.0K Aug  9 17:32 secrets
drwxr-sr-x 14 root www-data 4.0K Aug  9 17:32 static
drwxrwsr-x 14 root www-data 4.0K Aug  8 13:16 templates
drwxrwsr-x  6 root www-data 4.0K Aug  9 17:32 tenancy
drwxrwsr-x  5 root www-data 4.0K Aug  9 17:32 users
drwxrwsr-x  6 root www-data 4.0K Aug  9 17:32 utilities
drwxrwsr-x  7 root www-data 4.0K Aug  9 17:32 virtualization
netbox@netbox:~$ python3 /opt/netbox/netbox/manage.py
Traceback (most recent call last):
  File "/opt/netbox/netbox/manage.py", line 8, in <module>
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

Oh, that's an issue isn't it? Another issue I suspected, but this confirmed it. ModuleNotFoundError: No module named 'django' means that it wasn't just gunicorn that needed to be installed specially somewhere. Using pip3 install -r requirements.txt only installed the requirements for malachite@netbox rather than system-wide. I had to use sudo pip3 install gunicorn --install-option="--install-scripts=/usr/bin" -t python_modules/ specifically because gunicorn wasn't being installed to /usr/bin/.

This has actually been an issue I have run into generally. Pip and Pip3 do not function the way developers are expecting it to on Ubuntu 18.04.1 LTS. They do not seem to be installed with python3-setuptools as implied by other documentation, and python3-pip has been a pain when it comes to installing modules.

This page from the official documentation says that there is a possibility that pip isn't installed by default in some cases.

Before I blow away my installation and reset this, let's see if running pip3 install -r requirements.txt with sudo will change where the packages are installed...

malachite@netbox:/opt/netbox$ sudo pip3 install -r requirements.txt
The directory '/home/malachite/.cache/pip/http' or its parent directory is not owned by the current user and the cache has been disabled. Please check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
The directory '/home/malachite/.cache/pip' or its parent directory is not owned by the current user and caching wheels has been disabled. check the permissions and owner of that directory. If executing pip with sudo, you may want sudo's -H flag.
Requirement already satisfied: Django<2.1,>=1.11 in /home/malachite/.local/lib/python3.6/site-packages (from -r requirements.txt (line 1))
Requirement already satisfied: django-cors-headers==2.4.0 in /home/malachite/.local/lib/python3.6/site-packages (from -r requirements.txt (line 2))
Requirement already satisfied: django-debug-toolbar==1.9.1 in /home/malachite/.local/lib/python3.6/site-packages (from -r requirements.txt (line 3))
...

Alright, so pip3 is installing everything to /home/malachite/.local/lib/python3.6/site-packages. This is why when www-data attempts to execute the scripts it fails. Also, I know that www-data in particular is attempting to execute these scripts because in the supervisord documentation it states:

user
Instruct supervisord to use this UNIX user account as the account which runs the program. The user can only be switched if supervisord is run as the root user. If supervisord can’t switch to the specified user, the program will not be started.

Continuing to read the python documention, I have come across something rather important here.

Warning Recent Debian/Ubuntu versions have modified pip to use the “User Scheme” by default, which is a significant behavior change that can be surprising to some users.

Doing further digging I decided to look at some comparisons. Checking installed python3 modules on malachite@netbox:

malachite@netbox:~$ python3 -m pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
asn1crypto (0.24.0)
attrs (17.4.0)
Automat (0.6.0)
bcrypt (3.1.4)
blinker (1.4)
certifi (2018.4.16)
cffi (1.11.5)
chardet (3.0.4)
click (6.7)
cloud-init (18.3)
colorama (0.3.7)
command-not-found (0.3)
configobj (5.0.6)
constantly (15.1.0)
coreapi (2.3.3)
coreschema (0.0.4)
cryptography (2.3)
distro-info (0.18)
Django (2.0.8)
...

Versus installed python3 modules on netbox@netbox

netbox@netbox:~$ python3 -m pip list
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
asn1crypto (0.24.0)
attrs (17.4.0)
Automat (0.6.0)
blinker (1.4)
certifi (2018.1.18)
chardet (3.0.4)
click (6.7)
cloud-init (18.3)
colorama (0.3.7)
command-not-found (0.3)
configobj (5.0.6)
constantly (15.1.0)
cryptography (2.1.4)
distro-info (0.18)
httplib2 (0.9.2)
hyperlink (17.3.1)
idna (2.6)
incremental (16.10.1)
Jinja2 (2.10)
jsonpatch (1.16)
...

I decided to go to this specific level because we see some differences. User malachite@netbox in just this top section of modules has the followind additional packages:

bcrypt (3.1.4)
cffi (1.11.5)
coreapi (2.3.3)
coreschema (0.0.4)
Django (2.0.8)
...

And more. This means that python packages are being installed per user, and since www-data doesn't have a shell, let a lone a home directory, it cannot use any non-system packages for python3.

So I am going to try to cheat, here.

malachite@netbox:~$ sudo su - root
root@netbox:~# pip3 install -r /opt/netbox/requirements.txt

Now let's restart supervisor and see what we get...

malachite@netbox:~$ service supervisor status
● supervisor.service - Supervisor process control system for UNIX
   Loaded: loaded (/lib/systemd/system/supervisor.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-08-09 19:53:04 UTC; 6s ago
     Docs: http://supervisord.org
  Process: 52035 ExecStop=/usr/bin/supervisorctl $OPTIONS shutdown (code=exited, status=0/SUCCESS)
 Main PID: 52036 (supervisord)
    Tasks: 2 (limit: 972)
   CGroup: /system.slice/supervisor.service
           ├─52036 /usr/bin/python /usr/bin/supervisord -n -c /etc/supervisor/supervisord.conf
           └─52080 python3 /opt/netbox/netbox/manage.py rqworker

Aug 09 19:53:07 netbox supervisord[52036]: 2018-08-09 19:53:07,220 INFO spawned: 'netbox' with pid 52071
Aug 09 19:53:07 netbox supervisord[52036]: 2018-08-09 19:53:07,221 INFO success: netbox-rqworker entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Aug 09 19:53:07 netbox supervisord[52036]: 2018-08-09 19:53:07,756 INFO exited: netbox (exit status 1; not expected)
Aug 09 19:53:07 netbox supervisord[52036]: 2018-08-09 19:53:07,772 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 19:53:08 netbox supervisord[52036]: 2018-08-09 19:53:08,775 INFO spawned: 'netbox-rqworker' with pid 52073
Aug 09 19:53:09 netbox supervisord[52036]: 2018-08-09 19:53:09,779 INFO spawned: 'netbox' with pid 52078
Aug 09 19:53:09 netbox supervisord[52036]: 2018-08-09 19:53:09,779 INFO success: netbox-rqworker entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Aug 09 19:53:10 netbox supervisord[52036]: 2018-08-09 19:53:10,239 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 19:53:10 netbox supervisord[52036]: 2018-08-09 19:53:10,255 INFO spawned: 'netbox-rqworker' with pid 52080
Aug 09 19:53:10 netbox supervisord[52036]: 2018-08-09 19:53:10,292 INFO exited: netbox (exit status 1; not expected)

That is a new error. netbox-rqworker entered running state and stayed up for more than 1 second. Now, on the incredibly small off chance that it works. The log shows that it started to work, but crashed immediately after. The web page wasn't able to load, but we're closer. It's now very unstable unstable rather than dead. This is suprisingly a very good sign. Back under root@netbox, let's run pip3 install gunicorn just in case.

Aug 09 20:02:16 netbox systemd[1]: Stopped Supervisor process control system for UNIX.
Aug 09 20:02:16 netbox systemd[1]: Started Supervisor process control system for UNIX.
Aug 09 20:02:16 netbox supervisord[53810]: 2018-08-09 20:02:16,993 CRIT Supervisor running as root (no user in config file)
Aug 09 20:02:16 netbox supervisord[53810]: 2018-08-09 20:02:16,995 INFO Included extra file "/etc/supervisor/conf.d/netbox.conf" during parsing
Aug 09 20:02:17 netbox supervisord[53810]: 2018-08-09 20:02:17,003 INFO RPC interface 'supervisor' initialized
Aug 09 20:02:17 netbox supervisord[53810]: 2018-08-09 20:02:17,003 CRIT Server 'unix_http_server' running without any HTTP authentication checking
Aug 09 20:02:17 netbox supervisord[53810]: 2018-08-09 20:02:17,003 INFO supervisord started with pid 53810
Aug 09 20:02:18 netbox supervisord[53810]: 2018-08-09 20:02:18,006 INFO spawned: 'netbox' with pid 53835
Aug 09 20:02:18 netbox supervisord[53810]: 2018-08-09 20:02:18,009 INFO spawned: 'netbox-rqworker' with pid 53836
Aug 09 20:02:19 netbox supervisord[53810]: 2018-08-09 20:02:19,559 INFO success: netbox entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Aug 09 20:02:19 netbox supervisord[53810]: 2018-08-09 20:02:19,559 INFO success: netbox-rqworker entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Aug 09 20:02:22 netbox supervisord[53810]: 2018-08-09 20:02:22,674 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 20:02:23 netbox supervisord[53810]: 2018-08-09 20:02:23,680 INFO spawned: 'netbox-rqworker' with pid 53869

Checking the web site, it was still down. Refreshed again a little after and it's back up. Let's check the status one last time.

Aug 09 20:03:55 netbox supervisord[53810]: 2018-08-09 20:03:55,914 INFO success: netbox-rqworker entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
Aug 09 20:03:56 netbox supervisord[53810]: 2018-08-09 20:03:56,167 INFO exited: netbox-rqworker (exit status 1; not expected)
Aug 09 20:03:57 netbox supervisord[53810]: 2018-08-09 20:03:57,170 INFO spawned: 'netbox-rqworker' with pid 54135
Aug 09 20:03:58 netbox supervisord[53810]: 2018-08-09 20:03:58,171 INFO success: netbox-rqworker entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)

So installing the requirements from pip3 from root@netbox actually works. Which means we can cut out a bunch of the things we tried but didn't succeed with and then we can blow it all away and check again.

WORKING STEPS

Here's the deployment, starting from a fresh install of Ubuntu 18.04.1 LTS as user malachite@netbox (we will have to su - root, but I try to avoid being there as much as possible).

sudo apt update ; sudo apt upgrade
sudo apt autoremove

sudo apt-get install -y postgresql libpq-dev
sudo -u postgres psql
CREATE DATABASE netbox;
CREATE USER netbox WITH PASSWORD 'XY,gTr6GP-Xy';
GRANT ALL PRIVILEGES ON DATABASE netbox TO netbox;
\q

sudo apt-get install -y python3 python3-dev python3-setuptools build-essential libxml2-dev libxslt1-dev libffi-dev graphviz libpq-dev libssl-dev zlib1g-dev python3-pip

wget https://github.com/digitalocean/netbox/archive/v2.4.2.tar.gz
sudo tar -xzf v2.4.2.tar.gz -C /opt/
cd /opt/
sudo ln -s netbox-2.4.2/ netbox

Use sudo su - root to switch to root in order to install the python modules we are going to need.

pip3 install -r /opt/netbox/requirements.txt
pip3 install gunicorn
exit

Back as malachite@netbox, continue:

cd /opt/netbox/netbox/netbox
sudo cp configuration.example.py configuration.py
python3 /opt/netbox/netbox/generate_secret_key.py > ~/secretkey

sudo vi configuration.py

configuration.py changes, using :read ~/secretkey to pull the secret key into the file:

ALLOWED_HOSTS = ['192.168.0.11']
DATABASE = {
    'NAME': 'netbox',
    'USER': 'netbox',
    'PASSWORD': 'XY,gTr6GP-Xy',
    'HOST': 'localhost',
    'PORT': '',
}

SECRET_KEY = 'J8g4+*aFfpV#2tGEPOSA%NriQx=Yvb_uWzKLy-U)0^w$Tl&5os'
rm ~/secretkey

cd /opt/netbox/netbox/
python3 manage.py migrate
python3 manage.py createsuperuser
sudo python3 manage.py collectstatic --no-input

sudo apt install -y nginx
sudo vi /etc/nginx/sites-available/netbox

/etc/nginx/sites-available/netbox contents:

server {
    listen 80;

    server_name 192.168.0.11;

    client_max_body_size 25m;

    location /static/ {
        alias /opt/netbox/netbox/static/;
    }

    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
    }
}

As malachite@netbox:

cd /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/netbox

sudo vi /opt/netbox/gunicorn_config.py

/opt/netbox/gunicorn_config.py contents:

command = '/usr/bin/gunicorn'
pythonpath = '/opt/netbox/netbox'
bind = '127.0.0.1:8001'
workers = 3
user = 'www-data'

Install Supervisor, to keep things running, I guess.

sudo apt install -y supervisor

sudo vi /etc/supervisor/conf.d/netbox.conf

/etc/supervisor/conf.d/netbox.conf contents:

[program:netbox]
command = gunicorn -c /opt/netbox/gunicorn_config.py netbox.wsgi
directory = /opt/netbox/netbox/
user = www-data

[program:netbox-rqworker]
command = python3 /opt/netbox/netbox/manage.py rqworker
directory = /opt/netbox/netbox/
user = www-data

Finally restart the service to get everything up and running.

service nginx restart
service supervisor restart

And now netbox should be running and available on the network!

Thoughts

The installation process was frustrating because I never log onto root@localhost unless I absolutely have to. This was the first instance I have encountered where I require things to be installed by root@localhost. So, things I've learned in summary:

  • Most documentation seems to assume that you just exist as root@localhost all the time, which is an awful assumption and an awful practice.
  • Python modules are installed into a user's home directory.
  • Supervisor as a service is run by root@localhost, and the user set in the conf file is only changed to using setuid, meaning that the program still uses all of root@localhost's environment variables (including where python modules are).
  • I misattributed the python module error to a permission error in accessing the folders. This was due to me assuming that the python modules were installed for everyone and not per user, and that Supervisor specifically ran programs as root@localhost. I found these things in the documentation.

Support the Author

Devon Taylor (They/Them) is a Canadian network architect, security consultant, and blogger. They have experience developing secure network and active directory implementations in low-budget and low-personnel environments. Their blog offers a unique and detailed perspective on security and game design, and they tweet about technology, security, games, and social issues. You can support their work via Patreon (USD), or directly via ko-fi.