- on the same IP
- on the same Port 80
Why?
coming...
Who?
This setup was mostly created by @frog32 and the guide was written by @sspross. It was developed while working at allink. Warning: This setup is not battle tested and may or may not work for you.
How?
- Enable Automatic Security Updates
- Install Logwatch To Keep An Eye On Things
- Set Up a Firewall
- Switch to www-data User and require Public Key Authentication
- Lock Down SSH
- Colors for www-data
In this guide we used a digitalocean droplet, but it is just an Ubuntu Server.
- Add your SSH key to your digital ocean control panel
- Create a droplet (Ubuntu 12.04 x32 Server)
- Login over
ssh -A [email protected] - Change root password
passwd(you don't have to remember it, you login with your ssh key and you can reset the root password using the control panel anytime) - Update distribution
apt-get update && apt-get upgrade - Install fail2ban
apt-get install fail2ban
-
apt-get install vim unattended-upgradesand editvim /etc/apt/apt.conf.d/10periodic:APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Download-Upgradeable-Packages "1"; APT::Periodic::AutocleanInterval "7"; APT::Periodic::Unattended-Upgrade "1";
-
apt-get install logwatchand editvim /etc/cron.daily/00logwatch:/usr/sbin/logwatch --output mail --mailto [email protected] --detail high
-
apt-get install ufwandufw allow 22 ufw allow 80 ufw enable(allow only from a specific IP
ufw allow from {your-ip} to any port 22, allow httpsufw allow 443
-
Change home folder for user
www-dataand add your public key to theauthorized_keysfile:mkdir /home/www-data mkdir /home/www-data/.ssh chmod 700 /home/www-data/.ssh vim /home/www-data/.ssh/authorized_keys chown www-data:www-data /home/www-data -R usermod -d /home/www-data www-data -
Activate
sudoforwww-data:passwd www-data -
In
visudocomment all existing user/group grant lines and add:root ALL=(ALL) ALL www-data ALL=(ALL) ALLMaybe allow www-data to use supervisor without password:
www-data ALL=(ALL) NOPASSWD: /usr/bin/supervisorctl
-
Configure ssh to prevent password & root logins
vim /etc/ssh/sshd_config:PermitRootLogin no PasswordAuthentication no -
And restart ssh
service ssh restart
- Edit
/etc/passwdand change the shell ofwww-datauser from/bin/shto/bin/bash - Copy bashrc and profile files
cp /root/.bashrc /home/www-data/ && cp /root/.profile /home/www-data/and update their ownerchown www-data:www-data /home/www-data -R
-
Install packages:
apt-get install csstidy yui-compressor libpng12-dev libjpeg-dev zlib1g-dev python-virtualenv python-setuptools libxml2-dev git gettext python-dev libssl-dev mercurial libmysqlclient-dev redis-server rabbitmq-server mysql-server haproxy supervisor nginx node-less -
Our project structure looks like this:
/home/www-data/YOUR-PROJECT/dj/<- Django Project/home/www-data/YOUR-PROJECT/tx/<- Twisted Project
-
Python packages (e.g.
REQUIREMENTS_SERVER):hiredis redis django-redis-cache gunicorn -
Add to your
settings.pyconfig:USE_X_FORWARDED_HOST = True -
Provide URL in
urls.pyfor HAproxy to enable monitoring:url(r'^isrunning$', lambda r: HttpResponse('OK')),
-
Config HAproxy
/etc/haproxy/haproxy.cfg, e.g. this. -
Enable HAproxy, set
ENABLED=1in/etc/default/haproxy(and maybe in/etc/init.d/haproxy) and start it withsudo /etc/init.d/haproxy start. You should see the following if it's really running:* Starting haproxy haproxy ...done. -
If your firewall is active, open port for HAproxy stats
sudo ufw allow 1936 -
Now you can access HAproxy stats over
http://YOUR.IP:1936/and gunicorn should be up and working.
- There has to be a
wsgi.pyfile in/home/www-data/YOUR-PROJECT/dj/, e.g. this. - Create supervisor configuration for gunicorn
/etc/supervisor/conf.d/YOUR_PROJECT_gunicorn.conf, e.g. this. - Don't forget to create a
logsdirectory as configured in the gunicorn config. - Update supervisor
sudo supervisorctlrunupdate(to restart webserver userestart YOUR_PROJECT_gunicorn)
- Unlink default site
sudo unlink /etc/nginx/sites-enabled/default - Create an enabled site configuration
/etc/nginx/sites-enabled/YOUR-DOMAIN.ch, e.g. this. - Don't forget to create a
isrunningfile like configured e.g.touch /home/www-data/YOUR-PROJECT/dj/isrunningfor HAproxy Ping. - Restart nginx
sudo /etc/init.d/nginx restart - Now check HAproxy stats if nginx is pingable and up running
http://YOUR.IP:1936/
-
Create an additional virtualenv for your Twisted app in
/home/www-data/YOUR-PROJECT/tx/withvirtualenv --setuptools env -
Install python packages:
txsockjs pyopenssl twisted -
Create another supervisor configuration for twisted
/etc/supervisor/conf.d/YOUR_PROJECT_twisted.conf, e.g. this. -
Update supervisor
sudo supervisorctlrunupdate(to restart twisted userestart YOUR_PROJECT_twisted) -
Now both (gunicorn and twisted) should be running:
supervisor> status YOUR_PROJECT_gunicorn RUNNING pid 11194, uptime 0:03:34 YOUR_PROJECT_twisted RUNNING pid 11231, uptime 0:01:57 -
And everything should be green on the HAproxy status page
http://YOUR.IP:1936/.
-
Add to your
settings.pyfile:# broker and celery BROKER_URL = 'amqp://YOUR_PROJECT:YOUR_PROJECT@localhost:5672/YOUR_PROJECT' CELERY_RESULT_BACKEND = "redis://localhost/0" CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler" CELERYD_CONCURRENCY = 1 CELERY_SEND_EVENTS = False CELERY_ENABLE_UTC = True import djcelery djcelery.setup_loader() -
Create rabbitmq user and vhost:
sudo rabbitmqctl add_user YOUR_PROJECT YOUR_PROJECT sudo rabbitmqctl add_vhost YOUR_PROJECT sudo rabbitmqctl set_permissions -p YOUR_PROJECT YOUR_PROJECT ".*" ".*" ".*" -
Create another supervisor configuration for celery
/etc/supervisor/conf.d/YOUR_PROJECT_celery.conf, e.g. this. -
Update supervisor
sudo supervisorctlrunupdate(to restart celery userestart YOUR_PROJECT_celery) -
Now all three (gunicorn, twisted and celery) should be running:
supervisor> status YOUR_PROJECT_celery RUNNING pid 12281, uptime 0:00:13 YOUR_PROJECT_gunicorn RUNNING pid 11194, uptime 1:18:23 YOUR_PROJECT_twisted RUNNING pid 11231, uptime 1:16:46