Moms's picture

I am fairly new to Turkey so a lot of the lingo will likely go over my head but I do have a pretty good understanding of the basics and naviagting around it (PuTTy command interface).

I am trying to setup Turnkey Django but I really don't like working within the pre-built project they provide. The obnoxiously long file names are a pain not to mention as soon as you want to add a package or update something you go through a whole chain of troubleshooting just to get it working again. It's more work than it's worth. Also many of the Django design rules are broken so it's full of mental gymnastics tryin to translate Django Documentation into the Turnkey Django solution. So all I want to do it setup my own Django Project so I can build it from the ground up with my own file names. However as soon as I touch the django.conf file it just throws 404. So I am here asking for a some guidence to get it to work outside of the pre-built Django project.

All my databases, dependencies, packages and Django files are in working order within a virtualenv.

Here is what I am using and the versions:

  • PuTTy, SSH into the server (Windows 10 --SSH-> Linux)
  • virtualenv, contains the Django project and several packages
  • Django (2, 1, 6, 'final', 0)
  • Python 3.6.8
  • Turnkey GNU/Linux 9.6
  • sql_server.pyodbc with ODBC Driver 17 for SQL Server for MSSQL

So when I change django.conf in /root/etc/apache2/sites-available from the defualt:

   serverName localhost

   WSGIScriptAlias / /var/www/turnkey_project/turnkey_project/wsgi.py
   WSGIPythonPath /var/www/turnkey_project
   WSGIDaemonProcess django processes=1 threads=3
   WSGIProcessGroup django

   <VirtualHost *:80>
       UseCanonicalName Off
       ServerAdmin  webmaster@localhost
       DocumentRoot /var/www/turnkey_project/static
   </VirtualHost>

   <VirtualHost *:443>
       SSLEngine on
       ServerAdmin  webmaster@localhost
       DocumentRoot /var/www/turnkey_project/static
   </VirtualHost>

   Alias /static /var/www/turnkey_project/static
   <Location "/static">
       SetHandler None
   </Location>

   Alias /doc /usr/share/doc/python-django-doc/html
   <Location "/doc">
       SetHandler None
   </Location>

To what I assumed would work with my own file paths but does not:

   ServerName localhost

   WSGIScriptAlias / /var/www/sys/main/wsgi.py
   WSGIPythonPath /var/www/sys
   WSGIDaemonProcess django processes=1 threads=3
   WSGIProcessGroup django

   <VirtualHost *:80>
       UseCanonicalName Off
       ServerAdmin  webmaster@localhost
       DocumentRoot /var/www/sys/static
   </VirtualHost>

   <VirtualHost *:443>
       SSLEngine on
       ServerAdmin  webmaster@localhost
       DocumentRoot /var/www/sys/static
   </VirtualHost>

   Alias /static /var/www/sys/static
   <Location "/static">
       SetHandler None
   </Location>

   Alias /doc /var/www/sys/doc/html
   <Location "/doc">
       SetHandler None
   </Location>

So why does it throw a 404 when I navigate to my IP? Am I setting it up wrong or is Turnkey just too restrictive? Everything seems to be in working order but it just does not want to work.

I have an app in my Django project and for those who are familiar with Django and it's URL patterns will know it will automatically change the url from foo.com/bar to foo.com/bar/ (notice the suffixed '/'). When I "navigate" to my app it does apply this change automatically maybe suggesting Django is working properly but maybe my directories in my apache config isn't right or my file layout isn't correct (maybe).

Forum: 
Jeremy Davis's picture

FWIW, the default "TurnKey Django app" is only meant as a (super simple) "example app" and to provide a landing page for users launching the appliance. So in essence, you're "doing it right". :)

I should further note, that whilst my knowledge of Linux in general and TurnKey in particular is quite strong, I know next to nothing about Django and not that much more about Python (whilst I am getting much better with Python of late, my knowledge is still fairly rudimentary).

Having said all that, a 404 is server/file not found. The fact that you say that when you browse to your server, the URL appears to be being modified (i.e. the trailing '/' being added), suggests that it's not at all network related, but is likely related to you Apache config.

Beyond that, assuming that the path /var/www/sys/main/wsgi.py actually exists, it seems like a weird one. As a general rule, errors within Django itself (including Django config) are more likely to give you a 504 (when the Apache server can't connect to your python backend). Again that makes me suspect that it is related to your Apache config.

So a couple of quick thoughts. How have you created this new Apache config? Did you overwrite the default django.conf? Or have you created a new Apache config file (and disabled the default one)? It sounds like the former, but either way, have you restarted Apache to apply the updated config? FYI most Linux services read their config at start and won't re-read config to apply any changes unless you explicitly tell them to.

So even though it likely doesn't apply, if you have created a new Apache config file for your app (e.g. /etc/apache2/sites-available/new-app.conf) you would need to disable the default site config and enable your new site config, and finally restart Apache:

a2sdissite django
a2ensite new-app
service apache2 restart

Assuming that you've done that and it still isn't working, the next step I'd take is to check the Apache error log. Hopefully that will provide some insight into what might be going wrong. The (default) error file should be found at: /var/log/apache2/error.log. To get the last few lines of it (most likely what you want:

tail /var/log/apache2/error.log

Hopefully that might give you some ideas on what is going on. Please feel free to post it if you want me to provide some input (although I'm not sure how useful that might be...)

The other thing that jumps out at me (although not at all sure if this is related to this issue or not) is that you note the following:

  • virtualenv, contains the Django project and several packages
  • Django (2, 1, 6, 'final', 0)
  • Python 3.6.8

The virtualenv bit sounds all good, but have you installed Python 3.6 yourself? TurnKey v15.x ships with the Debian 9/Stretch default Python 3.5.3 and AFAIK (I could be wrong here) to use Python 3.6, regardless of virtualenv (unless there is someway to actually install it within the virtualenv itself that I'm unaware of?) you'd have to install that on your server and ensure that it's available in your path.

Also, the TurnKey Django appliance ships with the Debian Django package, which is v1.10.7 (FWIW v1.11.18 is in backports, but that seems irrelevant here). AFAIK, there is nothing stopping you from using a newer version of Django (e.g. install via pip), but it possibly be better to remove the default bundled one to avoid risk of confusion (although using a venv should solve that really I guess).

I hope that all makes sense. If you want me to elaborate on anything, please ask.

Moms's picture

Thank you for the welcome :)

I am not at my computer right now and won't likely be able to try them out until tomorrow. However thank you for responding.

 

To answer some of your questions and points first:

"Having said all that, a 404 is server/file not found."

 

"Suggests that it's not at all network related."

Correcrt. I should have clarified that. I am definitely connecting to the server.

 

"Did you overwrite the default django.conf?"

No. I simply saved the default as a different name (django-default.conf) to disable it. (yes, sites-enabled is updated with the new config) then I made a new config file (django.conf) with the new settings. So the original still exists, just under a different name. btw django.conf was always the default name.

"Restarted Apache to apply the updated config?"

Yes. 

 

"You would need to disable the default site config and enable your new site config, and finally restart Apache"

$ a2sdissite django

$ a2ensite new-app  

$ service apache2 restart

I will try this first thing in the morning.
 

"Check the Apache error log."

I did It fairly recently but always worth another look.

 

"Have you installed Python 3.6 yourself?"

Yes. I am using Pyenv. It's a python version manager so I have a few python versions installed however 3.6 is set globally. And yes I tested the example app with 3.6 and it worked fine. 

 

"TurnKey Django appliance ships with the Debian Django package."

Yes. I did upgrade the Debian Django package to 2.1 to test out the MSSQL packages to see if they work. And it worked as intended. However it still exists on the sytem and has not been unistalled. And yes I too assume venv isolates it well enough.

 

Thank you again for responding. Ill be sure to update this thread tomorrow after I tried you're solutions.

Jeremy Davis's picture

Ok, it sounds like you know more about Django than me! :)

Judging from your post, there's nothing obvious that I can come back with. The only thing that would occur is perhaps somehow the incorrect Apache conf file is enabled. Following what you posted, it shouldn't be, but perhaps...

Rather than following my a2dissite/a2ensite commands, instead I suggest that you check double check that the correct symlinks are in place within Apache's config dir. TBH, I doubt it will be an issue there as it seems you've essentially just edited the default conf file and restarted Apache (so no sites should need to be enabled/disabled).

If you check the sites-enable directory (with 'ls -l'), you should see something like this:

# ls -l /etc/apache2/sites-enabled/
total 0
lrwxrwxrwx 1 root root 32 Jan 22 23:51 django.conf -> ../sites-available/django.conf

Although the date will be a little older... :)

Assuming you have that already (and sites-available/django.conf contains what you posted previously) and you've restarted Apache (all as you've already indicated), TBH, I'm stumped already...

The issue you report certainly seems like a relatively simple Apache misconfiguration, but I'm not seeing any obvious issues in your described setup...

Hopefully the Apache logs should shine some light on it, although if you've already checked them, I'm not as confident as I was...

Jeremy Davis's picture

I hope this isn't the issue, but it appears that Debian's Apache mod_wsgi is compiled against a specific version of Python. In the case of TurnKey, we use the one provided by Debian (the package is called libapache2-mod-wsgi-py3. Being Debian, that is complied against the default Python3 - 3.5.3. I'm not at all sure that is the issue, but it certainly seems possible.

The 2 workarounds that I can think of would be:

  1. download the Debian source package of mod_wsgi and recompile it against Python3.6; or
  2. use some alternate server for running your app.

I suspect that 2 would likely be more straight forward. A quick google turned up this page which notes a few options (although no doubt there are more). I know that Gunicorn is quite popular. If you use one of those, you'll most likely still want to use Apache as the "primary" web server, but simply as a reverse proxy for whatever is actually running your Django app.

It seems that in your usage scenario, our Django server hasn't really been all that TurnKey... Perhaps we should consider looking at the alternate available options and include one OOTB?

Actually... just before I hit save on this post, I came across the pip mod_wsgi package. It looks like you might want to uninstall the default Debian mod_wsgi Apache module and install via pip. Hopefully that will at least give you some progress...

Also FWIW, I did come across quite a few "Django 404" post on Stack Overflow (etc) but nothing really jumped out at me as worth sharing, but perhaps worth a google if you continue to struggle (FWIW as you've probably already guessed, TurnKey v15.x is based on Debian 9/Stretch).

Moms's picture

I made a fresh instance. I wont lie, my current one was getting very messy because I have been mostly testing a bunch of different things without much care. I have installed everything and setup everything the way it was before. With the acception of some file paths but that's all relative. I am just going to use Python 3.5.3 instead of 3.6.x as the former seems more "consistant" with this turnkey solution as it's pre installed and should work fine for what I want to do.

But this time instead of a 404 I am not getting a 500 however my error logs are looking more useful now:

[Thu Jan 24 02:19:30.202396 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module
[Thu Jan 24 02:19:30.202424 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]     return _bootstrap._gcd_import(name[level:], package, level)
[Thu Jan 24 02:19:30.202470 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 986, in _gcd_import
[Thu Jan 24 02:19:30.202540 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 969, in _find_and_load
[Thu Jan 24 02:19:30.202658 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 944, in _find_and_load_unlocked
[Thu Jan 24 02:19:30.202715 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
[Thu Jan 24 02:19:30.202765 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 986, in _gcd_import
[Thu Jan 24 02:19:30.202814 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 969, in _find_and_load
[Thu Jan 24 02:19:30.202862 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124]   File "<frozen importlib._bootstrap>", line 956, in _find_and_load_unlocked
[Thu Jan 24 02:19:30.202946 2019] [wsgi:error] [pid 8772:tid 139891022157568] [remote 192.168.100.177:53124] ImportError: No module named 'dj'

 I will surf the web for some info on what these error mean and keep you updated but they are here is you have any ideas.

I also tried

pip install mod_wsgi

but I just got this error

Collecting mod_wsgi
  Using cached https://files.pythonhosted.org/packages/47/69/5139588686eb40053f8355eba1...
    Complete output from command python setup.py egg_info:
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-ei82qgxx/mod-wsgi/setup.py", line 168, in <module>
        'missing Apache httpd server packages.' % APXS)
    RuntimeError: The 'apxs' command appears not to be installed or is not executable. Please check the list of prerequisites in the documentation for this package and install any missing Apache httpd server packages.

    ----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-ei82qgxx/mod-wsgi/
 

Jeremy Davis's picture

I'm not so familiar with Django, but I play with Python a bit. Assuming that the stacktrace from the Apache log is consistent with a "normal" python stacktrace, it looks like it can't find a module (that I assume you're importing somewhere) called 'dj'.

I have no idea whether that should be a part of Django or something custom you've included ('dj' is suspiciously the first letters of Django, but that may be coincidental).

It's probably worth providing a little more info re default Apache WSGI integration. If you are happy to run with Python 3.5 (as per installed by default) then it should "just work". Our Django appliance comes pre-installed with the Apache WSGI module compiled against the default Python3.

According to the pypi page for mod_wsgi it looks like if you want to install via pip, then you'll also need to install the development Apache package. To quote the page:

If you are running Debian or Ubuntu Linux with Apache 2.4 system packages, regardless of which Apache MPM is being used, you would need both:
  • apache2
  • apache2-dev
  • Apache2 is (obviously) already installed, so you'll just need to install that dev package. Do that like this:

    apt update
    apt install apache2-dev
    

    Perhaps also worthy of note, assuming that you are ok with using the system-wide Debian pip package for Python3, you should be able to use that like this:

    pip3 install mod_wsgi

    It is possible that pip3 is not pre-installed (it probably should be though). So if the above gives an error, install pip3 like this:

    apt update
    apt install python3-pip
    

    Although as I note above, none of that should be required if you're ok with using Python 3.5, as the default pre-installed mod_wsgi should do the trick.

    As something of an aside, but perhaps useful FYI, by default in Debian 'python' is Python2 (2.7). If you want Python3, then you need to explicitly invoke it with python3. Also a number of Python libraries are packaged and pre-tested for use in Debian. They will almost always be older that you'll get on Pypi, but can be a good option if they suit your purpose. Generally their names are (assuming you want the python3 variant) 'python3-<lib-name>. The Debian package search page can be a really useful resource for finding Debian pacakges.

    Hope that helps.

    Moms's picture

    Thank you for responding again! I my self am not too familiar with Django, I am setting up this environment to learn it myself. That module called 'dj' was infact just the name of my project hence also the name of a "module", so you're right, it does stand for 'Django'. I jump around the files alot in a cli so I just like the short names to make my life a little easier. 

    I tried your commands to get mod_wsgi up to update through pip and it worked fine. Thank you! And as software is the gift that keeps on giving it gave us a new set of errors:

    [Thu Jan 24 21:33:39.089834 2019] [wsgi:error] [pid 17860:tid 139625512974080] [remote 192.168.100.177:52788]   File "/usr/lib/python3/dist-packages/django/__init__.py", line 27, in setup
    [Thu Jan 24 21:33:39.089863 2019] [wsgi:error] [pid 17860:tid 139625512974080] [remote 192.168.100.177:52788]     apps.populate(settings.INSTALLED_APPS)
    [Thu Jan 24 21:33:39.089911 2019] [wsgi:error] [pid 17860:tid 139625512974080] [remote 192.168.100.177:52788]   File "/usr/lib/python3/dist-packages/django/apps/registry.py", line 78, in populate
    [Thu Jan 24 21:33:39.089940 2019] [wsgi:error] [pid 17860:tid 139625512974080] [remote 192.168.100.177:52788]     raise RuntimeError("populate() isn't reentrant")
    [Thu Jan 24 21:33:39.090014 2019] [wsgi:error] [pid 17860:tid 139625512974080] [remote 192.168.100.177:52788] RuntimeError: populate() isn't reentrant
    [Thu Jan 24 21:34:09.361930 2019] [mpm_event:notice] [pid 17856:tid 139625635292352] AH00491: caught SIGTERM, shutting down
    [Thu Jan 24 21:34:09.553872 2019] [ssl:warn] [pid 24962:tid 140426591794368] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
    [Thu Jan 24 21:34:09.603748 2019] [ssl:warn] [pid 24963:tid 140426591794368] AH01909: localhost:443:0 server certificate does NOT include an ID which matches the server name
    [Thu Jan 24 21:34:09.606773 2019] [mpm_event:notice] [pid 24963:tid 140426591794368] AH00489: Apache/2.4.25 (Debian) OpenSSL/1.0.2q mod_wsgi/4.5.11 Python/3.5 configured -- resuming normal operations
    [Thu Jan 24 21:34:09.606854 2019] [core:notice] [pid 24963:tid 140426591794368] AH00094: Command line: '/usr/sbin/apache2'

    Originally it was just a bunch of mssql errors but I squished them fairly easily but these errors seem so abstract compared to the previous ones.

    FYI, by default in Debian 'python' is Python2 (2.7). If you want Python3, then you need to explicitly invoke it with python3.

    Thank you checking my back but I do have Python 3.5.3 sym linked correctly so I am not playing mental gymanastics.

    Jeremy Davis's picture

    As a general rule, I try to respond to new posts at least daily (although on occasion that does drop off; but you should see me around at least once per week).

    Re mod_wsgi, as I mentioned, if you are ok using the default Python3.5, then the mod_wsgi package that comes pre-installed should "just work" OOTB. Using the mod_wsgi package via pip should only be required if you are using an alternate version of Python3.

    So assuming you continue with the default Python3(.5) supplied by Debian, I'd recommend removing the pip installed mod_wsgi (hopefully it will clean up after itself when you remove it - although an Apache restart is likely required).

    If you'd instead rather persevere with the pypi mod_wsgi, then you'll likely want to remove the default Debian mod_wsgi package (or at least disable it) - so Apache doesn't get confused; and you can be sure which one you're using. I probably should have mentioned that sooner. It is possible that part of the install process that you've run through did that for you, but I can't be 100% sure... (You're in uncharted territory for me).

    To remove the default Debian mod_wsgi package:

    apt remove libapache2-mod-wsgi-py3

    Also after loading/install/enabling/disabling Apache modules, you'll need to restart Apache (you've possibly already done that, but just in case):

    service apache2 restart
    Thank you checking my back but I do have Python 3.5.3 sym linked correctly so I am not playing mental gymanastics.

    You're welcome! :) Also assuming that you have installed pip3 (i.e. python3-pip) as I noted, you may want to symlink that (to pip) too? Although if you install pip (for Python 3) some other way, then that's probably irrelevant.

    Re the new error message you're getting, TBH I have no idea. First up, I'd try restarting Apache (AFAIK it will cache python files; plus that will ensure that you have all the modules loaded as per above). Although I note from the log you posted, either you have restarted it since the error. Or perhaps it restarted itself?

    A quick google turned up this Stack Overflow Q&A which has a heap of different things you could consider. Actually, this answer (to a very similar question) looks like it provides a much more structured method to trying to troubleshoot and understand the underlaying issue - I'd start there myself. FYI I found those posts (and much much more!) googling the error message:

    raise RuntimeError("populate() isn't reentrant"

    (FWIW I also tried 'RuntimeError: "populate() isn't reentrant"' but the above gave better results).

    Moms's picture

    I don't have time to explain it now but next week I will be sure to provide a detailed tutorial on what I did to get it to work. It's the Aussie day long weekend and bevvies, snags, backyard cricket and apache troubleshooting don't go hand in hand too well.

    It will be a tutorial on how to set up your Turnkey Django to work with MSSQL.

    Thank you Jeremy Davis for all your help. Happy Australia Day!

     

    Jeremy Davis's picture

    Unless you need MSSQL, you're better off sticking with the default DB server that we ship with Django (MySQL/MariaDB). If you do that, then you should be able to follow many Django tutorials that you can find online.

    The only reason you should need MSSQL is if you have an existing Django app that requires it. Whilst you can install MSSQL, you'll find MySQL is plenty good enough, scales well and will be easier to maintain on Linux.

    Add new comment