Django Numpy ImportError with Apache but not on runserver - django

I've tried every other thread and their suggested solutions but without success so far.
I have a Django app with a virtualenv and Apache 2.4 and mod_wsgi, which i developed on other server. Now, I'm migrating (rebuilding from scratch) everything on another server.
While everything else works, when i tried to install pandas, the app served through Apache throws me an ImportError for Numpy.
Original error was: /optilab/env/lib64/python3.6/site-packages/numpy/core/_multiarray_umath.cpython-36m-x86_64-linux-gnu.so:
failed to map segment from shared object
Thing is, this doesn't happen while using runserver with manage.py . Everything is the same: Python Version (3.6.8), Python Executable (/optilab/env/bin/python) except the Python Path order.
For the testing runserver, this is the Python Path list:
['/optilab',
'/optilab/env/lib64/python3.6/site-packages',
'/usr/lib64/python36.zip',
'/usr/lib64/python3.6',
'/usr/lib64/python3.6/lib-dynload',
'/optilab/env/lib64/python3.6/site-packages',
'/optilab/env/lib/python3.6/site-packages',
'/home/appuser/.local/lib/python3.6/site-packages',
'/usr/local/lib64/python3.6/site-packages',
'/usr/local/lib/python3.6/site-packages',
'/usr/lib64/python3.6/site-packages',
'/usr/lib/python3.6/site-packages',
'/env/lib64/python3.6/site-packages']
But, for the app served through Apache, the Python Path is:
['/optilab',
'/optilab/core',
'/usr/lib64/python36.zip',
'/usr/lib64/python3.6',
'/usr/lib64/python3.6/lib-dynload',
'/optilab/env/lib64/python3.6/site-packages',
'/optilab/env/lib/python3.6/site-packages',
'/usr/local/lib64/python3.6/site-packages',
'/usr/local/lib/python3.6/site-packages',
'/usr/lib64/python3.6/site-packages',
'/usr/lib/python3.6/site-packages']
I suspect that the list order is the culprit for this problem, but it seems i'm not able to change it.
My file structure is the following:
/optilab
/core <-- startproject directory
/env <-- virtualenv files
/static
/media
... other apps
This is the first part of my apache config (BTW, I tried with python-path in WSGIDaemonProcess but didn't help):
WSGIPythonPath /optilab/env/lib64/python3.6/site-packages:/optilab/env/lib/python3.6/site-packages:/optilab:/optilab/core
<VirtualHost *:80>
ServerName optilab
WSGIDaemonProcess optilab python-home=/optilab/env
WSGIProcessGroup optilab
WSGIApplicationGroup %{GLOBAL}
WSGIScriptAlias / /optilab/core/wsgi.py
<Directory /optilab>
Require all granted
</Directory>
<Directory /optilab/core>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
....
I tried everything but nothing worked.

Related

How to deploy multiple django apps on apache in Windows?

I want to deploy multiple django apps on apache on Windows but only know how to deploy one.
Overriding the localhost of the Wamp Server I can deploy the app without problem but I need to deploy more and don't know how. I've sehen virtual hosts and think are good but don't know how to configurate them. Anyone know how can I do this? Thanks in advance.
hosting severel django apps with Apache is possible using virtual hosts (vhosts)
important to care about:
during config of Apache I recommend to start apache from command line as "httpd.exe" as in XAMPP or WAMP you will not see some of the initial start-up error messages in error.log files.
you can only use 1 python version even in different virt.env for each vhost as apache module mod_wsgi compilation needs to fit to it and is loaded once at startup of apache
something like this in httpd.conf (you should have this already in place because of your running single app config):
LoadFile "c:/.../python/python38/python38.dll"
LoadModule wsgi_module "c:/..../mod_wsgi.cp38-win_amd64.pyd"
for those starting from scratch:
activate virt.env.
> pip install mod_wsgi
> mod_wsgi-express module-config
will give above output (LoadFile ....) that you need to copy to httpd.conf
how to set path to virt.env and app folders:
with 1 host you would point to your virt.env by setting WSGIPythonHome and WSGIPythonPath to point to your app folders in httpd.conf:
WSGIPythonHome "d:/..../django_project/env_folder"
WSGIPythonPath "d:/..../django_project/app_name"
but: you can not place WSGIPythonHome/WSGIPythonPath inside the VirtualHost declaration in httpd-vhosts.conf .... it will cause an error message
Solution: set paths in wsgi.py dynamically and remove WSGIPythonHome/WSGIPythonPath from apache *.conf:
wsgi.py:
# replacement for WSGIPythonHome "d:/..../django_project/env_folder"
# choose one:
sys.path.append('d:/.../env_folder/lib/site-packages') # add individual virt.environment packages at the end of sys.path; global env packages have prio
sys.path.insert(0,'d:/.../env_folder/lib/site-packages') # add individual virt.environment packages at the beginning of sys.path; indiv. virt.env packages have prio over global env
# replacement WSGIPythonPath "d:/..../django_project/app_name"
sys.path.append('d:/.../django_project/app_name') # add indiv. app folder to search path
here is example for apache conf:
(why the dummy host: there is a (strange or buggy) behavior of apache ... if none of the virtual host names match the request, then automatically apache will dispatch the request to the first vhost in the config - no matter which server name is defined ther. This can lead to confusion because the total wrong app is called and an error messages will most certainly pop-up from inside django, not indicating that the error is on the Apache conf level. A dummy host with a simple index.html and an error message can make this tranparent)
httpd-vhost.conf:
<VirtualHost *:80>
ServerName Dumme_Host
DocumentRoot "d:/WEBSPACES/Dummy_Host"
<Directory d:/WEBSPACES/Dummy_Host>
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName xxxx1
WSGIScriptAlias / "d:/.... /wsgi.py" application-group=app_name1
Alias /media/ d:/.../media/
Alias /static/ d:/.../static/
<Directory d:/.../app_name1>
Require all granted
</Directory>
<Directory d:/.../media>
Require all granted
</Directory>
<Directory d:/.../static>
Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName xxxx2
WSGIScriptAlias / "d:/.... /wsgi.py" application-group=app_name2
Alias /media/ d:/.../media/
Alias /static/ d:/.../static/
<Directory d:/.../app_name2>
Require all granted
</Directory>
.....
</VirtualHost>

mod_wsgi: "No module named 'django'"

Maybe some needed context:
I installed python3.9 into a directory /opt/python39/. I compiled mod_wsgi with this version of python (as per this post) and was able to conduct a test to make sure that it was working correctly. I am not using a virtual environment.
I am trying to move my django project to production, so naturally, I am following the django docs. When I use the default file configurations at the very beginning, i.e.:
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonHome /opt/python39/bin/python3.9
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
It works (for the most part - there are resources missing on the page, but thats for another SO post) like a charm.
So I continue through the docs (which is now telling me that I should move it to "Daemon mode"):
“Daemon mode” is the recommended mode for running mod_wsgi (on non-Windows platforms). To create the required daemon process group and delegate the Django instance to run in it, you will need to add appropriate WSGIDaemonProcess and WSGIProcessGroup directives. A further change required to the above configuration if you use daemon mode is that you can’t use WSGIPythonPath; instead you should use the python-path option to WSGIDaemonProcess, for example:
So I change my file to look like:
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
#WSGIPythonHome /opt/python39/bin/python3.9
#WSGIPythonPath /path/to/mysite.com
WSGIDaemonProcess mysite.com python-home=/opt/python39/bin/python3.9 python-path=/path/to/mysite.com
WSGIProcessGroup mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
then run sudo apachectl restart, go back to my browser, refresh, shows 500 internal server error, check my logs, and "what do you know?" - ImportError: "No module named 'django'".
I've come across this SO article that seems to be describing my problem, but for virtual environments, and offers a solution, but I give it a go anyway:
WSGIProcessGroup mysite.com
WSGIDaemonProcess mysite.com python-home=/opt/python39 python-path=/path/to/mysite.com
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py process-group=iengravethat.com application-group=%{GLOBAL}
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
I rerun sudo apachectl restart, check my browser - same error, check the logs - same error.
I have tried a multitude of other configurations, but they all boil down to this error. Does anyone have any idea as to how to remedy this problem?
---UPDATE---
SUTerliakov and I opened up a channel for discussion, the end conclusion was thus:
Regarding recompilation - I was absolutely happy with the following installation (from Dockerfile, but it doesn't really matter):
pip install -U --no-cache-dir mod-wsgi
mod_wsgi-express install-module | tee /etc/apache2/mods-available/wsgi_express.load /etc/apache2/mods-available/wsgi_express.conf
And it can be done from venv too.
I really don't understand why did your paths stop working after
switching to daemon mode. I just suggest to try virtualenv instead,
because this method is recommended by maintainer.
You can just drop "tee" part and use standalone mod_wsgi-express install-module. It will print two lines of config, you can add them to your config file manually. It will print WSGIPythonHome, take this value and use for python-home option of WSGIDaemonProcess.
(may require root, AFAIR)
So, basically just create a venv and link it in your .conf file.
Create a virtual environment with the python interpreter you want to use and activate it.
pip install the packages you were using for django.
pip install mod-wsgi.
Grab the version of mod_wsgi you want.
untar it and enter the directory.
./configure --with-python=python3 (This python3 is the same version as the python3 I wanted - not python 3.6 which comes pre-installed on centos7).
make LDFLAGS='-L/path/to/venv/lib -Wl,-rpath,/path/to/venv/lib'.
sudo make install.
run mod_wsgi-express module-config and copy and paste it at the top of your .conf file.
deactivate your environment.
restart apache - sudo apachectl restart
I have the following config:
ServerName ${SERVER_NAME}
ServerAdmin ${SERVER_ADMIN}
<IfModule unixd_module>
User ${APP_USER}
Group ${APP_USER}
</IfModule>
WSGIRestrictEmbedded On
WSGIPassAuthorization On
IncludeOptional /etc/apache2/conf.d/*.conf
Timeout 60
<VirtualHost *:80>
Redirect permanent / https://${SERVER_NAME}/
</VirtualHost>
<VirtualHost *:443>
Alias /media <media folder>
<Directory <media_folder> >
Options -Indexes
Require all granted
</Directory>
Alias /static <static_folder>
<Directory <static_folder> >
Options -Indexes
Require all granted
</Directory>
WSGIDaemonProcess <name> processes=1 threads=5 display-name=%{GROUP} home=<top_folder>
WSGIScriptAlias / <wsgi.py path> process-group=<name> application-group=%{GLOBAL}
... SSL config here ...
</VirtualHost>
It is not a full config: logging, SSL and WebSocket proxies are thrown away.
<name> is any alias
<top_folder> is folder with manage.py file
<wsgi.py path> is <top_folder>/something/wsgi.py
<media_folder> and <static_folder> are paths of MEDIA_ROOT and STATIC_ROOT settings.
It is deployed with docker (system-level package installation as root, no virtual environment).
Final attempt
Probably something gets messed up when using system python that is not the default interpreter. You can set up virtual environment and make httpd use it. To avoid manual recompilation, mod_wsgi pip package can be used:
# With venv activated
pip install mod_wsgi
sudo mod_wsgi-express install-module
This will install mod_wsgi for venv python and print two lines of config: LoadModule ... and WSGIPythonHome <path>. You can add LoadModule to configuration file and use the following daemon config:
WSGIDaemonProcess mysite.com home=/path/to/mysite.com python-home=<venv_root>
Note
You don't need to recompile mod_wsgi manually with this package, it is the most amazing aspect of such installation! Two commands above are sufficient to install mod_wsgi. It will copy module files to required folders for you (see end of this readme), so your steps 4-8 can be omitted.

Django Apache2 VirtualEnv - no response from server

So I am trying to migrate my app to a new production server. I'm not getting a reply from the server Apache server when I access it. The server is on AWS and it's a standard Apache config with just one site enabled:
<VirtualHost *:80>
Alias /static/ /home/ubuntu/myapp/myapp/myapp/static
Alias /media/ /home/ubuntu/myapp/myapp/myapp/media
<Directory /home/ubuntu/myapp/myapp/myapp/static>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp/media>
Require all granted
</Directory>
<Directory /home/ubuntu/myapp/myapp/myapp>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
WSGIDaemonProcess myapp python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
WSGIProcessGroup myapp
WSGIScriptAlias / /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
ErrorLog /var/log/apache2/myapp_error.log
LogLevel warn
CustomLog /var/log/apache2/myapp_access.log combined
</VirtualHost>
I have made sure that all files are owned by the ubuntu user and that www-data has group rights.
The wsgi file is the original, but I added a print statement to see the folder it's checking for the application:
"""
WSGI config for match2 project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
"""
import os, sys
print(sys.path)
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings")
application = get_wsgi_application()
Eventually, the error log will produce:
Timeout when reading response headers from daemon process 'myapp': /home/ubuntu/myapp/myapp/myapp/myapp/wsgi.py
I'd appreciate any advice.
Timeout when reading response headers from daemon process 'myapp' means your application is taking to long to handle the request. This could be because it is deadlocked, or is waiting on backend service.
Add WSGIApplicationGroup to your virtual host configuration.
<VirtualHost *:80>
# config remaining parts
WSGIApplicationGroup %{GLOBAL}
# config remaining parts
</VirtualHost>
From docs
... forces the WSGI application to run in the main Python interpreter context of each process. This is preferred in this scenario as some third party packages for Python which include C extensions will not run in the Python sub interpreter contexts which mod_wsgi would use by default. By using the main Python interpreter context you eliminate the possibility of such third party packages for Python causing problems.
A similar case link.
Also:
Looking at this,
python-home=/home/ubuntu/myapp/myapp/myapp python-path=/home/ubuntu/myapp:/home/ubuntu/myapp/lib/python3.6/site-packages
I think you have the wrong path for python-home. Make sure python-home path is correctly provided. Activate your virtual environment and run the command to get the python-home path [docs].
python -c 'import sys; print(sys.prefix)'

Deploying Django on Apache with mod_wsgi

I'm currently trying to set up a Django application on Apache on a Centos server, with the use of mod_wsgi. This is set up to run on https. It is on virtualenv.
However, currently it gives a 504 Gateway Timeout error.
Error log:
(2)No such file or directory: mod_wsgi (pid=15007): Unable to stat Python home /bin/virtualenv:/var/www/django/mysite/mysite/lib/python3.6/site-packages. Python interpreter may not be able to be initialized correctly. Verify the supplied path and access permissions for whole of the path.
Fatal Python error: Py_Initialize: Unable to get the locale encoding
ModuleNotFoundError: No module named 'encodings'
httpd.conf
<VirtualHost *:443>
ServerName mysite.example.com
ServerAlias www.mysite.example.com
# DocumentRoot /var/www/django/mysite
LogLevel info
ErrorLog /etc/httpd/logs/mysite_error.log
Alias /static /var/www/django/mysite/static
<Directory /var/www/django/mysite/static>
Require all granted
</Directory>
<Directory /var/www/django/mysite/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
WSGIDaemonProcess mysite python-home=/bin/virtualenv:/var/www/django/mysite/mysite/lib/python3.6/site-packages
WSGIProcessGroup mysite
WSGIScriptAlias / /var/www/django/mysite/mysite/wsgi.py
WSGIApplicationGroup %{GLOBAL}
SSLEngine on
SSLProtocol all -SSLv2
SSLCompression off
SSLCertificateFile /etc/pki/tls/certs/mysite.cert.pem
SSLCertificateKeyFile /etc/pki/tls/private/mysite.key.pem
SSLCertificateChainFile /etc/pki/tls/certs/mysite.chain.pem
</VirtualHost>
This is incorrect:
WSGIDaemonProcess mysite python-home=/bin/virtualenv:/var/www/django/mysite/mysite/lib/python3.6/site-packages
Review:
http://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html
The python-home value should be a single directory, which is the same as sys.prefix for Python when using virtual environment. Do not added site-packages directory.
Most important, mod_wsgi must be compiled for same Python version as was used to create the virtual environment. You can't use mod_wsgi compiled for Python 2.7 with virtual environment created with Python 3.6.
Check what version of Python mod_wsgi was compiled for using:
http://modwsgi.readthedocs.io/en/develop/user-guides/checking-your-installation.html#python-installation-in-use

Serving files from Django using mod_wsgi and apache on CentOS 6.8

I have a django web application which I need to serve from an apache server on CentOS 6.8. In order to get this, I´m using mod_wsgi.
I have my project located in /path/to/myproject.
Right there I have the following directories and files:
- app1/
- db.sqlite3
- myproject/
- myprojectenv/
- manage.py
- static/
I have added to my setting.py this directive: STATIC_ROOT = os.path.join(BASE_DIR, "static/") and I´ve tried to run the django server and I can see my app view correctly.
So, after that I´ve tried to configure apache server in order to send a petition from my browser to my app, but apache rises a 403 Forbidden error.
The steps that I followed are:
- Add to httpd.conf the following information:
<VirtualHost *:80>
Alias /static /path/to/myproject/static
Alias /app1 /path/to/myproject/app1
<Directory /path/to/myproject/static>
Order allow,deny
Allow from all
</Directory>
<Directory /path/to/myproject/app1>
Order allow,deny
Allow from all
</Directory>
<Directory /path/to/myproject/myproject>
<Files wsgi.py>
Order allow,deny
Allow from all
</Files>
</Directory>
WSGIDaemonProcess myproject user=myuser group=mygroup python-path=/path/to/myproject:/path/to/myproject/myprojectenv/lib/python2.7/site-packages
WSGIProcessGroup myproject
WSGIScriptAlias / /path/to/myproject/myproject/wsgi.py
</VirtualHost>
Then, I gave rights to apache user, in order to allow apache to have access to my django project:
- sudo usermod -a -G myuser apache
- chmod 710 /home/myuser
- chmod 664 ~/myproject/db.sqlite3
- sudo chown :apache ~/myproject/db.sqlite3
- sudo chown :apache ~/myproject
Finally, I restarted the htttpd service and tried to send a petition to my app, but I got a "403 Forbidden error".
After that, I tried to copy my django project to the apache directory /var/www/ and doing this, I finnaly could see my django files but just like files, apache couldn´t run my app and show my view correctly.
I think that the problem could be about the permissions of apache user but I don´t know what else I can do.
What am I doing wrong?
What is the actual error in the Apache error log, not the 403 error in the browser?
Most likely the problem is due to your home directory being 710. This means an other user such as the Apache user cannot see into your home directory. It needs to be able to do that as the Apache user to map the URL to the WSGI application.
Either move your whole project outside of your home directory, or create a separate WSGI script file called myproject.wsgi under /var/www/myproject or similar, which has in it:
from myproject.wsgi import application
Also change:
WSGIScriptAlias / /path/to/myproject/myproject/wsgi.py
<Directory /path/to/myproject/myproject>
<Files wsgi.py>
Order allow,deny
Allow from all
</Files>
</Directory>
to:
WSGIScriptAlias / /var/www/myproject/myproject.wsgi
<Directory /var/www/myproject>
<Files myproject.wsgi>
Order allow,deny
Allow from all
</Files>
</Directory>
The Apache user only needs to be able to see the WSGI script file when doing URL mapping. The application code will actually run in your case under daemon mode with user myuser which presumably can read stuff from your home directory.
You didn't need to change ownership of your directory/files to Apache user, again because the code will run as myuser.