
Setting up Python virtual environments has never been easier.
When I returned to Django and began to rebuild my site I didn’t find any information that mentioned this option.
A number of the how-tos I read involved editing the wsgi.py
file that is installed when you create a mod_wsgi
app on WebFaction, so the wsgi.py
file would activate the virtualenv. This really isn’t necessary. Interestingly, WebFaction’s own instructions are simple, current, and really all you need to get things rolling pretty easily. Go figure. This article adds a few specifics (particulary for the Apache config file), but is really about using Python3’s built in venv
command.
As of Python3.3, the ability to create virtual environments is built right in to the language in the form of the pyvenv
command (which will be deprecated in favor of simply venv
in Python3.6.) This makes it even easier to setup Python virtualenvs on WebFaction.
One last bit before we get to it. Most of what I did to set up Django in a virtualenv is exactly what is described in the this excellent how-to by Michał Karzyński, the only real difference being the use of the built in venv
instead of doing a separate install of virtualenv
. I recommend you read Michał’s article as it goes a bit beyond setup and includes instructions on serving static media and separating your development and production environments.
Ok. Here’s what I did:
We’re going to skip the Django App installer script that WebFaction provides and just create a generic mod_wsgi
application.
In the WebFaction control panel,
- Create a new app of type
mod_wsgi 4.5.9/Python 3.5
(if you read this in the future the version numbers may have increased.) I’m going to call this app, ‘yourapp.’ - Create a website using one of your available domains and connect it to yourapp.
- Make sure it’s working by visiting the site in your browser. You should see this:
Welcome to your mod_wsgi website! It uses: Python 3.5.2 (default, Sep 4 2016, 00:18:27) [GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] WSGI version: (4, 5, 8)
Now, if you visit /home/username/webapps/yourapp
via ssh or your FTP client, you will see the directories: apache2
and htdocs
.
You aren’t going to need htdocs
so you can delete that now.
Ok. Now we just have to create the virtual environment for our Django app and set up a virtual host for our site in the Apache config file.
Let’s create the virtual environment first.
I prefer to create the virtual environment directory in the same location as the app itself. This puts the directory next to the apache2 directory (and in a moment next to our Django project directory.)
Do an ssh login to your WebFaction account, and run these commands: (You can use any name for your virtual environment. I’ve used the app name with ‘env’ appended.)
cd /home/username/webapps/yourapp python3 -m venv yourappenv
Or just:
python3 -m venv /home/username/webapps/yourapp/yourappenv
Now we have a Python virtual environment installed. Easy! (See the directory tree below.)
/yourapp ├── apache2 │ ├── bin │ ├── conf <== #location of http.conf file │ ├── lib │ ├── logs │ └── modules └── yourappenv ├── bin <== #location of activate command ├── include ├── lib └── lib64 -> lib
Activating your virtual environment
When you are managing your app from an ssh session you will need to activate your virtual environment. The command is located in yourappenv/bin
. From the yourapp directory, run source yourappenv/bin/activate
(I’d suggest creating an alias or login hook that activates your virtual environment so you don’t have to type in file paths everytime.)
Pip!
Another nice thing about the built in venv
command is that it installs pip automatically. Let’s get pip updated and ready to load your requirements.txt
file.
Run:pip install --upgrade pip
(Optional)
I like to install yolk so I can easily update all of my installed packages.pip install yolk3K
Running,yolk --upgrade
will check all of your installed packages for available updates and install them if there are any.
Now you can install the latest version of Django with:pip install Django
If you have a requirements.txt
file ready you can install all of your packages with:pip install -r requirements.txt
(If Django is included in your requirements file, you can skip the separate pip install for it.)
Create a Django project
At this point I recommend you go ahead and set up a Django project. You will need to know the name (the path) of this project when we configure Apache to serve your site.
With your virtual environment activated run:django-admin.py startproject yourproject
You may need to make sure that your django-admin.py
and manage.py
files are executable.cd /home/username/webapps/yourapp/yourappenv/bin/
chmod +x django-admin.py
Once you create your project, from the project directory, run: chmod +x manage.py
This allows you to run:./manage.py 'your command'
whenever you are managing your project
Great! Only one thing left to do!
Set up a virtual host for your site.
This will ensure that Apache is serving your site using the correct environment.
You are going to make some changes to your app’s httpd.conf
file. The file is located here: /home/username/webapps/yourapp/apache2/conf/httpd.conf
You can make a copy and alter the original if you like. Change the original to look like this:
ServerRoot "/home/username/webapps/yourapp/apache2" LoadModule authz_core_module modules/mod_authz_core.so LoadModule dir_module modules/mod_dir.so LoadModule env_module modules/mod_env.so LoadModule log_config_module modules/mod_log_config.so LoadModule mime_module modules/mod_mime.so LoadModule rewrite_module modules/mod_rewrite.so LoadModule setenvif_module modules/mod_setenvif.so LoadModule wsgi_module modules/mod_wsgi.so LoadModule unixd_module modules/mod_unixd.so Listen 27140 #this should be whatever WebFaction set it to. KeepAlive Off SetEnvIf X-Forwarded-SSL on HTTPS=1 ServerLimit 1 StartServers 1 MaxRequestWorkers 5 MinSpareThreads 1 MaxSpareThreads 3 ThreadsPerChild 5 WSGIRestrictEmbedded On WSGILazyInitialization On <VirtualHost *> ServerName yourdomain.net # Logging config LogFormat "%{X-Forwarded-For}i %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" combined CustomLog /home/username/logs/user/access_yourapp.log combined ErrorLog /home/username/logs/user/error_yourapp.log #Django WSGI settings WSGIDaemonProcess yourapp processes=2 threads=12 python-home=/home/username/webapps/yourapp/yourappenv python-path=/home/username/webapps/yourapp/yourproject WSGIProcessGroup yourapp WSGIScriptAlias / /home/username/webapps/yourapp/yourproject/yourproject/wsgi.py </VirtualHost>
- Make the necessary substitutions in the path names using your own user, application, and project names.
- Set the
Listen
value to whatever WebFaction set it to in the original config file (meaning you shouldn’t have to change it.) - Change
ServerName
to the appropriate domain. - Note that due to Django’s somewhat frustrating naming conventions, the
WSGIScriptAlias
path will seem like it contains a typo. It doesn’t. This path needs to go all the way to your project directory, which is where thewsgi.py
file lives. (When you create a Django project you get a directory named as you asked, with a subdirectory of the same name.) - Save the
httpd.conf
file (to its original location) and restart Apache.
From the ‘yourapp’ directory run:./apache2/bin/restart
And that should do it! Have fun and build something cool!