
Django Shared Hosting, Model N
There are many ways to deploy Django applications in a * nix environment. I will not pretend to be original, just share the most-most-very-most .
Prerequisites:
It often happens that, along with developers, users / clients / customers also wish to have access to the file tree of their projects (you can call them anything you like), i.e. “Almost” outsiders. That means limiting third-party users to the possibility of rummaging around on the server’s disks is a good idea. At first glance, the idea comes to limit the user to his home directory. You should not give in to this impulse, because in your home directory the user is king and god, and one wrong moveand you are the father can lead to the inoperability of the project. Therefore, let's go to the trick and create the following hierarchy:
the home directory of the user “client” has the rights client: client, the rest of the directories, unless otherwise specified, root: client and chmod 750, respectively. You must also include the nginx user in the client group so that nginx has the right to access static files inside the project. Also in the system, create a sftponly group in which we include clients. In the sshd config (/ etc / ssh / sshd_config) add the following:
As a result, we get a situation when a user logging on to the server via sftp (for example, using winscp) gets into his home directory, can go up one level, roam about his projects, watch the logs. However, he is unable to go up or delete any important directory (chmod 750 however).
Nginx is perhaps the best of http-servers for delivering static content and resolving issues related to the generation of dynamic. In our case, nginx should be assembled together with the uwsgi-module (comes as standard). When installed by default (at least in gentoo) nginx stores its configs in / etc / nginx. We will not break this tradition, and even vice versa try to use it. In the main nginx'a config (/etc/nginx/nginx.conf), add the line to the end of the http section
Something like this:
Once, when uwsgi was just starting to appear, it knew how to fall during operation, it didn’t have an “imperial” regime, but it was already in hell of a demand - a script was written in haste, to rewrite it that normally didn’t reach for one single reason - it works. So how does it work and what does it do.
Nust runs on the crown (crontab -e)
You can install nust into the system as follows:
In the nginx config using the “curly comment” # uwsgi # you can override the following options:
To start any python code under uwsgi, you need a so-called module. To run django, the following code is located in django_wsgi.py :
There is no need to register the launch of nust in the startup scripts of the system, since nust is launched periodically on the crown. In addition to just starting projects, nust monitors their status (crashes, is not running, is running, but does not respond), as well as the status of nginx virtual host config files. If the virtual host config has been changed, the corresponding project will be restarted.
Well, that's all. I hope I have not forgotten anything important. Thanks for attention.
Introductory conditions
Prerequisites:
- One client (customer) - one user in the system on the server.
- All client projects are in one file hierarchy.
- Virtualenv is good and must use.
- Ftp is evil, we use modern means (sftp).
- The number of files for project management should be minimized.
- nginx
- uwsgi
- cron
- virtualenv
- openssh
And nefig rummage around here
It often happens that, along with developers, users / clients / customers also wish to have access to the file tree of their projects (you can call them anything you like), i.e. “Almost” outsiders. That means limiting third-party users to the possibility of rummaging around on the server’s disks is a good idea. At first glance, the idea comes to limit the user to his home directory. You should not give in to this impulse, because in your home directory the user is king and god, and one wrong move
/home
/client -- директория с проектами данного клиента
/client -- домашняя директория пользователя "client"
/another_project
/project
/www-root
/static
/app1
/app2
manage.py
settings.py
django_wsgi.py
...
/var
/log -- логи nginx'a, не забыть включить ее в logrotate
/tmp -- chmod 770 -- временные файлы проекта
/run -- тут будут пиды и сокеты
/client2 -- директория с проектами другого клиента
/client3 -- директория с проектами еще одного клиента
the home directory of the user “client” has the rights client: client, the rest of the directories, unless otherwise specified, root: client and chmod 750, respectively. You must also include the nginx user in the client group so that nginx has the right to access static files inside the project. Also in the system, create a sftponly group in which we include clients. In the sshd config (/ etc / ssh / sshd_config) add the following:
Match Group sftponly
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
ChrootDirectory /home/%u
ForceCommand internal-sftp
and line Subsystem sftp /usr/lib/misc/sftp-server
replace with Subsystem sftp internal-sftp
As a result, we get a situation when a user logging on to the server via sftp (for example, using winscp) gets into his home directory, can go up one level, roam about his projects, watch the logs. However, he is unable to go up or delete any important directory (chmod 750 however).
nginx - how much in this word
Nginx is perhaps the best of http-servers for delivering static content and resolving issues related to the generation of dynamic. In our case, nginx should be assembled together with the uwsgi-module (comes as standard). When installed by default (at least in gentoo) nginx stores its configs in / etc / nginx. We will not break this tradition, and even vice versa try to use it. In the main nginx'a config (/etc/nginx/nginx.conf), add the line to the end of the http section
include /etc/nginx/vhost.d/*.conf ;
As a result, we can have one configuration file (/etc/nginx/vhost.d/project.conf) per project. Something like this:
#uwsgi# USER client
#uwsgi# PRJ cool_site.ru
#uwsgi# HOME ~/../project
#uwsgi# VE ~/.virtualenvs/project
#uwsgi# SOCKET ../var/run/uwsgi-project
#uwsgi# LOG ../var/log/uwsgi-project.log
#uwsgi# PID ../var/run/uwsgi-project.pid
#uwsgi# WORKERS 2
upstream wsgi_cluster__project {
server unix:/home/client/var/run/uwsgi-project;
}
server {
listen 80;
server_name .cool_site.ru;
charset utf8;
autoindex off;
root /home/client/project/www-root;
access_log /home/client/var/log/nginx_access.log ;
error_log /home/client/var/log/nginx_error.log error;
location /static {
root /home/client/project;
expires 1d;
}
location / {
try_files $uri @django;
}
location @django {
uwsgi_pass wsgi_cluster__project;
include uwsgi_params;
}
}
Lines beginning with # uwsgi # will be interpreted by nginx as comments, however, the nust start script (discussed below) looks at these lines, considering them directives for themselves.nust - Nginx Uwsgi STarter
Once, when uwsgi was just starting to appear, it knew how to fall during operation, it didn’t have an “imperial” regime, but it was already in hell of a demand - a script was written in haste, to rewrite it that normally didn’t reach for one single reason - it works. So how does it work and what does it do.
Nust runs on the crown (crontab -e)
*/5 * * * * nust -s -c /etc/nust.conf
with your configuration file. The configuration file has two sections, the first of which relates directly to nust'y and defines the paths and utilities that it uses, and the second - the default for uwsgi.[nust]
pstree = /usr/bin/pstree
vhosts = /etc/nginx/vhost.d/*.conf
uwsgi = /usr/bin/uwsgi
uwsgi_def_args = --ini=/etc/nust.conf
dbdir = /var/run
kill = /bin/kill -s TERM
kill_k9= /bin/kill -s KILL
[uwsgi]
master=
disable-logging=
vacuum=
logfile-chown=
chmod-socket=666
catch-exceptions=
memory-report=
You can install nust into the system as follows:
sudo pip install nust
In the nginx config using the “curly comment” # uwsgi # you can override the following options:
- WORKERS - number of parallel workflows
- MODULE - name of the python module to start (django_wsgi.py)
- PRJ - project name
- PID - pid-file of the workflow tree (var / run / uwsgi.pid)
- LOG - path to the uwsgi log file (var / log / uwsgi.log)
- HARAKIRI - maximum query execution time, sec.
- MAX_REQ - the number of processed requests, after which the workflow will be restarted
- USER - user from which the project will be launched
- HOME - project home directory (NOT USER!)
- VE - the path to the virtual environment (the result of virtualenv)
- SOCKET - where to create a socket file. If not specified, it will be taken from the upstream section.
- absolute path starts with a slash
(/ tmp) - path relative to the user's home directory
(~ / gde-to / tam /) - path relative to the project home directory
(var / run / uwsgi.pid)
To start any python code under uwsgi, you need a so-called module. To run django, the following code is located in django_wsgi.py :
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
There is no need to register the launch of nust in the startup scripts of the system, since nust is launched periodically on the crown. In addition to just starting projects, nust monitors their status (crashes, is not running, is running, but does not respond), as well as the status of nginx virtual host config files. If the virtual host config has been changed, the corresponding project will be restarted.
Instead of an afterword
Well, that's all. I hope I have not forgotten anything important. Thanks for attention.