Setting up "Heroku like" git push deploys on a VPS is so easy
I was reading about Docker closing a $40M series C round this morning. While containerization is extremely useful at large scale, I think that the vast majority of individual developers and small teams write many web applications that don't need to scale beyond a beefed up VPS or single physical server.
For a good developer experience it is difficult to beat a slightly expensive but convenient PaaS like Heroku. However, if you have many small web app projects and experiments then hosting on a PaaS and paying $30-$50/month per application can add up, year after year. If you need failover and scalability, then paying for a PaaS or implementing a more failsafe system on AWS makes sense. For experimental projects that don't need close to 100% uptime, I set up a .git/hooks/post-commit git hook like this:
./rsync.sh ssh mark@myappname.com 'bash -s' < run.shI have my DNS setup for myappname.com (this is not a real domain, I am using it as an example) and all other domains for my example/experimental web apps point to the IP address of my large VPS. My rsync.sh files look like this:
rsync -e "ssh" -avz --delete --delete-excluded \ --exclude-from=/Users/mark/Code/mywebapps/myappname.com/rsync_exclude \ /Users/mark/BITBUCKET/myappname.com mark@myappname.com:/home/mark/In my rsync_exclude file I specify to not copy my .git folder to the server:
.gitThe run.sh file that gets remotely executed on my server looks like this:
This is the pattern I use for running Clojure web apps. Running Ruby/Sinatra, Haskell, and Java apps is similar.#! /bin/bash ps aux | grep -e 'myappname.com' | grep -v grep | awk '{print $2}' | xargs -i kill {} (cd myappname.com; lein deps; nohup lein trampoline run prod > out.log&)
Since I tend to run many small experiments on a single large VPS, I use entries like the following in my /etc/rc.local file to restart all applications if I reboot the VPS:
(cd /home/mark/myappname.com ; su mark -c 'nohup lein trampoline run prod > out.log&') &
I use an account on the server that does not have root or sudo privileges so my web apps use non-privileged ports and I use nginx as a proxy. In my nginx.conf file, I have entries like the following to map non-privileged to virtual domain names:
server { listen 80; server_name myappname.com www.myappname.com; location / { proxy_pass http://localhost:7070; 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; } error_page 500 502 503 504 /error.html; location = /error.html { root /etc/nginx; } }In this example, the myappname.com application is running on the non-privileged port 7070 and this app would be accessed as http://myappname.com or http://www.myappname.com. On my laptop, just doing a git push has the new version of my app running on my server in a few seconds.
Comments
Post a Comment