dumb-deploy
Simple application deployment for side projects
This is a stupid script I use to deploy applications to a remote web server for my side projects with minimal hassle/setup - on a budget!
Install
$ yarn add dumb-deploy
Usage
Here's an example for deploying a containerized docker app:
Docker App
const deploy = require("dumb-deploy");
async function downCmd() {
return `docker ps -a --filter="name=nginx" --format "{{.ID}}" | xargs -I{} docker rm --force "{}"`;
}
async function upCmd({ deployPath }) {
return `cd ${deployPath} && docker-compose up --no-deps -d nginx`;
}
async function main() {
await deploy({
appName: "nginx",
appDir: path.join(__dirname, ".."),
downCmd,
upCmd,
user: "mark",
host: "1.2.3.4",
prodRoot: "/home/mark/prod",
sshId: "/Users/mark/.ssh/deploy",
});
}
main();
Here's another example for a NodeJS app:
NodeJS App
deploy/deploy.js
:
const deploy = require("dumb-deploy");
const path = require("path");
async function downCmd({ deployPath }) {
return path.join(deployPath, "deploy", "down.sh");
}
async function upCmd({ deployPath }) {
return path.join(deployPath, "deploy", "up.sh");
}
async function main() {
await deploy({
appName: "api_server",
appDir: path.join(__dirname, ".."),
downCmd,
upCmd,
user: "mark",
host: "1.2.3.4",
prodRoot: "/home/mark/prod",
sshId: "/Users/mark/.ssh/deploy",
});
}
main();
deploy/down.sh
:
#!/bin/bash
set -euo pipefail
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ROOT="${DIR}/.."
ps aux | grep forever | grep build/index.js | awk '{print $2}' | xargs -I{} kill -9 {} || true
lsof -i :44525 | grep node | awk '{print $2}' | xargs -I{} kill -9 {} || true
deploy/up.sh
:
#!/bin/bash
set -euo pipefail
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
ROOT="${DIR}/.."
pushd "${ROOT}"
make build
NODE_ENV=production yarn start
- When you want to push a new version of your app to your webserver, run your
deploy.js
script - The application files will be rsync'd to a new directory
- .gitignore files will not rsync'd
- I'd suggest calling your deploy script manually instead of putting it in a CI pipeline. Since you're artisanally hand crafting your deploy logic, it's probably going to break sometimes if something gets stuck. You'll want to be able to ssh in and unjam things occasionally.
Motivation: What is this for?
- Side projects that need a server runtime exposed to the world wide web
- (For simple static websites, one should probably just use vercel or netlify etc)
Why not use <insert SaaS cloud provider here>?
- I'm cheap, and I want to deploy my side projects to the web for the least amount of money
- But I also don't want to compromise on availability (e.g. sleeping Heroku dynos)
- I don't want to deal with complex networking setups to let the DB talk to the API server etc (sorry AWS)
- I want an actual relational database that lives close to the API server (sorry Fauna)
- This lets me deploy a Postgres DB, API Server and Web Server all on the same vultr web server for $2.50/month
- Once the project graduates beyond "side project" to "serious production", you should probably ditch this and seek out a SaaS/AWS solution to get fancy CI pipelines,
Why not use Lambda Functions for everything?
-
I'll appeal to authority: The Good Parts of AWS
:
A problem we often see is that people
sometimes mistake Lambda for a general-purpose
application host. Unlike EC2, it is very hard to run a
sophisticated piece of software on Lambda without
making some very drastic changes to your application and
accepting some significant new limitations from the
platform.
Treating Lambda as a general-purpose host for your
applications is risky. It might look compelling at first—no
servers to manage, no operating system to worry about,
and no costs when unused—but Lambda’s limitations are
insidious hidden risks that typically reveal themselves
once your application evolves into something bigger.
Then, things start coming at you one after the other, and
before you know it, you are spending most of your time
trying to figure out convoluted solutions to Lambda’s
numerous limitations.
(I'll avoid quoting further, you should definitely buy the book if you're doing anything with AWS.)
Non goals
- Rollbacks (maybe I'll add this in the future if I can get the API simple enough)
- Fancy blue/green deployments. You're probably going to have a couple of minutes of downtime during deploys.