{"id":18400920,"url":"https://github.com/magicmark/dumb-deploy","last_synced_at":"2025-04-12T16:59:39.794Z","repository":{"id":69481526,"uuid":"285949842","full_name":"magicmark/dumb-deploy","owner":"magicmark","description":"dumb deploy scripts","archived":false,"fork":false,"pushed_at":"2020-08-08T16:53:28.000Z","size":22,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-16T03:25:09.499Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/magicmark.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-08T01:16:48.000Z","updated_at":"2022-01-25T23:12:04.000Z","dependencies_parsed_at":"2023-03-15T22:00:42.952Z","dependency_job_id":null,"html_url":"https://github.com/magicmark/dumb-deploy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magicmark%2Fdumb-deploy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magicmark%2Fdumb-deploy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magicmark%2Fdumb-deploy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magicmark%2Fdumb-deploy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/magicmark","download_url":"https://codeload.github.com/magicmark/dumb-deploy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248602232,"owners_count":21131613,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T02:37:15.662Z","updated_at":"2025-04-12T16:59:39.762Z","avatar_url":"https://github.com/magicmark.png","language":"JavaScript","readme":"# dumb-deploy\n\n**Simple application deployment for side projects**\n\nThis 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!\n\n## Install\n\n```\n$ yarn add dumb-deploy\n```\n\n### Usage\n\nHere's an example for deploying a containerized docker app:\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eDocker App\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n```js\nconst deploy = require(\"dumb-deploy\");\n\n/**\n * downCmd should kill any previous instances of the app.\n * Be agressive. We don't provide any context to the previous deployment.\n * Be careful not to kill other applications running on the server.\n * (Don't worry about cleaning up the directory, we'll do that for you.)\n */\nasync function downCmd() {\n  return `docker ps -a --filter=\"name=nginx\" --format \"{{.ID}}\" | xargs -I{} docker rm --force \"{}\"`;\n}\n\n/**\n * Start the application. Process should not run in the foreground.\n */\nasync function upCmd({ deployPath }) {\n  // https://docs.docker.com/compose/production/#deploying-changes\n  return `cd ${deployPath} \u0026\u0026 docker-compose up --no-deps -d nginx`;\n}\n\nasync function main() {\n  await deploy({\n    // Specify a directory-friendly name for this app\n    appName: \"nginx\",\n    // Path to the root of your app\n    appDir: path.join(__dirname, \"..\"),\n    downCmd,\n    upCmd,\n    // user/host of the webserver\n    user: \"mark\",\n    host: \"1.2.3.4\",\n    // Where should we deploy applications to on the host?\n    prodRoot: \"/home/mark/prod\",\n    // Path to an SSH key that we can SSH into the server with\n    sshId: \"/Users/mark/.ssh/deploy\",\n  });\n}\n\nmain();\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\nHere's another example for a NodeJS app:\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eNodeJS App\u003c/b\u003e\u003c/summary\u003e\n\u003cp\u003e\n\n`deploy/deploy.js`:\n\n```js\nconst deploy = require(\"dumb-deploy\");\nconst path = require(\"path\");\n\nasync function downCmd({ deployPath }) {\n  return path.join(deployPath, \"deploy\", \"down.sh\");\n}\n\nasync function upCmd({ deployPath }) {\n  return path.join(deployPath, \"deploy\", \"up.sh\");\n}\n\nasync function main() {\n  await deploy({\n    // Specify a directory-friendly name for this app\n    appName: \"api_server\",\n    // Path to the root of your app\n    appDir: path.join(__dirname, \"..\"),\n    downCmd,\n    upCmd,\n    // user/host of the webserver\n    user: \"mark\",\n    host: \"1.2.3.4\",\n    // Where should we deploy applications to on the host?\n    prodRoot: \"/home/mark/prod\",\n    // Path to an SSH key that we can SSH into the server with\n    sshId: \"/Users/mark/.ssh/deploy\",\n  });\n}\n\nmain();\n```\n\n`deploy/down.sh`:\n\n```bash\n#!/bin/bash\nset -euo pipefail\n\n# https://stackoverflow.com/a/246128/4396258\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" \u003e/dev/null 2\u003e\u00261 \u0026\u0026 pwd )\"\nROOT=\"${DIR}/..\"\n\n# Brutally clean up all old instances of the app running under forever. Life's too short for gracefulness.\n# (Make sure to grep filter for our app specifcially tho, to avoid killing other apps running on this server)\nps aux | grep forever | grep build/index.js | awk '{print $2}' | xargs -I{} kill -9 {} || true\nlsof -i :44525 | grep node | awk '{print $2}' | xargs -I{} kill -9 {} || true\n```\n\n`deploy/up.sh`:\n\n```bash\n#!/bin/bash\nset -euo pipefail\n\n# https://stackoverflow.com/a/246128/4396258\nDIR=\"$( cd \"$( dirname \"${BASH_SOURCE[0]}\" )\" \u003e/dev/null 2\u003e\u00261 \u0026\u0026 pwd )\"\nROOT=\"${DIR}/..\"\n\n# run commands from the deploy dir root\npushd \"${ROOT}\"\n\nmake build\nNODE_ENV=production yarn start\n```\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n- When you want to push a new version of your app to your webserver, run your `deploy.js` script\n- The application files will be rsync'd to a new directory\n- .gitignore files will not rsync'd\n- 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.\n\n## Motivation: What is this for?\n\n- **Side projects** that need a server runtime exposed to the world wide web\n- (For simple static websites, one should probably just use vercel or netlify etc)\n\n### Why not use \\\u003cinsert SaaS cloud provider here\u003e?\n\n- I'm cheap, and I want to deploy my side projects to the web for the least amount of money\n- But I also don't want to compromise on availability (e.g. sleeping Heroku dynos)\n- I don't want to deal with complex networking setups to let the DB talk to the API server etc (sorry AWS)\n- I want an actual relational database that lives close to the API server (sorry Fauna)\n- This lets me deploy a Postgres DB, API Server and Web Server all on the same vultr web server for \\$2.50/month\n- 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,\n\n### Why not use Lambda Functions for everything?\n\n- I'll appeal to authority: [The Good Parts of AWS\n  ](https://www.goodreads.com/book/show/49966180-the-good-parts-of-aws):\n\n  \u003e A problem we often see is that people\n  \u003e sometimes mistake Lambda for a general-purpose\n  \u003e application host. Unlike EC2, it is very hard to run a\n  \u003e sophisticated piece of software on Lambda without\n  \u003e making some very drastic changes to your application and\n  \u003e accepting some significant new limitations from the\n  \u003e platform.\n  \u003e\n  \u003e Treating Lambda as a general-purpose host for your\n  \u003e applications is risky. It might look compelling at first—no\n  \u003e servers to manage, no operating system to worry about,\n  \u003e and no costs when unused—but Lambda’s limitations are\n  \u003e insidious hidden risks that typically reveal themselves\n  \u003e once your application evolves into something bigger.\n  \u003e Then, things start coming at you one after the other, and\n  \u003e before you know it, you are spending most of your time\n  \u003e trying to figure out convoluted solutions to Lambda’s\n  \u003e numerous limitations.\n\n  (I'll avoid quoting further, you should definitely [buy the book](https://gumroad.com/l/aws-good-parts) if you're doing anything with AWS.)\n\n## Non goals\n\n- Rollbacks (maybe I'll add this in the future if I can get the API simple enough)\n- Fancy [blue/green deployments](https://martinfowler.com/bliki/BlueGreenDeployment.html). You're probably going to have a couple of minutes of downtime during deploys.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagicmark%2Fdumb-deploy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmagicmark%2Fdumb-deploy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagicmark%2Fdumb-deploy/lists"}