Deploying django application in production? - python

I have installed Django and mod_wsgi-express (the new way) on an ubuntu 15.10 server using:
pip install Django
pip install mod_wsgi
Currently I am starting/deploying my django application using a script that:
cd ~/.local/bin
./mod_wsgi-express start-server ~/mysite/mysite/wsgi.py
where my application is located in (as a git repository):
~/mysite/
Since ~/mysite/ is not on the PYTHONPATH I have modified the wsgi.py file to:
import os
from django.core.wsgi import get_wsgi_application
# Hardcode the path to the application/add it to the PYTHONPATH
import sys
path = '/home/user/mysite'
if path not in sys.path:
sys.path.append(path)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
application = get_wsgi_application()
This works fine for now. But if I want to use this in production I see some problems:
wsgi.py contains hard coded path to the django web application to make sure its in the PYTHONPATH. Further its not guaranteed to be in the same path on the local developer machine. At least an improvement could be to use relative paths.
The web application is distributed as a git repository. E.g. in java you would package it into a war or an ear file.
Both django and mod_wsgi-express are located in the ~/.local folder for a specific local user.
Are there any obvious changes I should start looking into to eliminate bullet 1-3 above or is the above approach more or less how django deployment works?

I'll start out by saying that I'm assuming you're using the set up you describe for specific reasons and I won't try to steer you towards anything that might be more admin-friendly. If you're not and could use a friendly nudge, you can try Googling around for different people's pros/cons and examples or I would put in a good word for Gunicorn and an LTS version of Ubuntu.
Anyway.
When I was reading your question the first thing that popped into my head was that you could use something like Fabric or even just a deployment script that could do a string substitution in your wsgi.py file, putting in the correct path for you along with handling everything else in your deployment. I would say automated deployments are something of a standard and you might like the freedom of being able to throw out a server and spin up a new one in 5 minutes, but they can be a lot to learn if you're doing other things at the time.
Figuring that you probably didn't want to mess with all the automation rigmarole, I then popped over to Django's mod_wsgi deployment documentation (which is pretty good) because messing around with the Python path seemed weird and like something you shouldn't have to do. Sure enough, they recommend running mod_wsgi in daemon mode, which gives you an opportunity to set the Python path in the Apache config and keep it separate from the code you distribute. Then you can just have different boxes use different config files based on their needs.
That same documentation has notes on using a virtual environment (virtualenv) which you also want to probably do -- that virtualenv would then be portable and would handle your concerns with point 3.
With point 2 you should probably just think of the git distribution as a feature -- no need to run a build process and upload WAR files and all the etceteras. Java people only put up with that because they theoretically get something from having their code compiled into bytecode; Python, for better or for worse, doesn't do any compilation so you can deploy your code transparently and use git to handle your files at all points in the application's life without worrying about keeping the artifact versions straight and all that.
EDIT:
You could also probably avoid any issues with PYTHONPATH by adding your ~/.local/bin folder to your path (export PATH=~/.local/bin:$PATH from command line) and then cding into your site's directory and just running mod_wsgi-express start-server mysite/wsgi.py. By adding the local bin folder to your PATH you gain the ability to reference any applications in it implicitly from any directory while still having everything rooted in the directory you cd into, which should keep Python from getting confused.
I would still prefer to link mod_wsgi into your main Apache installation and run it in daemon mode so that you can control bringing it up/down from systemd/systemctl instead of forking processes from your terminal and having to look up the process ID in ps to kill it.

Better something like this:
import os
import sys
sys.path.append("add/Your/Path")
os.environ.setdefault("DJANGO_SETTINGS_MODULE","mysite.settings")
import django
django.setup
import django.core.handlers.wsgi
application = get_wsgi_application()
application = django.core.handlers.wsgi.WSGIHandler()
check that You project is named a mysite, If You project have other name change mysite on name of You django-project. You will use to production apache?

import os
import sys
sys.path.append("add/Your/Path")
os.environ.setdefault("DJANGO_SETTINGS_MODULE","mysite.settings")
import django
django.setup()
import django.core.handlers.wsgi
application = get_wsgi_application()
application = django.core.handlers.wsgi.WSGIHandler()

Related

Deploy Django project using wsgi and virtualenv on shared webhosting server without root access

I have a Django project which I would like to run on my shared webspace (1und1 Webspace) running on linux. I don't have root access and therefore can not edit apache's httpd.conf or install software system wide.
What I did so far:
installed squlite locally since it is not available on the server
installed Python 3.5.1 in ~/.localpython
installed virtualenv for my local python
created a virtual environment in ~/ve_tc_lb
installed Django and Pillow in my virtual environment
cloned my django project from git server
After these steps, I'm able to run python manage.py runserver in my project directory and it seems to be running (I can access the login screen using lynx on my local machine).
I read many postings on how to configure fastCGI environments, but since I'm using Django 1.9.1, I'm depening on wsgi. I saw a lot about configuring django for wsgi and virtualenv, but all examples required access to httpd.conf.
The shared web server is apache.
I can create a new directory in my home with a sample hello.py and it is working when I enter the url, but it is (of course) using the python provided by the server and not my local installation.
When I change the first line indicating which python version to use to my virtual environment (#!/path/to/home/ve_tc_lb/bin/python), it seems to use the correct version in the virtual environment. Since I'm using different systems for developing and deployment, I'm not sure whether it is a good idea to e.g. add such a line in my djangoproject/wsgi.py.
Update 2016-06-02
A few more things I tried:
I learned that I don't have access to the apache error logs
read a lot about mod_wsgi and django in various sources which I just want to share here in case someone needs them in the future:
modwsgi - IntegrationWithDjango.wiki
debug mod_wsgi installation (only applicable if you are root)
mod_wsgi configuration guide
I followed the wsgi test script installation here - but the wsgi-file is just displayed in my browser instead of beeing executed.
All in all it seems like my provider 1und1 did not install wsgi extensions (even though the support told me a week ago it would be installed)
Update 2016-06-12: I got a reply from support (after a week or so :-S ) confirming that they dont have mod_wsgi but wsgiref...
So I'm a bit stuck here - which steps should I do next?
I'll update the question regularly based on comments and remarks. Any help is appreciated.
Since your apache is shared, I don't expect you can change the httpd.conf but use instead your solution. My suggestion is:
If you have multiple servers you will deploy your project (e.g. testing, staging, production), then do the following steps for each deploy target.
In each server, create a true wsgi.py file which you will never put in versioning systems. Pretty much like you would do with a local_settings.py file. This file will be named wsgy.py since most likely you cannot edit the apache settings (since it is shared) and that name will be expected for your wsgi file.
The content for the file will be:
#!/path/to/your/virtualenv/python
from my_true_wsgi import *
Which will be different for each deploy server, but the difference will be, most likely, in the shebang line to locate the proper python interpreter.
You will have a file named my_true_wsgi to have it matching the import in the former code. That file will be in the versioning systems, unlike the wsgi.py file. The contents of such file is the usual contents of the wsgi.py on any regular django project, just that you are not using that name directly.
With this solution you can have several different wsgi files with no conflict on shebangs.
You'll have to use a webhost that supports Django. See https://code.djangoproject.com/wiki/DjangoFriendlyWebHosts. Personally, I've used WebFaction and was quite happy with it, their support was great and customer service very responsive.

Python app configuration best practices

I know this issue has been discussed before, but I am struggling to find a starightforward explanation of how to approach configuration between local development and production server.
What I have done so far: I had one my_app_config.py file that had a section with machine / scenario (test vs production) sections I could just comment out. I would develop with my local machine path hardcoded, test database connection string, my test spreadsheet location, etc. When it comes time to deploy the code to the server, I comment out the "test" section and uncomment the "production section". As you may guess, this is wrought with errors.
I recently adopted the Python ConfigParser library to use .ini files. Now, I have the following lines in my code
import ConfigParser
config = ConfigParser.RawConfigParser()
config.read(os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'settings',
'my_app_config.ini')))
database_connect_string_admin = config.get('Database', 'admin_str')
The problems with this are many...
I need to have the import at the top of every file
The filename my_app_config.ini can't change. So, I rely on comments within the content of the .ini file to know which one I'm dealing with. They are stored in a folder tree so I know which is which.
notice the path to the config file is defined here. So, depending where the python file lives in the tree structure dictates if I get a copy / paste error.
I tried to set environment variables at the beginning of the program, but all the imports for all modules are performed right away at code launch. I was getting "not found" errors left and right.
What I want: To understand how to keep all the configurations stored in one place that is not easy to lose track of what I am doing. I want an easy way to keep these configuration files (ideally one file or script) under version control (security is a whole other issue, I digress). I want to be able to seamlessly switch contexts (local-test, local-production, serverA-test, serverA-production, serverB-test, serverB-production) My app uses
my_app_config.ini read by my parser
uwsgi.ini read by the uwsgi application server emperor
web_config.py used by the flask application
nginx.conf symlinked to the web server's configuration
celery configuration
not to mention different paths for everything (ideally handled within the magic config handling genie). I imagine once I figure this out I will be embarrassed it took so long to grasp.
Are Environment variables what I am trying to do here?
You have to try `simple-settings. It will resolve all you issues. One way set environment variable
in development
$ export SIMPLE_SETTINGS=settings.general,settings.development
$ python app.py
in production
$ export SIMPLE_SETTINGS=settings.general,settings.production
$ python app.py
You can keep `` development.pyandproduction.py` not in a repository for security reasons.
Example
settings/general.py
SIMPLE_CONF = 'simple'
app.py
from simple_settings import settings
print(settings.SIMPLE_CONF)
The documentation indicated many more features and benefits.

How do I use multiple settings file in Django with multiple sites on one server?

I have an ec2 instance running Ubuntu 14.04 and I want to host two sites from it. On my first site I have two settings file, production_settings.py and settings.py (for local development). I import the local settings into the production settings and override any settings with the production settings file.
Since my production settings file is not the default settings.py name, I have to create an environment variable
DJANGO_SETTINGS_MODULE='site1.production_settings'
However because of this whenever I try to start my second site it says
No module named site1.production_settings
I am assuming that this is due to me setting the environment variable. Another problem is that I won't be able to use different settings file for different sites.
How do I start use two different settings file for two different websites?
Edit: I missed the apache tag on this so I've updated my answer accordingly
Your problem is when running your Django app, site2, the python interpreter does not know about any of the modules in site1 because it's not listed in your PYTHONPATH.
I would highly recommend doing a short amount of reading up on how PYTHONPATH works before you continue: http://www.stereoplex.com/blog/understanding-imports-and-pythonpath
Now, there are many ways to resolve this, but we'll cover 3:
Modify your apache virtualhost configuration for site2:
Be sure to read the docs here, first, for differences between mod_wsgi v1 and v2 but as you're running ubuntu 14.04, you should be using mod_wsgi v2 anyway.
https://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPythonPath
<virtualhost *:80>
# your existing config directives
WSGIPythonPath /path/to/site1
</virtualhost>
This has the advantage of not modifying any of your application code and, potentially having invalid directories in your PYTHONPATH when running site2 on your development machine.
Append the path in your python code
Python sys.path - appending PYTHONPATH
In your site2.wsgi file, before you start your Django app, add the following code.
import sys
sys.path.append('/path/to/site1')
Simple, and works. This approach will also not cause you problems when moving between development (using manage.py runserver) and production.
Create a simlink
How to symlink a file in Linux?
Another simple choice is to simply simlink your production_settings.py into site2, and and then set your DJANGO_SETTTINGS_MODULE='site2.production_settings'
ln -s /path/to/site1/site1/production_settings.py /path/to/site2/site2/production_settings.py
If you're developing on a windows machine, this is probably the most problematic of the 3 approaches, so if you're pushing to the server using git or any other version control system, make sure to add your new simlink to your .gitignore file or your VCS's equivalent.

trying to deploy django and wsgi can't import my settings file - improperly configured/module doesn't exist

I'm trying not to scream...
I am trying to deploy my django project and I can't seem to set the settings module correctly. I have been googling and have come up empty. I have deployed projects before(but am still a noob) and not had this problem so I can't figure it out. PLEASE HELP.
I am deploying on dotcloud. FWIW I was going to deploy on heroku(until I realized that dotcloud is better suited for my project) and was having the same error. I just can't figure out what I'm doing wrong!
My settings file is located at:
/Users/<myname>/wheretoeat/wheretoeat/wheretoeat/settings.py
wsgi.py
import os
import sys
#sys.path.append('/Users/<myname>/wheretoeat/wheretoeat/wheretoeat')
from django.core.wsgi import get_wsgi_application
import sys
sys.path.append('/Users/<myname>/wheretoeat/wheretoeat/wheretoeat')
#sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'wheretoeat')))
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
os.environ["DJANGO_SETTINGS_MODULE"] = "wheretoeat.settings"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wheretoeat.settings")
Pathing issues can sometimes be a little tricky. Could I suggest an alternate approach of starting your project on dotcloud by using a working project (something that deploys reliably) and then incrementally port your existing work into this base project. I'd like to invite you to see our django-on-dotcloud recipe:
https://github.com/dotcloud/django-on-dotcloud
Using this project, you should be able to quickly iterate on something that deploys vs getting potentially hung up on a series of problems that may or may not be deployment related (we don't have visibility into your entire project, so its difficult to be definitive about what problem you're seeing. module locations, package locations, etc could be affecting the error).
Using this, you can see how we've set-up the project and the location of the settings files.
https://github.com/dotcloud/django-on-dotcloud/blob/master/hellodjango/settings.py
I realize that that the recipe is a little outdated and that it doesn't use the new settings files locations introduced with the more recent versions of django, however once you have a working project you can incrementally make it conform to whatever standards you'd like to move forward with.
If you're still having trouble, feel free to drop us a line at support#dotcloud.com and we can help take a closer look at what might not be working for you.

Can Sentry be run under passenger WSGI (dreamhost)

I am trying to get sentry running on my dreamhost server. Dreamhost uses passenger wsgi to serve python frameworks, like django. I am able to get django apps running.
I am using virtualenv and I install sentry using pip, so all the code for sentry sits under the virtualenv directory. The instructions given for sentry doesn't use the startproject to create a directory that you can place somewhere for the passenger_wsgi.py file to find.
The sentry website gives examples of the program running under Nginx and uWSGI, but I am limited to (in this case) to apache and passenger wsgi.
Is it possible to run sentry under dreamhost's configuration and if so how does one pass things in like the config file to get it working. I have been able to locally start and interact with sentry, using :
sentry --config=/home/user/.sentry/sentry.conf.py start
so I know that all the dependencies are present on the host system
OK it looks like I was over thinking it, I forgot from a python perspective the file wsgi.py (which is found in the sentry directory) is called as sentry.wsgi when imported as a module. I was confused by sentry being a module that was downloaded from pip and how to access it. This is the reduced solution that works:
passenger_wgsi.py
import sys, os
INTERP = "/home/user/.virtualenv/sentry2/bin/python"
if sys.executable != INTERP:
os.execl(INTERP, INTERP, *sys.argv)
os.environ['SENTRY_CONF'] = "/home/user/.virtualenv/sentry2/sentry.conf.py"
import sentry.wsgi
believe it or not, that's it. If you look at the wsgi file in the sentry directory under the virtualenv install you will see it does all the importing of the django.core.handlers.wsgi and kicks off the correct application.

Categories