Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Setup deployment target for Nginx + Python/uWSGI + Supervisor + Git (for a Linode Stackscript)
#!/bin/bash
# Setup deployment target for Nginx + Python/uWSGI + Supervisor + Git
# From: https://gist.github.com/1210041
function usage() {
cat << EOF
Usage: $0 PROJECT_NAME [DOMAIN] [OPTIONS]
Options:
-y No prompts, assume yes to all.
-1 One-step, don't try to do the root parts automagically.
-p Only print deploy instructions, don't do anything else.
-f Overwrite any existing configurations.
Example:
$0 -y foo fooapp.com
EOF
}
function deploy_instructions() {
IP_ADDRESS="$(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://$1@$IP_ADDRESS/home/$1/repo/$2
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
}
USERNAME="$(whoami)"
USERTARGET="$USERNAME"
positional=( );
while [ "$1" ]; do
case "$1" in
"-h")
usage
exit
;;
"-p")
ONLY_INSTRUCTIONS="y"
shift
;;
"-f")
FORCE="y"
shift
;;
"-y")
NOPROMPT="y"
shift
;;
"-1")
ONESTEP="y"
shift
;;
"-2")
TWOSTEP="y"
shift
USERTARGET="$1"
shift
;;
*)
positional[${#positional[*]}]="$1"
shift
;;
esac
done
PROJECTNAME="${positional[0]}"
DOMAIN="${positional[1]}"
if [ ! "$PROJECTNAME" ]; then
echo "Error: Must specify a project name."
usage
exit 3;
fi
if [ ! "$DOMAIN" ]; then
DOMAIN="$PROJECTNAME.com"
fi
if [ "$ONLY_INSTRUCTIONS" == "y" ]; then
deploy_instructions $USERTARGET $PROJECTNAME
exit
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
if [ "$USERNAME" != "root" ]; then ################### Userland configuration ##
# Setup our directory structure
mkdir ~/{deploy,env,logs,public_html,repo,uploads}
mkdir ~/{repo,deploy,logs,public_html,uploads}/$PROJECTNAME
git_repo=~/repo/$PROJECTNAME
if [ -d $git_repo/config ] && [ "$FORCE" != "y" ]; then
echo "Git repository already exists, skipping: $git_repo"
else
# Create a detached tree repository
cd $git_repo
git init --bare
git config core.worktree ~/deploy/$PROJECTNAME
git config receive.denycurrentbranch ignore
# Setup post-receive hook to update detached tree on receive
cat > hooks/post-receive << EOF
#!/bin/sh
git checkout -f
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
cd -
fi
# Setup static assets to be served by nginx directly
ln -s ~/deploy/$PROJECTNAME/static ~/public_html/$PROJECTNAME/static
# Virtualenv
virtualenv_path=~/env/$PROJECTNAME
if [ -d $virtualenv_path ] && [ "$FORCE" != "y" ]; then
echo "Virtualenv already exists, skipping: $virtualenv_path"
else
rm -rf $virtualenv_path
virtualenv $virtualenv_path
fi
source $virtualenv_path/bin/activate
if [ "$ONESTEP" != "y" ]; then
echo "The rest of this script requires root permission, please give sudo permission or run it again as root manually."
command="$0 $PROJECTNAME -2 $USERNAME -y"
if [ "$FORCE" == "y" ]; then
command="$command -f"
fi
sudo $command
fi
else ################################################# Rootland configuration ##
if [ ! "$TWOSTEP" ]; then
echo "Warning: Running as root, only doing root parts."
fi
# Install root config files
## Supervisor
supervisor_conf_path=/etc/supervisor/conf.d/$PROJECTNAME.conf
if [ -f $supervisor_conf_path ] && [ "$FORCE" != "y" ]; then
echo "Supervisor configuration already exists, skipping: $supervisor_conf_path"
else
tee $supervisor_conf_path > /dev/null << EOF
[program:$PROJECTNAME-uwsgi]
directory=/home/$USERTARGET/deploy/$PROJECTNAME
user=$USERTARGET
command=/usr/bin/uwsgi-python -C -H /home/$USERTARGET/env/$PROJECTNAME -L -w wsgi --socket /tmp/$PROJECTNAME-uwsgi.sock --master --processes 1 --pidfile /tmp/$PROJECTNAME-uwsgi.pid
stdout_logfile=/home/$USERTARGET/logs/$PROJECTNAME/uwsgi.log
redirect_stderr=true
stopsignal=INT
autorestart=true
EOF
fi
## Nginx
nginx_conf_path=/etc/nginx/sites-available/$PROJECTNAME
if [ -f $nginx_conf_path ] && [ "$FORCE" != "y" ]; then
echo "Nginx site configuration already exists, skipping: $nginx_conf_path"
else
tee $nginx_conf_path > /dev/null << EOF
server {
listen 80;
server_name $DOMAIN;
access_log /home/$USERTARGET/logs/$PROJECTNAME/access.log;
charset utf-8;
client_max_body_size 32M;
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/$USERTARGET/public_html/$PROJECTNAME/static;
}
location /static {
root /home/$USERTARGET/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
ln -sft /etc/nginx/sites-enabled/ "../sites-available/$PROJECTNAME"
fi
# Restart things
/etc/init.d/nginx reload
supervisorctl reload
fi
# Print instructions
if [ "$TWOSTEP" == "y" ]; then
deploy_instructions $USERTARGET $PROJECTNAME
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment