-
-
Save leonardinius/3667663 to your computer and use it in GitHub Desktop.
Setup deployment target for Nginx + Python/uWSGI + Supervisor + Git
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Setup deployment target for Nginx + Python/uWSGI + Supervisor + Git | |
function usage() { | |
cat << EOF | |
Usage: $0 [-y] PROJECT_NAME [DOMAIN] | |
Options: | |
-y No prompts, assume yes to all. | |
Example: | |
$0 -y foo fooapp.com | |
EOF | |
} | |
while getopts "h:y" OPTION; do | |
case $OPTION in | |
h) | |
usage | |
exit | |
;; | |
y) | |
NOPROMPT="y" | |
shift | |
;; | |
?) | |
usage | |
exit | |
;; | |
esac | |
done | |
PROJECTNAME="$1" | |
DOMAIN="$2" | |
USERNAME="$(whoami)" | |
if [ "$USERNAME" == "root" ]; then | |
echo "Error: Must be run as non-root." | |
exit 2 | |
fi | |
if [ ! "$PROJECTNAME" ]; then | |
echo "Error: Must specify a project name." | |
exit 3; | |
fi | |
if [ ! "$DOMAIN" ]; then | |
DOMAIN="$PROJECTNAME.com" | |
fi | |
if [ "$NOPROMPT" != "y" ]; then | |
echo "This script is intended to be run on a remote server, not on a local development environment. It will create a bunch of directories and change a bunch of configurations." | |
read -n1 -p "Are you sure you want to continue? [y/N] " answer | |
if [ "$answer" != "y" ]; then | |
echo "Aborting." | |
exit 4 | |
fi | |
fi | |
# Setup our directory structure | |
mkdir ~/{deploy,env,logs,public_html,repo,uploads} | |
mkdir ~/{repo,logs,public_html,uploads}/$PROJECTNAME | |
# Create a detached tree repository | |
cd ~/repo/$PROJECTNAME | |
git init --bare | |
git config core.bare false | |
#git config core.worktree ~/deploy/$PROJECTNAME | |
git config receive.denycurrentbranch ignore | |
git clone ~/repo/$PROJECTNAME ~/deploy/$PROJECTNAME | |
# Setup post-receive hook to update detached tree on receive | |
cat > hooks/post-receive << EOF | |
#!/bin/sh | |
WORK_DIR=/home/$USERNAME/deploy/$PROJECTNAME | |
DEPLOY_LOG=/home/$USERNAME/deploy/deploy-$PROJECTNAME.log | |
echo === \`date\` === | tee -a \$DEPLOY_LOG | |
git --git-dir \$WORK_DIR/.git --work-tree \$WORK_DIR pull origin | tee -a \$DEPLOY_LOG | |
UWSGI_PID=/tmp/$PROJECTNAME-uwsgi.pid | |
if [ -f "\$UWSGI_PID" ]; then | |
echo "Restarting uwsgi."; | |
kill -HUP \$(cat \$UWSGI_PID); | |
fi | |
EOF | |
chmod +x hooks/post-receive | |
# Setup static assets to be served by nginx directly | |
ln -s ~/deploy/$PROJECTNAME/static ~/public_html/$PROJECTNAME/static | |
# Virtualenv | |
virtualenv ~/env/$PROJECTNAME | |
source ~/env/$PROJECTNAME/bin/activate | |
# Install root config files | |
## Supervisor | |
sudo tee /etc/supervisor/conf.d/$PROJECTNAME.conf > /dev/null << EOF | |
[program:$PROJECTNAME-uwsgi] | |
directory=/home/$USERNAME/deploy/$PROJECTNAME | |
user=$USERNAME | |
command=/usr/bin/uwsgi_python -C -H /home/$USERNAME/env/$PROJECTNAME -L -w wsgi --socket /tmp/$PROJECTNAME-uwsgi.sock --master --processes 4 --pidfile /tmp/$PROJECTNAME-uwsgi.pid --module $PROJECTNAME --callable app --harakiri=20 --limit-as=128 --max-requests=5000 --vacuum | |
stdout_logfile=/home/$USERNAME/logs/$PROJECTNAME/uwsgi.log | |
redirect_stderr=true | |
stopsignal=INT | |
autorestart=true | |
EOF | |
## Nginx | |
sudo tee /etc/nginx/sites-available/$PROJECTNAME > /dev/null << EOF | |
server { | |
listen 80; | |
server_name $DOMAIN; | |
access_log /home/$USERNAME/logs/$PROJECTNAME/access.log; | |
charset utf-8; | |
gzip on; | |
gzip_http_version 1.1; | |
gzip_vary on; | |
gzip_comp_level 6; | |
gzip_proxied any; | |
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript; | |
gzip_buffers 16 8k; | |
gzip_disable "MSIE [1-6].(?!.*SV1)"; | |
location ~ ^/(robots.txt|favicon.ico)\$ { | |
root /home/$USERNAME/public_html/$PROJECTNAME/static; | |
} | |
location /static { | |
root /home/$USERNAME/public_html/$PROJECTNAME/; | |
expires max; | |
add_header Cache-Control "public"; | |
} | |
location / { | |
include uwsgi_params; | |
uwsgi_pass unix:///tmp/$PROJECTNAME-uwsgi.sock; | |
uwsgi_param SCRIPT_NAME ""; | |
} | |
} | |
server { | |
listen 80; | |
server_name www.$DOMAIN; | |
rewrite ^/(.*) http://$DOMAIN/\$1 permanent; | |
} | |
EOF | |
## Enable new Nginx config | |
sudo ln -sft /etc/nginx/sites-enabled/ "../sites-available/$PROJECTNAME" | |
# Restart things | |
sudo service nginx restart | |
sudo service supervisor stop | |
sudo service supervisor start | |
# Print instructions | |
IP_ADDRESS="$(/sbin/ifconfig eth0 | awk -F: '/inet addr:/ {print $2}' | awk '{ print $1 }')" | |
cat << EOF | |
Setup your development clone as follows: | |
git branch live | |
git remote add -t live live ssh://$USERNAME@$IP_ADDRESS/home/$USERNAME/repo/$PROJECTNAME | |
Now you can deploy: | |
git checkout live | |
git merge master | |
git checkout master | |
git push live | |
Or use this handy 'deploy' alias in your ~/.gitconfig file: | |
deploy = "!merge(){ git checkout \$2 && git merge \$1 && git push \$2 && git checkout \${1#refs/heads/}; }; merge \$(git symbolic-ref HEAD) \$1" | |
So you can do (from 'master'): | |
git deploy live | |
Happy pushing! | |
EOF |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## be sure you have already have latest software installed | |
apt-get update | |
apt-get dist-upgrade -y | |
apt-get upgrade -y | |
apt-get install -y build-essential git-core | |
apt-get install -y python-software-properties python-dev python-pip | |
pip install virtualenv | |
apt-get install -y libfreetype6-dev libjpeg62-dev libpng12-dev | |
rm -rf /usr/lib/{libfreetype.so,libz.so,libjpeg.so} | |
ln -s /usr/lib/*-linux-gnu/{libfreetype.so,libz.so,libjpeg.so} /usr/lib/ | |
apt-get install -y nginx | |
# Nginx-related: Move the default nginx config name so that it doesn't take | |
# priority over our other configurations. | |
mv /etc/nginx/sites-enabled/{default,99_default} | |
apt-get install -y supervisor | |
apt-get install -y uwsgi uwsgi-plugin-python python-uwsgidecorators | |
adduser --disabled-password --gecos "" deploy | |
passwd deploy <<EOF | |
password | |
password | |
EOF | |
cd /home/deploy | |
sudo -u deploy wget "https://raw.github.com/gist/3667663/create_project.sh" | |
sudo -u deploy chmod +x create_project.sh | |
echo "Adding deploy user to sudoers" | |
echo "deploy ALL=(ALL) NOPASSWD:ALL" | tee -a /etc/sudoers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# interactive | |
# re-logins as user deploy | |
su - deploy | |
# creates all the nescessary changes | |
./create_project.sh noimageyet youdomain.com | |
# follow ./create_project.sh instructions | |
# after pushing code (local env) to server's git repository | |
# proceed with app configuration | |
# | |
# this will install app dependencies | |
source ~/env/noimageyet/local/bin/activate | |
pip install -r deploy/noimageyet/requirements.txt | |
# noimageyet depends on Truetype font (Arial.ttf by default) being installed | |
sudo apt-get install -y msttcorefonts | |
# app configuration | |
tee deploy/noimageyet/.config.json > /dev/null << EOF | |
{ | |
"NOIMAGEYET_TTF" : "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf", | |
"BOOTSTRAP_USE_CDN" : false, | |
"BOOTSTRAP_USE_MINIFIED" : true, | |
"BOOTSTRAP_GOOGLE_ANALYTICS_ACCOUNT" : false, | |
"LOG_FILE" : "/home/deploy/logs/noimageyet/app.log", | |
"HOST" : "http://192.168.1.103/" | |
} | |
EOF | |
# restart services | |
sudo service nginx restart | |
sudo service supervisor stop | |
sleep 3 | |
sudo service supervisor start |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment