- 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-upgrades
and 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 logwatch
and editvim /etc/cron.daily/00logwatch
:/usr/sbin/logwatch --output mail --mailto [email protected] --detail high
-
apt-get install ufw
andufw 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-data
and add your public key to theauthorized_keys
file: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
sudo
forwww-data
:passwd www-data
-
In
visudo
comment all existing user/group grant lines and add:root ALL=(ALL) ALL www-data ALL=(ALL) ALL
Maybe 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/passwd
and change the shell ofwww-data
user from/bin/sh
to/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.py
config:USE_X_FORWARDED_HOST = True
-
Provide URL in
urls.py
for HAproxy to enable monitoring:url(r'^isrunning$', lambda r: HttpResponse('OK')),
-
Config HAproxy
/etc/haproxy/haproxy.cfg
, e.g. this. -
Enable HAproxy, set
ENABLED=1
in/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.py
file 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
logs
directory as configured in the gunicorn config. - Update supervisor
sudo supervisorctl
runupdate
(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
isrunning
file like configured e.g.touch /home/www-data/YOUR-PROJECT/dj/isrunning
for 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 supervisorctl
runupdate
(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.py
file:# 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 supervisorctl
runupdate
(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