Created
September 11, 2011 19:58
-
-
Save shazow/1210041 to your computer and use it in GitHub Desktop.
Setup deployment target for Nginx + Python/uWSGI + Supervisor + Git (for a Linode Stackscript)
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 | |
# 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