Skip to content

Instantly share code, notes, and snippets.

@cedricziel
Last active November 17, 2016 23:14
Show Gist options
  • Save cedricziel/4ec91a5c594b1e8fc7d0 to your computer and use it in GitHub Desktop.
Save cedricziel/4ec91a5c594b1e8fc7d0 to your computer and use it in GitHub Desktop.
Deploy a Play! Framework Application behind nginx -> haproxy -> netty (Play2 core) for transient upgrading. This setup fully supports Websockets in almost any variation. - But most importantly uses 2 instances minimum to allow seamless upgrade. Prepare the instances with "cd app/instances/$instance && ~/app/play/play clean compile stage"
fooapp@srv:~$ cat app/env/PLAY_OPTS
export DATABASE_URL="jdbc:postgresql://127.0.0.1/foobar"
# We could wire a different configuration file here
# or set up a different database on the fly
export PLAY_OPTS="-DapplyEvolutions.default=true -DapplyDownEvolutions.default=true -Ddb.default.url="$DATABASE_URL" -Ddb.default.user=fooapp -Ddb.default.password=fooapppw -Ddb.default.driver=org.postgresql.Driver"
#!/bin/bash
# These environment variables are sometimes needed by the running daemons
export USER=fooapp
export HOME=/home/fooapp
# Include the user-specific profile, it's actually called .profile on debian.
$HOME/.profile
# You can load ENV-Vars from a file.
# I load $PLAY_OPTS from it to read database configuration
# and evolutions settings
source "$HOME/app/env/PLAY_OPTS"
# Now let's go!
# New Relic Agent is loaded as well from a known place
exec /home/fooapp/app/instances/alpha/target/universal/stage/bin/fooapp -J-javaagent:/home/fooapp/app/lib/newrelic/newrelic.jar -Dhttp.port=62002 "$PLAY_OPTS" 2>&1
# There's more! Common structure ensures easy management through some scripts in ~/app/bin,
# ENV-var files in ~/app/env, a git repo in ~/app/src, Play in ~/app/play, libs, configs for daemontools daemons in ~/app/etc
# and most importantly at least two play instances to minimize downtime.
fooapp@serv:~$ tree app -L 2
app
├── bin
│   ├── control
│   └── manage
├── downloads
│   └── play-2.2.2.zip
├── env
│   └── PLAY_OPTS
├── etc
│   └── haproxy
├── instances
│   ├── alpha
│   └── beta
├── lib
│   └── newrelic
├── play
│   ├── CONTRIBUTING.md
│   ├── framework
│   ├── play
│   ├── play.bat
│   ├── README.md
│   ├── repository
│   └── samples
├── src
│   ├── branches
│   ├── config
│   ├── description
│   ├── HEAD
│   ├── hooks
│   ├── info
│   ├── objects
│   └── refs
└── templates
├── haproxy.cfg.tpl
└── post-receive.tpl
21 directories, 13 files
# I run haproxy with DJBs daemontools, so no daemon here
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#log loghost local0 info
maxconn 4096
#debug
#quiet
user fooapp
group fooapp
defaults
log global
mode http
option httplog
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
listen fooapp-master 127.0.0.1:62000
mode http
stats enable
# change this, or disable stats!
stats auth user:statspw
balance leastconn
option httpclose
option forwardfor
option httpchk GET / HTTP/1.0
server alpha 127.0.0.1:62002 check
server beta 127.0.0.1:62003 check
server {
server_name fooapp.org;
listen server.ip;
listen [ip:v6:ip] default_server ipv6only=on;
root /home/appuser/public_html;
index index.html index.htm index.php;
access_log /var/log/nginx/fooapp_access_log;
error_log /var/log/nginx/fooapp_error_log;
ssl_certificate /home/fooapp/ssl.cert;
ssl_certificate_key /home/fooapp/ssl.key;
# Little caveat: on upgrade of alpha (which involves the "clean" task,
# this would fail. See fx http://stackoverflow.com/questions/5555419/nginx-search-for-static-content-in-multiple-directories
# for a possible solution
location /assets {
root /home/fooapp/app/instances/alpha/target/scala-2.10/classes/public;
rewrite ^/assets(/.*)$ $1 break;
}
location / {
# haproxy balances on port 62000
proxy_pass http://127.0.0.1:62000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_buffering off;
proxy_connect_timeout 43200000;
proxy_read_timeout 43200000;
proxy_send_timeout 43200000;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment