5

What am I missing? This is my first time trying to use Django. The server that is built into Django will serve the file locally just fine, but I can't get Apache to do the same. The following is what I'm doing from a brand new, clean, Linux 2 instance.

sudo yum update
sudo yum install -y python3
sudo yum install httpd-devel
sudo yum install -y mod_wsgi
cd /etc/httpd/modules     (verify that mod_wsgi is there)
cd /var/www/
sudo mkdir myApp
sudo chown ec2-user myApp
cd myApp
sudo pip3 install virtualenv
virtualenv myprojectenv
source myprojectenv/bin/activate
sudo pip3 install django==2.1.1
django-admin startproject myApp
cd myApp
python manage.py migrate
python manage.py runserver
wget http://127.0.0.1:8000/      (works correctly as it should and I receive test page)
python manage.py startapp hello
cd myApp
vim settings.py

settings.py: edit this part to look like this:

INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
     'django.contrib.staticfiles',
      'hello.apps.HelloConfig',
]

.

vim urls.py

urls.py: entire file looks like this:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('hello.urls')),
]

.

cd ..
cd hello
vim views.py

views.py: entire file looks like this

from django.shortcuts import render
# Create your views here.

# hello/views.py
from django.http import HttpResponse
def homePageView(request):
return HttpResponse('Hello, World!')

.

vim urls.py

hello/urls.py: entire file looks like this:

# hello/urls.py
from django.urls import path
from .views import homePageView

urlpatterns = [
         path('', homePageView, name='home')
]

.

cd ..
python manage.py runserver
wget http://127.0.0.1:8000/      (works correctly as it should, now gets “Hello World!”)

Now for the Apache part:

sudo vim /etc/httpd/conf/httpd.conf
    

Paste the following to the bottom of httpd.conf:

WSGIScriptAlias / /var/www/myApp/myApp/myApp/wsgi.py
WSGIPythonHome /var/www/myApp/myprojectenv
WSGIPythonPath /var/www/myApp

<Directory /var/www/myApp/myApp/myApp>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

.

sudo service httpd restart
wget http://127.0.0.1

Connecting to 127.0.0.1:80... connected. HTTP request sent, awaiting response...

and that is all it does until it times out. Connecting to the public IP address through a browser does the same thing; it connects and just sits there waiting for a response.

Apache error log (/var/log/httpd/error_log) says this:

Django ImportError: No module named site

A quick search suggests that this is because mod_wsgi is using a different version of python than my virtual environment. I'm using python3.7

cd /etc/httpd/modules
ldd mod_wsgi.so

outputs

    linux-vdso.so.1 (0x00007ffd7dec3000)
    libpython2.7.so.1.0 => /lib64/libpython2.7.so.1.0 (0x00007fe35815d000)
    libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe357f3f000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007fe357d3b000)
    libutil.so.1 => /lib64/libutil.so.1 (0x00007fe357b38000)
    libm.so.6 => /lib64/libm.so.6 (0x00007fe3577f8000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fe35744d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fe358755000)

Clearly that is a different version. I've uninstalled it, and installed it again while in the python3.7 virtual environment, but the result is the same. It still says "libpython2.7.so.1.0 => /lib64/libpython2.7.so.1.0".

Adam Winter
  • 1,680
  • 1
  • 12
  • 26
  • In the first code block at the top, I had to run the python commands using `python3`, e.g. `python3 manage.py migrate` - otherwise I got a syntax error. BTW, this is the best tutorial **by far** for setting up Django in Apache on Amazon EC2. – Indiana Bones Nov 11 '21 at 02:13

2 Answers2

2

Ultimately, the problem here was a matter of getting Python to use the correct/new version of sqlite3. The error log located at /var/log/httpd/error_log proved very useful for troubleshooting (surprise).

In searching through other Q&A I found a lot of answers that involved LD_LIBRARY_PATH and LD_RUN_PATH. However, with deeper research I found that these are not the preferred method for instructing the compiler as to library paths. As shown below, ldconfig is used instead, along with a .conf file placed in the /etc/ld.so.conf.d/ directory.

The following is the step-by-step instructions for getting the latest Django served up by Apache; beginning with a fresh Linux 2 EC2 instance.

sudo yum update
sudo su
yum groupinstall "Development Tools"
crtl-d
sudo yum -y install libffi-devel
sudo yum install -y openssl-devel
sudo vim /etc/ld.so.conf.d/usrlocal.conf

In this empty file you created, add:

/usr/local/lib
/usr/local/lib64

next:

sudo ldconfig -v
cd ~
mkdir downloads
cd downloads
wget https://sqlite.org/2020/sqlite-autoconf-3320300.tar.gz
tar -xvf sqlite-autoconf-3320300.tar.gz
cd sqlite-autoconf-3320300
./configure --prefix=/usr/local
make -L
sudo make install
sudo ldconfig -v
cd ~downloads
wget https://www.python.org/ftp/python/3.7.7/Python-3.7.7.tgz
tar -xvf Python-3.7.7.tgz
cd Python-3.7.7
./configure --enable-shared --enable-optimizations --with-threads --enable-loadable-sqlite-extensions --with-openssl=/usr/local/lib64
sudo make -L
sudo make altinstall        (altinstall keeps old 2.7 version)
sudo ldconfig -v
python 3.7                  (to verify installation ctrl-d to quit)
>>>import sqlite3
>>> sqlite3.sqlite_version
ctrl-d
sudo chown -R ec2-user /usr/local/lib/python3.7
sudo chown ec2-user /usr/local/bin
sudo chown ec2-user /usr/local/lib
sudo yum install httpd-devel
sudo ldconfig -v
cd /var/www/
sudo mkdir django
sudo chown ec2-user django
cd django
pip3.7 install virtualenv
virtualenv myprojectenv
source myprojectenv/bin/activate
python -c 'import sys; print(sys.prefix)'
pip3.7 install mod_wsgi           
mod_wsgi-express module-config

That will output something like the following. You will copy that and paste it to the bottom of your httpd.conf file. sudo vim /etc/httpd/conf/httpd.conf

LoadModule wsgi_module "/var/www/django/myprojectenv/lib/python3.7/site-packages/mod_wsgi/server/mod_wsgi-py37.cpython-37m-x86_64-linux-gnu.so"
WSGIPythonHome "/var/www/django/myprojectenv"

next:

pip3.7 install Django==3.0.7
django-admin startproject myApp
cd myApp
python manage.py migrate
python manage.py startapp hello
cd myApp
vim wsgi.py

edit to look like the following (add ‘import sys’ and ‘sys.path…….’)

import os
import sys
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myApp.settings')
sys.path.append('/var/www/myApp/myApp/myApp')
sys.path.append('/var/www/myApp/myApp')

application = get_wsgi_application()

next:

vim settings.py

edit to look like the following, substituting your EC2 instance public IP

    ALLOWED_HOSTS = ['xx.xxx.xx.xxx']     (substitute your EC2 public IP address)

    INSTALLED_APPS = [
     'django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
     'django.contrib.staticfiles',
      'hello.apps',
     ]


vim urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('hello.urls')),
]

next:

cd ../hello
vim views.py

Edit to look like the following. These are Python files. So, mind your indentations

from django.shortcuts import render
# Create your views here.

# hello/views.py
from django.http import HttpResponse
def homePageView(request):
    return HttpResponse('Hello, World!')

This next file you will create.

vim urls.py

Paste:

# hello/urls.py
from django.urls import path
from .views import homePageView

urlpatterns = [
    path('', homePageView, name='home')
]

Now back to Apache:

sudo vim /etc/httpd/conf/httpd.conf
    

Paste the following to the bottom of httpd.conf:

WSGIScriptAlias / /var/www/django/myApp/myApp/wsgi.py
WSGIPythonPath /var/www/django

<Directory /var/www/django/myApp/myApp>
<Files wsgi.py>
Require all granted
</Files>
</Directory>

.

sudo service httpd start

At this point you should be able to make a request to the public IP of your instance and get the “Hello World!” response.

Finally:

sudo su
vim /var/log/httpd/error_log

and viola, you have some new issues to address!

Adam Winter
  • 1,680
  • 1
  • 12
  • 26
  • 1
    You're making your life a lot more difficult with the above instructions. There's no reason to compile SQLite or Python 3.7.7 from source when the stock packages that are easily available. The stock yum packages are easier to maintain, and don't require any messing with library paths. At a certain point you might just not want to bother running Amazon Linux 2 and run a different distro on the machine. Also just to note, that all goes way beyond the original question scope. But so long as it works! – Programming123 Jul 02 '20 at 06:28
  • Sorry, I guess I didn't make it clear that that is where I started. I mean, obviously installing everything with yum is preferable as it is much easier. It's when that doesn't work that you have to start doing this sort of thing. Yes, I tried to make it work with the stock yum packages, but it either didn't work, or certain dependencies were only good for older versions of Django. – Adam Winter Jul 02 '20 at 07:26
  • Besides Amazon Linux 2 and the other AMI, can you elaborate on why I would want to run a different distro? – Adam Winter Jul 02 '20 at 20:20
  • Well, my thought at the time was if you're mostly running AWS Linux 2 as a web host, but are compiling all of the packages yourself because they weren't current enough for you, then running Ubuntu or something else that stays more up to date might be a better fit? That way you'd still get package maintenance to update any security issues, whereas now you're stuck doing that yourself and monitoring for/compiling new releases every time. That said, if you prefer that then it doesn't really matter which distro you're using I suppose! – Programming123 Jul 08 '20 at 19:59
2

On Amazon Linux 2 you need to compile the mod_wsgi against Python 3.7 yourself (EDIT: If you want to install the traditional apache module version of mod_wsgi). For some reason Amazon only has a yum package for a 2.7 compiled version included.

I recently did the same and followed the instructions here http://www.marek.tokyo/2018/08/apache-24-modwsgi-python-37-django.html. But essentially:

  1. Download mod_wsgi (latest is 4.7.1)
  2. Expand the tar.gz archive
  3. Run ./configure --with-python=/usr/bin/python3
  4. Run LD_RUN_PATH=/usr/local/lib make
  5. Run make install
  6. Open /etc/ld.so.conf and add: /usr/local/lib to the end of the file if it's not there already
  7. Run ldconfig
  8. Check if mod_wsgi is linked properly by running ldd /usr/lib64/httpd/modules/mod_wsgi.so, if it is you'll see a link to libpython3.7
  9. Finally, you need to tell Apache to load the new module so create a module file in the apache config (echo "LoadModule wsgi_module /usr/lib64/httpd/modules/mod_wsgi.so" > /etc/httpd/conf.modules.d/01-wsgi.conf)

You might need to install gcc or some other build tools if they aren't installed already.

EDIT: In case it's not clear, you should only download source code from sources you trust, so in this case, while that instruction page has a link, you could also just use the mod_wsgi github page (https://github.com/GrahamDumpleton/mod_wsgi/releases).

As an alternative, you can also use pip to install a mod_wsgi-express which doesn't take additional apache config (https://modwsgi.readthedocs.io/en/develop/).

Either way, you can't use the Amazon Linux 2 package if you are using the latest build of Python 3.

Programming123
  • 302
  • 3
  • 15
  • Since posting this, I've also stopped using yum to install mod_wsgi. I'm now using pip3.7 to install it. So, since Python is essentially installing mod_wsgi itself, I would assume it's the correct version. That said, I'm still getting an error on the sqlite3 version. – Adam Winter Jun 29 '20 at 00:43
  • Can't help with sqlite, but that might be worth opening a new question. I had fine luck with just installing mod-wsgi from source, it's global anyway. – Programming123 Jun 30 '20 at 01:02
  • Turns out it's not true that you have to compile mod-wsgi yourself. All official documentation seems to point at pypi.org, which says to use pip for installation. I'm a little concerned about the link that you provided for downloading the source, as it seems it could easily be a hack. – Adam Winter Jun 30 '20 at 02:32
  • The mod_wsgi site itself talks about the two ways (from source or package vs pypi), see here https://modwsgi.readthedocs.io/en/develop/. The link was just the instructions I had followed to do the installation and configurating, I didn't say to download the code from there, just as easy to pull it from github (https://github.com/GrahamDumpleton/mod_wsgi/releases) – Programming123 Jul 02 '20 at 06:11