├── .gitignore ├── .jscsrc ├── .jshintrc ├── LICENSE ├── README.md ├── paastor-cli ├── .gitignore ├── .jscsrc ├── .jshintrc ├── LICENSE ├── README.md ├── app.js ├── cli.js ├── client.js └── package.json ├── paastor-server ├── .jshintrc ├── bin │ └── www.js ├── config.js ├── gulpfile.js ├── lib │ ├── genrand.js │ └── hash.js ├── models.js ├── paastor.js ├── package.json ├── public │ ├── css │ │ ├── animate.css │ │ ├── bootstrap-clear.css │ │ ├── bootstrap-lgr.css │ │ └── style.css │ ├── dash.png │ ├── diagram.png │ ├── email-logo.gif │ ├── email-logo.xcf │ ├── favicon-old-white.png │ ├── favicon-old.png │ ├── favicon.png │ ├── js │ │ ├── app.js │ │ ├── controllers │ │ │ ├── AccountEditController.js │ │ │ ├── AppCreateController.js │ │ │ ├── AppSslController.js │ │ │ ├── ManageServicesController.js │ │ │ ├── MongoController.js │ │ │ ├── NavController.js │ │ │ ├── RedisController.js │ │ │ ├── VpsCreateController.js │ │ │ ├── VpsListController.js │ │ │ └── VpsViewController.js │ │ ├── directives │ │ │ └── pa-enter.js │ │ ├── readable-time.js │ │ └── services.js │ ├── p2.xcf │ ├── pages │ │ ├── changelog.html │ │ ├── concepts.html │ │ ├── contact.html │ │ ├── docs.html │ │ ├── faq.html │ │ ├── mongo.html │ │ ├── pstr-cli.html │ │ ├── redis.html │ │ ├── sheep-system.html │ │ ├── ssl.html │ │ ├── terms.html │ │ ├── usage.html │ │ └── vision.html │ ├── redis-white.png │ ├── redis.png │ └── sman.png ├── routes │ ├── api.js │ └── home.js ├── sheep-client.js ├── sheep-ssh-client.js ├── spec │ ├── api.spec.js │ ├── paastor-credentials.json.example │ ├── seed-stripe.js │ ├── sheep-client.spec.js │ ├── sheep-ssh-client.spec.js │ └── vps-credentials.json.example └── views │ ├── conf.jade │ ├── error.jade │ ├── index.jade │ ├── layout.jade │ ├── pages │ ├── changelog.jade │ ├── concepts.jade │ ├── contact.jade │ ├── docs.jade │ ├── faq.jade │ ├── mongo.jade │ ├── pstr-cli.jade │ ├── redis.jade │ ├── sheep-system.jade │ ├── ssl.jade │ ├── terms.jade │ ├── usage.jade │ └── vision.jade │ ├── parts │ └── ssl.jade │ ├── reset.jade │ └── templates │ ├── 404.jade │ ├── account-edit.jade │ ├── app-create.jade │ ├── app-ssl.jade │ ├── home.jade │ ├── manage-services.jade │ ├── mongo.jade │ ├── redis.jade │ ├── vps-create.jade │ ├── vps-list.jade │ └── vps-view.jade ├── paastor-sheep ├── .gitignore ├── api.js ├── lib │ └── hash.js ├── package.json ├── proxy.js └── scripts │ ├── sheep │ └── start.sh └── pack /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | 3 | # Paastor 4 | node_modules 5 | 6 | # Paastor tests 7 | paastor-server/spec/vps-credentials.json 8 | paastor-server/spec/paastor-credentials.json 9 | 10 | 11 | # Sheep 12 | # do not ignore node_modules, at this point 13 | sheep/system.json 14 | build/ 15 | sheep_apps/ 16 | sheep_logs/ 17 | sheep.cert 18 | sheep.key 19 | 20 | 21 | # CLI 22 | cli/node_modules/ 23 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": [ 3 | "if", 4 | "else", 5 | "for", 6 | "while", 7 | "do", 8 | "try", 9 | "catch" 10 | ], 11 | "requireSpaceAfterKeywords": [ 12 | "do", 13 | "for", 14 | "if", 15 | "else", 16 | "switch", 17 | "case", 18 | "try", 19 | "void", 20 | "while", 21 | "return", 22 | "function" 23 | ], 24 | "disallowKeywords": ["with"], 25 | "requireSpaceBeforeBlockStatements": true, 26 | "requireSpacesInConditionalExpression": true, 27 | "disallowSpacesInNamedFunctionExpression": { 28 | "beforeOpeningRoundBrace": true 29 | }, 30 | "disallowSpacesInFunctionDeclaration": { 31 | "beforeOpeningRoundBrace": true 32 | }, 33 | "requireSpacesInFunction": { 34 | "beforeOpeningCurlyBrace": true 35 | }, 36 | "disallowMultipleVarDecl": true, 37 | "disallowMultipleLineBreaks": false, 38 | "requireBlocksOnNewline": 1, 39 | "disallowQuotedKeysInObjects": "allButReserved", 40 | "disallowSpaceAfterObjectKeys": true, 41 | "requireSpaceBeforeObjectValues": true, 42 | "requireCommaBeforeLineBreak": true, 43 | "disallowSpaceBeforePostfixUnaryOperators": true, 44 | "requireSpaceBeforeBinaryOperators": true, 45 | "requireSpaceAfterBinaryOperators": true, 46 | "disallowMixedSpacesAndTabs": true, 47 | "disallowTrailingWhitespace": true, 48 | "disallowTrailingComma": true, 49 | "requireLineFeedAtFileEnd": true, 50 | "requireCapitalizedConstructors": true, 51 | "disallowYodaConditions": true, 52 | "validateParameterSeparator": ", ", 53 | "validateIndentation": 4, 54 | "excludeFiles": [ 55 | "node_modules/**", 56 | "coverage/**", 57 | "assets/**", 58 | ".tmp/**" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "curly": true, 4 | "undef": true, 5 | "unused": false, 6 | "trailing": true, 7 | "strict": true, 8 | "laxbreak": true, 9 | "laxcomma": true, 10 | "mocha": true, 11 | "predef": [ 12 | "-Promise", 13 | "xit", 14 | "xdescribe" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Jeff H. Parrish 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **paastor** 2 | 3 | *A hostable gui for deployment management of Node.js, MongoDB, and Redis apps on Ubuntu servers.* 4 | 5 | **Formerly paastor.com**, this project was open sourced and the website 6 | was shutdown because I do not have time to maintain it. Apologies to 7 | the users. 8 | 9 | # **sheep** 10 | 11 | *A proxy and api for running node apps on a slave VPS.* 12 | 13 | ## How it works 14 | 15 | ![diagram of paastor setup](https://raw.githubusercontent.com/paastor/paastor/master/paastor-server/public/diagram.png) 16 | 17 | ### Managing servers via gui 18 | 19 | ![screenshot of paastor gui](https://raw.githubusercontent.com/paastor/paastor/master/paastor-server/public/dash.png) 20 | 21 | ### Deploy with the command line tool 22 | 23 | ``` 24 | pstr push my-server myapp 25 | ``` 26 | 27 | ## Development and Running Locally 28 | 29 | requirements: 30 | 31 | * node.js 32 | * mongodb 33 | * gulp 34 | 35 | installing: 36 | 37 | git clone https://github.com/ruffrey/paastor 38 | cd paastor && npm install 39 | cd sheep && npm install 40 | 41 | sheep is an express app inside the paastor directory, hence the double npm install. 42 | 43 | running: 44 | 45 | npm start 46 | 47 | or 48 | 49 | npm run debug-start 50 | 51 | Also 52 | 53 | gulp 54 | 55 | will watch and perform tasks like recompiling jade and client JS. 56 | 57 | 58 | ## Default Server Locations 59 | 60 | * *paastor* is at `localhost:2999` 61 | * *sheep proxy* is at `localhost:3001` in development and `localhost:80` in production 62 | * *sheep api* is at `localhost:3000` 63 | 64 | ## Default Services 65 | 66 | Install mongodb and redis via gui. 67 | 68 | ## Security 69 | 70 | * header `Paastor-Secret` is sent during paastor --> sheep api communications. 71 | * secret is stored **hashed and salted** on sheep, by sheep, inside `system.json`. 72 | * secret is stored in paastor database under the `Vps.secret` property 73 | * YOU set the secret when creating a Vps 74 | * To tell **sheep** to reset and hash the secret, start the instance with an environment variable `HASH_RESET=` and your new secret. `cd /path/to/sheep && HASH_RESET=asdfpassword npm start` 75 | 76 | 77 | ## System Settings 78 | * `email` Login email address. 79 | * `name` System informational name. 80 | * `password` Hashed login password. 81 | * `sshkey` Generated from the paastor gui. System public ssh key - add this to your git repos. 82 | 83 | 84 | ## Tests 85 | 86 | First add a vps for testing at `spec/vps-credentials.json` and set up paastor (http://localhost:2999/), then add paastor credentials at `spec/paastor-credentials.json`. 87 | 88 | An example file is at `spec/vps-credentials.json.example`. 89 | 90 | ##### Running the Tests 91 | 92 | npm test 93 | 94 | If you have problems, try 95 | 96 | npm run debug-test 97 | 98 | for more verbose output. 99 | 100 | If tests fail, you might end up with node processes that have gone rogue. Find them and stop them: 101 | 102 | ps -l | grep node 103 | 104 | kill [pid goes here] 105 | 106 | ![find-and-kill](http://i.imgur.com/ZawnSMg.png) 107 | 108 | 109 | ## Deploying sheep to the static site 110 | 111 | From the root directory of `paastor`: 112 | 113 | ./pack 114 | 115 | will do it. 116 | 117 | # License 118 | 119 | MIT - see LICENSE file in this repository 120 | 121 | Copyright 2015 Jeff H. Parrish 122 | -------------------------------------------------------------------------------- /paastor-cli/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | *.log 3 | .DS_Store 4 | Thumbs.db 5 | -------------------------------------------------------------------------------- /paastor-cli/.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces": [ 3 | "if", 4 | "else", 5 | "for", 6 | "while", 7 | "do", 8 | "try", 9 | "catch" 10 | ], 11 | "requireSpaceAfterKeywords": [ 12 | "do", 13 | "for", 14 | "if", 15 | "else", 16 | "switch", 17 | "case", 18 | "try", 19 | "void", 20 | "while", 21 | "return", 22 | "function" 23 | ], 24 | "disallowKeywords": ["with"], 25 | "requireSpaceBeforeBlockStatements": true, 26 | "requireSpacesInConditionalExpression": true, 27 | "disallowSpacesInNamedFunctionExpression": { 28 | "beforeOpeningRoundBrace": true 29 | }, 30 | "disallowSpacesInFunctionDeclaration": { 31 | "beforeOpeningRoundBrace": true 32 | }, 33 | "requireSpacesInFunction": { 34 | "beforeOpeningCurlyBrace": true 35 | }, 36 | "disallowMultipleVarDecl": true, 37 | "disallowMultipleLineBreaks": false, 38 | "requireBlocksOnNewline": 1, 39 | "disallowQuotedKeysInObjects": "allButReserved", 40 | "disallowSpaceAfterObjectKeys": true, 41 | "requireSpaceBeforeObjectValues": true, 42 | "requireCommaBeforeLineBreak": true, 43 | "disallowSpaceBeforePostfixUnaryOperators": true, 44 | "requireSpaceBeforeBinaryOperators": true, 45 | "requireSpaceAfterBinaryOperators": true, 46 | "disallowMixedSpacesAndTabs": true, 47 | "disallowTrailingWhitespace": true, 48 | "disallowTrailingComma": true, 49 | "requireLineFeedAtFileEnd": true, 50 | "requireCapitalizedConstructors": true, 51 | "disallowYodaConditions": true, 52 | "validateParameterSeparator": ", ", 53 | "validateIndentation": 4, 54 | "excludeFiles": [ 55 | "node_modules/**", 56 | "coverage/**", 57 | "assets/**", 58 | ".tmp/**" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /paastor-cli/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "curly": true, 4 | "undef": true, 5 | "unused": false, 6 | "trailing": true, 7 | "strict": true, 8 | "laxbreak": true, 9 | "laxcomma": true, 10 | "mocha": true, 11 | "predef": [ 12 | "-Promise", 13 | "xit", 14 | "xdescribe" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /paastor-cli/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jeff Parrish 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /paastor-cli/README.md: -------------------------------------------------------------------------------- 1 | [![NPM version](https://badge.fury.io/js/paastor.svg)](http://badge.fury.io/js/paastor) 2 | 3 | # Deploy to [Paastor](https://paastor.com) via command line interface (CLI) 4 | 5 | [Quickstart Usage Guide](https://paastor.com/pages/usage.html) 6 | 7 | [CLI Documentation](https://paastor.com/pages/pstr-cli.html) 8 | 9 | ```bash 10 | npm install -g paastor 11 | ``` 12 | 13 | Then use the `pstr` tool: 14 | 15 | ```bash 16 | pstr [commands go here] 17 | ``` 18 | 19 | # Use the client library programmatically 20 | 21 | ```bash 22 | npm install paastor --save 23 | ``` 24 | 25 | ```javascript 26 | var Paastor = require('paastor'); 27 | var paastor = new Paastor(); 28 | paastor.login({ email: 'asdf', password: 'asdfasdf' }, function (data, res, body) { 29 | console.log('logged in'); 30 | 31 | paastor.listServers(function (err, servers) { 32 | console.log('servers', servers); 33 | }); 34 | 35 | paastor.getLogs({ vps: 'myserver', app: 'chatty' }, function (err, logs) { 36 | console.log('logs', logs); 37 | }); 38 | 39 | }); 40 | ``` 41 | 42 | ---- 43 | ###### Copyright (c) 2014 Jeff Parrish 44 | ###### MIT License 45 | -------------------------------------------------------------------------------- /paastor-cli/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // Test http server 3 | var http = require('http'); 4 | var port = process.env.PAASTOR_PORT || 3006; 5 | 6 | http.createServer(function (req, res) { 7 | var sometime = +new Date(); 8 | console.log(req.method, req.url, sometime); 9 | res.writeHead(200, {'Content-Type': 'application/json'}); 10 | var message = { message: "it works", sometime: sometime }; 11 | res.end(JSON.stringify(message)); 12 | }).listen(port, '127.0.0.1'); 13 | console.log('Server running at http://127.0.0.1:' + port); 14 | -------------------------------------------------------------------------------- /paastor-cli/client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Generic wrapper client for Paastor. 5 | * 6 | * All `callback` functions receive three arguments: 7 | * 8 | * callback(error, res, body) 9 | * 10 | * @param {object} options 11 | * @param {string} [options.paastorUrl=https://paastor.com/api] 12 | */ 13 | function Client (options) { 14 | var self = this; 15 | options = options || {}; 16 | 17 | self.cookies = []; 18 | 19 | var paastorUrl = options.paastorUrl || "https://paastor.com/api"; 20 | 21 | var request = require('request').defaults({ 22 | // cookies 23 | jar: true, 24 | rejectUnauthorized: false 25 | }); 26 | 27 | 28 | /** 29 | * Log in. 30 | * @param {object} params 31 | * @param {string} [params.email] 32 | * @param {string} [params.password] 33 | * @param {function} callback 34 | */ 35 | self.login = function (params, callback) { 36 | request({ 37 | method: 'POST', 38 | uri: paastorUrl + '/login', 39 | json: true, 40 | body: params 41 | }, callback); 42 | }; 43 | 44 | /** 45 | * List all servers. 46 | * @param {object} params - Optional 47 | * @param {array} [params.cookies] - Optional 48 | * @param {function} callback 49 | */ 50 | self.listServers = function (params, callback) { 51 | var cookies = params.cookies || self.cookies; 52 | delete params.cookies; 53 | 54 | if (typeof params === 'function' && !callback) { 55 | callback = params; 56 | } 57 | request({ 58 | method: 'GET', 59 | uri: paastorUrl + '/vps', 60 | json: true, 61 | headers: { 62 | 'Cookie': cookies 63 | } 64 | }, callback); 65 | }; 66 | 67 | /** 68 | * Get logs for a server or an app on a server. 69 | * @param {object} params 70 | * @param {string} [params.vps] - The server _id. 71 | * @param {string} [params.app] - The app _id. 72 | * @param {array} [params.cookies] - Optional 73 | * @param {function} callback 74 | */ 75 | self.getLogs = function (params, callback) { 76 | 77 | var reqUrl = paastorUrl + '/vps/' + params.vps; 78 | if (!params.app) { 79 | reqUrl += '/logs'; 80 | } 81 | else { 82 | reqUrl += '/apps/' + params.app + '/logs'; 83 | } 84 | 85 | var cookies = params.cookies || self.cookies; 86 | delete params.cookies; 87 | 88 | request({ 89 | method: 'GET', 90 | uri: reqUrl, 91 | json: true, 92 | headers: { 93 | 'Cookie': cookies 94 | } 95 | }, callback); 96 | }; 97 | 98 | /** 99 | * Get detailed diagnostic info about a server. 100 | * @param {object} params 101 | * @param {string} [params.vps] - The server _id. 102 | * @param {array} [params.cookies] - Optional 103 | * @param {function} callback 104 | */ 105 | self.getServerInfo = function (params, callback) { 106 | var cookies = params.cookies || self.cookies; 107 | delete params.cookies; 108 | 109 | request({ 110 | method: 'GET', 111 | uri: paastorUrl + '/vps/' + params.vps, 112 | json: true, 113 | headers: { 114 | 'Cookie': cookies 115 | } 116 | }, callback); 117 | }; 118 | 119 | /** 120 | * Stop a currently running app. 121 | * @param {object} params 122 | * @param {string} [params.vps] - The server _id. 123 | * @param {string} [params.app] - The app _id. 124 | * @param {array} [params.cookies] - Optional 125 | * @param {function} callback 126 | */ 127 | self.stopApp = function (params, callback) { 128 | var cookies = params.cookies || self.cookies; 129 | delete params.cookies; 130 | 131 | request({ 132 | method: 'PUT', 133 | uri: paastorUrl + '/vps/' + params.vps + '/apps/' + params.app + '/kill', 134 | json: true, 135 | headers: { 136 | 'Cookie': cookies 137 | } 138 | }, callback); 139 | }; 140 | 141 | /** 142 | * Start a currently running app. 143 | * @param {object} params 144 | * @param {string} [params.vps] - The server _id. 145 | * @param {string} [params.app] - The app _id. 146 | * @param {array} [params.cookies] - Optional 147 | * @param {function} callback 148 | */ 149 | self.startApp = function (params, callback) { 150 | var cookies = params.cookies || self.cookies; 151 | delete params.cookies; 152 | 153 | request({ 154 | method: 'PUT', 155 | uri: paastorUrl + '/vps/' + params.vps + '/apps/' + params.app + '/start', 156 | json: true, 157 | headers: { 158 | 'Cookie': cookies 159 | } 160 | }, callback); 161 | }; 162 | 163 | /** 164 | * Start a currently running app. 165 | * @param {object} params 166 | * @param {string} [params.vps] - The server _id. 167 | * @param {string} [params.app] - The app _id. 168 | * @param {array} [params.cookies] - Optional 169 | * @param {function} callback 170 | */ 171 | self.restartApp = function (params, callback) { 172 | var cookies = params.cookies || self.cookies; 173 | delete params.cookies; 174 | 175 | request({ 176 | method: 'PUT', 177 | uri: paastorUrl + '/vps/' + params.vps + '/apps/' + params.app + '/restart', 178 | json: true, 179 | headers: { 180 | 'Cookie': cookies 181 | } 182 | }, callback); 183 | }; 184 | 185 | /** 186 | * Set / change environment variable 187 | * @param {object} params 188 | * @param {string} [params.vps] - The server _id. 189 | * @param {string} [params.app] - The app _id. 190 | * @param {array} [params.key] - The env var name 191 | * @param {array} [params.val] - The env var value 192 | * @param {function} callback 193 | */ 194 | self.setenv = function (params, callback) { 195 | 196 | var cookies = params.cookies || self.cookies; 197 | delete params.cookies; 198 | 199 | request({ 200 | method: 'PUT', 201 | uri: paastorUrl + '/vps/' + params.vps + '/apps/' + params.app + '/setvar', 202 | json: true, 203 | body: params, 204 | headers: { 205 | 'Cookie': cookies 206 | } 207 | }, callback); 208 | }; 209 | 210 | /** 211 | * Set / change environment variable 212 | * @param {object} params 213 | * @param {string} [params.vps] - The server _id. 214 | * @param {string} [params.version] - The version of Node.js to install. 215 | * @param {function} callback 216 | */ 217 | self.installNode = function (params, callback) { 218 | 219 | var cookies = params.cookies || self.cookies; 220 | delete params.cookies; 221 | 222 | request({ 223 | method: 'POST', 224 | uri: paastorUrl + '/vps/' + params.vps + '/node/' + params.version, 225 | json: true, 226 | headers: { 227 | 'Cookie': cookies 228 | } 229 | }, callback); 230 | }; 231 | 232 | self.pushPackage = function (params, callback) { 233 | 234 | var cookies = params.cookies || self.cookies; 235 | delete params.cookies; 236 | 237 | var uri = paastorUrl + '/vps/' + params.vps + '/apps/' + params.app + '/pkg'; 238 | 239 | delete params.vps; 240 | delete params.app; 241 | 242 | request({ 243 | method: 'PUT', 244 | uri: uri, 245 | json: true, 246 | headers: { 247 | 'Cookie': cookies 248 | }, 249 | body: params 250 | }, callback); 251 | }; 252 | 253 | self.createApp = function (params, callback) { 254 | var cookies = params.cookies || self.cookies; 255 | delete params.cookies; 256 | 257 | var uri = paastorUrl + '/vps/' + params.vps + '/apps'; 258 | 259 | delete params.vps; 260 | delete params.app; 261 | 262 | request({ 263 | method: 'POST', 264 | uri: uri, 265 | json: true, 266 | headers: { 267 | 'Cookie': cookies 268 | }, 269 | body: params 270 | }, callback); 271 | }; 272 | } 273 | 274 | exports = module.exports = Client; 275 | -------------------------------------------------------------------------------- /paastor-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paastor", 3 | "version": "0.4.7", 4 | "homepage": "https://paastor.com", 5 | "description": "CLI and Library for managing your Paastor servers and deploy apps.", 6 | "main": "client.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "preferGlobal": true, 11 | "bin": { 12 | "pstr": "./cli.js" 13 | }, 14 | "author": "hello@paastor.com", 15 | "license": "MIT", 16 | "respository": { 17 | "type": "git", 18 | "url": "https://github.com/paastor/paastor" 19 | }, 20 | "bugs": { 21 | "url": "http://github.com/paastor/paastor/issues" 22 | }, 23 | "dependencies": { 24 | "archiver": "~0.11.0", 25 | "async": "~0.9.0", 26 | "cli-table": "~0.3.0", 27 | "colors": "~0.6.2", 28 | "commander": "~2.3.0", 29 | "promptly": "~0.2.0", 30 | "request": "~2.42.0", 31 | "semver": "~3.0.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /paastor-server/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | // JSHint Default Configuration File (as on JSHint website) 4 | // See http://jshint.com/docs/ for more details 5 | 6 | "maxerr" : 50, // {int} Maximum error before stopping 7 | 8 | // Enforcing 9 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 10 | "camelcase" : false, // true: Identifiers must be in camelCase 11 | "curly" : true, // true: Require {} for every new block or scope 12 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 13 | "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() 14 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 15 | "indent" : 4, // {int} Number of spaces to use for indentation 16 | "latedef" : false, // true: Require variables/functions to be defined before being used 17 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` 18 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 19 | "noempty" : true, // true: Prohibit use of empty blocks 20 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 21 | "plusplus" : false, // true: Prohibit use of `++` & `--` 22 | "quotmark" : false, // Quotation mark consistency: 23 | // false : do nothing (default) 24 | // true : ensure whatever is used is consistent 25 | // "single" : require single quotes 26 | // "double" : require double quotes 27 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 28 | "unused" : true, // true: Require all defined variables be used 29 | "strict" : true, // true: Requires all functions run in ES5 Strict Mode 30 | "maxparams" : false, // {int} Max number of formal params allowed per function 31 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 32 | "maxstatements" : false, // {int} Max number statements per function 33 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 34 | "maxlen" : false, // {int} Max number of characters per line 35 | 36 | // Relaxing 37 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 38 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 39 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 40 | "eqnull" : false, // true: Tolerate use of `== null` 41 | "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) 42 | "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) 43 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 44 | // (ex: `for each`, multiple try/catch, function expression…) 45 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 46 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 47 | "funcscope" : false, // true: Tolerate defining variables inside control statements 48 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 49 | "iterator" : false, // true: Tolerate using the `__iterator__` property 50 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 51 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 52 | "laxcomma" : false, // true: Tolerate comma-first style coding 53 | "loopfunc" : false, // true: Tolerate functions being defined in loops 54 | "multistr" : false, // true: Tolerate multi-line strings 55 | "proto" : false, // true: Tolerate using the `__proto__` property 56 | "scripturl" : false, // true: Tolerate script-targeted URLs 57 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 58 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 59 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 60 | "validthis" : false, // true: Tolerate using this in a non-constructor function 61 | 62 | // Environments 63 | "browser" : true, // Web Browser (window, document, etc) 64 | "couch" : false, // CouchDB 65 | "devel" : true, // Development/debugging (alert, confirm, etc) 66 | "dojo" : false, // Dojo Toolkit 67 | "jquery" : false, // jQuery 68 | "mootools" : false, // MooTools 69 | "node" : true, // Node.js 70 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 71 | "prototypejs" : false, // Prototype and Scriptaculous 72 | "rhino" : false, // Rhino 73 | "worker" : false, // Web Workers 74 | "wsh" : false, // Windows Scripting Host 75 | "yui" : false, // Yahoo User Interface 76 | 77 | // Custom Globals 78 | "globals" : { 79 | // mocha 80 | "describe": true, 81 | "it": true, 82 | "before": true, 83 | "beforeEach": true, 84 | "after": true, 85 | "afterEach": true 86 | 87 | } // additional predefined global variables 88 | } -------------------------------------------------------------------------------- /paastor-server/bin/www.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var debug = require('debug')('paastor'); 3 | var logger = require('debug')('redir'); 4 | var app = require('../paastor'); 5 | var http = require('http'); 6 | var https = require('https'); 7 | var fs = require('fs'); 8 | 9 | // if (process.env.NODE_ENV === 'production') { 10 | 11 | // var sslServer = https.createServer({ 12 | // key: fs.readFileSync(__dirname + '/../paastor.key'), 13 | // cert: fs.readFileSync(__dirname + '/../paastor.crt'), 14 | // ca: [fs.readFileSync(__dirname + '/../gd_bundle-g2-g1.crt')] // godaddy ssl CA 15 | // }, app).listen(3443, function () { 16 | // debug('Paastor SSL server listening on port ' + sslServer.address().port); 17 | // }); 18 | 19 | // var server = http.createServer(function (req, res) { 20 | // var secureLocation = 'https://' + req.headers.host + req.url; 21 | // logger(+new Date(), secureLocation); 22 | // res.writeHead(302, { 23 | // 'Content-Type': 'text/plain', 24 | // 'Location': secureLocation 25 | // }); 26 | // res.end('Redirecting to SSL\n'); 27 | // }).listen(3380, function () { 28 | // debug('Paastor redirect service listening on port ' + server.address().port); 29 | // }); 30 | 31 | // } 32 | // else { 33 | var server = http.createServer(app).listen(process.env.PAASTOR_PORT || 2999, function () { 34 | debug('Paastor redirect service listening on port ' + server.address().port); 35 | }); 36 | // } 37 | -------------------------------------------------------------------------------- /paastor-server/config.js: -------------------------------------------------------------------------------- 1 | var config = { 2 | redisSession: { 3 | host: 'localhost', 4 | port: '6379', 5 | secret: '' 6 | }, 7 | mongo: "mongodb://localhost/paastor", 8 | email: { 9 | key: "", 10 | from: "hello@mydomain.com" 11 | }, 12 | url: "http://localhost:2999", 13 | stripe: { 14 | public: '', 15 | secret: '' 16 | }, 17 | sheepDownload: "http://localhost/or-something" 18 | }; 19 | 20 | if (process.env.NODE_ENV === 'production') { 21 | config.redisSession = { 22 | host: process.env.REDIS_HOST || config.redisSession.host, 23 | port: process.env.REDIS_PORT || config.redisSession.port, 24 | secret: process.env.REDIS_SECRET || config.redisSession.secret, 25 | password: process.env.REDIS_PASS || config.redisSession.password 26 | }; 27 | 28 | config.url = "https://paastor.com"; 29 | config.mongo = "some-uri" 30 | config.stripe = { 31 | public: '', 32 | secret: '' 33 | }; 34 | } 35 | 36 | exports = module.exports = config; 37 | -------------------------------------------------------------------------------- /paastor-server/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var jade = require('gulp-jade'); 3 | var notify = require('gulp-notify'); 4 | var browserify = require('gulp-browserify'); 5 | var uglify = require('gulp-uglify'); 6 | 7 | gulp.task('js', function () { 8 | // Single entry point to browserify 9 | gulp.src('./public/js/app.js') 10 | .pipe(browserify({ 11 | insertGlobals : true, 12 | debug: !gulp.env.production 13 | })) 14 | .pipe(uglify()) 15 | .pipe(gulp.dest('./public/build/js')) 16 | .pipe(notify({ message: 'JS recompiled' })); 17 | }); 18 | 19 | gulp.task('jade-templates', function () { 20 | return gulp.src('./views/templates/**/*.jade') 21 | .pipe(jade({ 22 | pretty: true, 23 | })) 24 | .pipe(gulp.dest('./public/build/html/')) 25 | .pipe(notify({ message: 'Jade angular views rebuilt' })); 26 | }); 27 | 28 | gulp.task('jade-pages', function () { 29 | return gulp.src(['./views/pages/**/*.jade']) 30 | .pipe(jade({ 31 | pretty: true, 32 | })) 33 | .pipe(gulp.dest('./public/pages/')) 34 | .pipe(notify({ message: 'Jade pages rebuilt' })); 35 | }); 36 | 37 | gulp.task('watch', function () { 38 | gulp.watch('./views/templates/**/*.jade', ['jade-templates']); 39 | gulp.watch(['./views/pages/**/*.jade', './views/layout.jade'], ['jade-pages']); 40 | gulp.watch('./public/js/**/*.js', ['js']); 41 | }); 42 | 43 | gulp.task('default', ['jade-templates', 'jade-pages', 'js', 'watch']); 44 | -------------------------------------------------------------------------------- /paastor-server/lib/genrand.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var crypto = require('crypto'); 3 | /** 4 | * Asynchronously get a crypto random string of a certain length with chars 0-9 a-z A-Z. 5 | * @param number len 6 | * @param function cb - With arguments: [err, randOut, totalTimeReadable] 7 | */ 8 | exports = module.exports = function randomValueBase64 (len, cb) { 9 | var starttime = process.hrtime(); 10 | return crypto.randomBytes(Math.ceil(len * 3 / 4), function (err, buf) { 11 | if (err) { 12 | return cb(err); 13 | } 14 | var randOut = buf 15 | .toString('base64') // convert to base64 format 16 | .slice(0, len) // return required number of characters 17 | .replace(/\+/g, '0') // replace '+' with '0' 18 | .replace(/\//g, '0'); // replace '/' with '0' 19 | var endtime = process.hrtime(starttime); 20 | var totalTimeReadable = (endtime[0] > 0 ? endtime[0] + 's ' : '') + (endtime[1] / 1000000).toFixed(3) + 'ms' ; 21 | cb(null, randOut, totalTimeReadable); 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /paastor-server/lib/hash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var crypto = require('crypto'); 3 | exports = module.exports = function (pass) { 4 | return crypto.createHash('sha256').update(pass).digest('base64'); 5 | }; 6 | -------------------------------------------------------------------------------- /paastor-server/paastor.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var config = require('./config'); 3 | var debug = require('debug')('paastor'); 4 | 5 | /** 6 | * Handle uncaught exceptions. 7 | */ 8 | process.on('uncaughtException', function (err) { 9 | debug('\n------ uncaughtException ------\n', err.message); 10 | debug(err.stack, '\n'); 11 | process.exit(1); 12 | }); 13 | 14 | var express = require('express'); 15 | var redis = require('redis'); 16 | var session = require('express-session'); 17 | var RedisStore = require('connect-redis')(session); 18 | var express = require('express'); 19 | var redisClient = redis.createClient(config.redisSession.port, config.redisSession.host); 20 | redisClient.on('connect', function () { 21 | debug('Redis is connected'); 22 | }); 23 | redisClient.on('error', function (err) { 24 | debug('Redis error', err); 25 | }); 26 | 27 | redisClient.auth(config.redisSession.password, function (err) { 28 | if (err) { 29 | debug('Redis auth error', err); 30 | return; 31 | } 32 | debug('Redis authenticated'); 33 | }); 34 | 35 | var path = require('path'); 36 | var favicon = require('static-favicon'); 37 | var logger = require('morgan'); 38 | var cookieParser = require('cookie-parser'); 39 | var bodyParser = require('body-parser'); 40 | var Mandrill = require('node-mandrill'); 41 | 42 | var home = require('./routes/home'); 43 | var api = require('./routes/api'); 44 | 45 | var dataModels = require('./models'); 46 | var mandrill = new Mandrill(config.email.key); 47 | var stripe = require('stripe')(config.stripe.secret); 48 | 49 | var stripePlans = []; 50 | stripe.plans.list({ limit: 100 }, function (err, plans) { 51 | if (err) { 52 | debug(err); 53 | return; 54 | } 55 | plans = plans || { data: [] }; 56 | var output = plans.data.map(function (plan) { 57 | return { 58 | id: plan.id, 59 | name: plan.name, 60 | amount: plan.amount, 61 | interval: plan.interval 62 | }; 63 | }); 64 | output.sort(function (a, b) { 65 | if (a.amount > b.amount) { 66 | return 1; 67 | } 68 | if (a.amount < b.amount) { 69 | return -1; 70 | } 71 | return 0; 72 | }); 73 | debug('Got ' + output.length + ' plans from Stripe'); 74 | stripePlans = output; 75 | }); 76 | 77 | var app = express(); 78 | if (process.env.NODE_ENV === 'production') { 79 | app.enable('trust proxy'); 80 | app.use(function (req, res, next) { 81 | if (req.headers && req.headers.referrer && req.headers.referrer.indexOf('http://') !== -1) { 82 | return res.redirect(301, config.url + req.url); 83 | } 84 | if (req.host && req.host.indexOf('www.') !== -1) { 85 | return res.redirect(301, config.url + req.url); 86 | } 87 | next(); 88 | }); 89 | } 90 | 91 | // view engine setup 92 | app.set('views', path.join(__dirname, 'views')); 93 | app.set('view engine', 'jade'); 94 | 95 | app.use(dataModels); 96 | app.use(function (req, res, next) { 97 | req.mandrill = mandrill; 98 | req.plans = stripePlans; 99 | next(); 100 | }); 101 | 102 | app.use(favicon()); 103 | app.use(bodyParser.json({ limit: '100mb' })); 104 | app.use(bodyParser.urlencoded({ extended: true })); 105 | app.use(cookieParser()); 106 | app.use(express.static(path.join(__dirname, 'public'))); 107 | app.use(logger('dev')); 108 | app.use(session({ 109 | store: new RedisStore({ 110 | client: redisClient 111 | }), 112 | secret: config.redisSession.secret, 113 | resave: true, 114 | saveUninitialized: true, 115 | unset: 'destroy' 116 | })); 117 | app.use(function (req, res, next) { 118 | res.set('X-Powered-By', undefined); 119 | 120 | next(); 121 | }); 122 | app.use('/', home); 123 | app.use('/api/', api); 124 | 125 | /// catch 404 and forward to error handler 126 | app.use(function(req, res, next) { 127 | var err = new Error('Paastor route not matched'); 128 | err.status = 404; 129 | next(err); 130 | }); 131 | 132 | 133 | // will print stacktrace 134 | 135 | app.use(function errHandler(err, req, res, next) { 136 | res.status(err.status || 500); 137 | var output = { 138 | message: err.message, 139 | error: err 140 | }; 141 | if (process.env.NODE_ENV === 'production') { 142 | delete err.stack; 143 | } 144 | if (req.accepts('json')) { 145 | return res.send(output); 146 | } 147 | res.render('error', output); 148 | }); 149 | 150 | 151 | 152 | exports = module.exports = app; 153 | -------------------------------------------------------------------------------- /paastor-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paastor", 3 | "version": "0.1.1", 4 | "main": "bin/www.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "DEBUG=mongoose,paastor,sheep-client,sheep-ssh-client,redir node bin/www.js" 8 | }, 9 | "dependencies": { 10 | "archiver": "^0.10.1", 11 | "async": "^0.9.0", 12 | "body-parser": "^1.6.5", 13 | "connect-redis": "^2.1.0", 14 | "cookie-parser": "^1.3.2", 15 | "cookie-session": "git+https://github.com/ForbesLindesay/cookie-session#09ef5bbc89fc470525e3743ff0e0c772eed14d33", 16 | "debug": "^0.7.4", 17 | "express": "^4.8.5", 18 | "express-session": "^1.8.2", 19 | "gift": "^0.4.2", 20 | "jade": "^1.3.1", 21 | "lodash": "^2.4.1", 22 | "mongodb": "^1.4.12", 23 | "mongoose": "^3.8.15", 24 | "morgan": "^1.2.3", 25 | "node-mandrill": "^1.0.1", 26 | "node-uuid": "^1.4.1", 27 | "redis": "^0.12.1", 28 | "request": "^2.39.0", 29 | "rimraf": "^2.2.8", 30 | "ssh-keygen": "^0.2.1", 31 | "ssh2": "^0.3.4", 32 | "static-favicon": "^1.0.2", 33 | "strength": "^0.1.4", 34 | "stripe": "^2.8.0", 35 | "uuid": "^1.4.1" 36 | }, 37 | "devDependencies": { 38 | "gulp": "^3.8.7", 39 | "gulp-browserify": "^0.5.0", 40 | "gulp-jade": "^0.7.0", 41 | "gulp-notify": "^1.5.0", 42 | "gulp-uglify": "^1.0.1", 43 | "mocha": "^1.21.3", 44 | "should": "^4.0.4", 45 | "supertest": "^0.13.0" 46 | }, 47 | "engines": { 48 | "node": "0.10.31" 49 | }, 50 | "domains": [ 51 | "paastor.com", 52 | "www.paastor.com" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /paastor-server/public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 13px 21px; 3 | } 4 | 5 | .container { 6 | max-width: 800px; 7 | font-size: 16px; 8 | } 9 | 10 | .left { 11 | text-align: left; 12 | } 13 | .right { 14 | text-align: right; 15 | } 16 | .center { 17 | text-align: center; 18 | } 19 | 20 | .smaller { 21 | font-size: .8em; 22 | } 23 | 24 | .wrapall { 25 | word-break: break-word; 26 | } 27 | 28 | .monospace { 29 | font-family: 'Menlo', 'Monaco', 'Consolas', monospace; 30 | } 31 | 32 | .white { 33 | color: #ffffff; 34 | } 35 | 36 | .clickable { 37 | cursor: pointer; 38 | } 39 | 40 | #footer { 41 | position: fixed; 42 | left: 0; 43 | right: 0; 44 | bottom: 0; 45 | padding: 8px 13px 0 13px; 46 | background: #fff; 47 | box-shadow: 1px 2px 10px rgba(0,0,0,.5); 48 | z-index: 200; 49 | } 50 | 51 | /* image sizing to match fa-* */ 52 | img.img-1x { 53 | margin-top: -4px; 54 | width: 16px; 55 | height: 16px; 56 | } 57 | img.img-2x { 58 | margin-top: -4px; 59 | width: 30px; 60 | height: 30px; 61 | } 62 | img.img-3x { 63 | width: 51px; 64 | height: 51px; 65 | } 66 | .storage-panel { 67 | margin: 0 3% 6px 3%; 68 | padding: 1px 20px 69 | } 70 | -------------------------------------------------------------------------------- /paastor-server/public/dash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/dash.png -------------------------------------------------------------------------------- /paastor-server/public/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/diagram.png -------------------------------------------------------------------------------- /paastor-server/public/email-logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/email-logo.gif -------------------------------------------------------------------------------- /paastor-server/public/email-logo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/email-logo.xcf -------------------------------------------------------------------------------- /paastor-server/public/favicon-old-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/favicon-old-white.png -------------------------------------------------------------------------------- /paastor-server/public/favicon-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/favicon-old.png -------------------------------------------------------------------------------- /paastor-server/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/favicon.png -------------------------------------------------------------------------------- /paastor-server/public/js/app.js: -------------------------------------------------------------------------------- 1 | angular.module('readableTime', []).filter('readableTime', require('./readable-time')); 2 | Stripe.setPublishableKey( 3 | location.hostname.indexOf('paastor.com') === -1 4 | ? 'pk_test_GdSOMC1qnIe80eWMZkhVoDXR' 5 | : 'pk_live_pcMlMokqIbmjbureLdobpP8D' 6 | ); 7 | 8 | var ngmodules = ['ngResource', 'readableTime']; 9 | if (window.location.pathname === '/') { 10 | ngmodules.push('ngRoute'); 11 | } 12 | var paastor = angular.module('paastor', ngmodules); 13 | 14 | require('./controllers/NavController')(paastor); 15 | require('./controllers/VpsCreateController')(paastor); 16 | require('./controllers/VpsListController')(paastor); 17 | require('./controllers/VpsViewController')(paastor); 18 | require('./controllers/AppCreateController')(paastor); 19 | require('./controllers/AppSslController')(paastor); 20 | require('./controllers/RedisController')(paastor); 21 | require('./controllers/MongoController')(paastor); 22 | require('./controllers/AccountEditController')(paastor); 23 | require('./controllers/ManageServicesController')(paastor); 24 | 25 | require('./services.js')(paastor); 26 | 27 | paastor.directive('paEnter', require('./directives/pa-enter.js')); 28 | 29 | if (window.location.pathname === '/') { 30 | paastor 31 | .config(['$routeProvider', 32 | function ($routeProvider) { 33 | 34 | $routeProvider 35 | .when('/', { 36 | templateUrl: 'build/html/home.html' 37 | }) 38 | .when('/manage-services', { 39 | templateUrl: 'build/html/manage-services.html', 40 | controller: 'ManageServicesController' 41 | }) 42 | .when('/account', { 43 | templateUrl: 'build/html/account-edit.html', 44 | controller: 'AccountEditController' 45 | }) 46 | .when('/list', { 47 | templateUrl: 'build/html/vps-list.html', 48 | controller: 'VpsListController' 49 | }) 50 | .when('/vps', { 51 | templateUrl: 'build/html/vps-create.html', 52 | controller: 'VpsCreateController' 53 | }) 54 | .when('/vps/:_id', { 55 | templateUrl: 'build/html/vps-view.html', 56 | controller: 'VpsViewController' 57 | }) 58 | .when('/vps/:_id/app', { 59 | templateUrl: 'build/html/app-create.html', 60 | controller: 'AppCreateController' 61 | }) 62 | .when('/vps/:vps/ssl/:app', { 63 | templateUrl: 'build/html/app-ssl.html', 64 | controller: 'AppSslController' 65 | }) 66 | .when('/vps/:vps/redis', { 67 | templateUrl: 'build/html/redis.html', 68 | controller: 'RedisController' 69 | }) 70 | .when('/vps/:vps/mongo', { 71 | templateUrl: 'build/html/mongo.html', 72 | controller: 'MongoController' 73 | }) 74 | .otherwise({ 75 | templateUrl: 'build/html/404.html' 76 | }); 77 | 78 | } 79 | ]); 80 | } 81 | else { 82 | 83 | } 84 | -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/AccountEditController.js: -------------------------------------------------------------------------------- 1 | 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('AccountEditController', [ 4 | '$scope', 5 | 'Account', 6 | 'Payments', 7 | '$rootScope', 8 | function ($scope, Account, Payments, $rootScope) { 9 | $scope.vps = {}; 10 | $scope.message = ""; 11 | $scope.password = ""; 12 | $scope.passwordConf = ""; 13 | $scope.card = null; 14 | $scope.newCard = {}; 15 | 16 | Account.getCard(function (err, card) { 17 | if (err) { 18 | $scope.message = err.error; 19 | return; 20 | } 21 | $scope.card = card; 22 | }); 23 | 24 | $scope.changePassword = function () { 25 | $scope.message = ""; 26 | if (!$scope.password) { 27 | $scope.message = "Password is required." 28 | return; 29 | } 30 | if ($scope.password !== $scope.passwordConf) { 31 | $scope.message = "Passwords don't match."; 32 | return; 33 | } 34 | Account.update({ 35 | password: $scope.password 36 | }, function (err, account) { 37 | if (err) { 38 | $scope.message = err.error; 39 | return; 40 | } 41 | $scope.password = ""; 42 | $scope.passwordConf = ""; 43 | $scope.message = "Password was changed."; 44 | }); 45 | 46 | }; 47 | 48 | $scope.setCard = function () { 49 | $scope.message = ""; 50 | Payments.card($scope.newCard, function (err, card) { 51 | console.log(err, card); 52 | if (err) { 53 | $scope.message = err.error; 54 | $scope.$apply(); 55 | return; 56 | } 57 | $scope.card = card; 58 | $scope.newCard = {}; 59 | $scope.message = "Successfully updated card."; 60 | }); 61 | }; 62 | } 63 | ]); 64 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/AppCreateController.js: -------------------------------------------------------------------------------- 1 | 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('AppCreateController', [ 4 | '$scope', 5 | 'Vps', 6 | 'App', 7 | '$routeParams', 8 | '$interval', 9 | function ($scope, Vps, App, $routeParams, $interval) { 10 | $scope.app = {vps: $routeParams._id }; 11 | $scope.message = ""; 12 | $scope.saving = false; 13 | $scope.done = false; 14 | $scope.logs = ""; 15 | 16 | $scope.save = function () { 17 | $scope.saving = true; 18 | $scope.message = "Creating and starting the app. This will take several minutes."; 19 | 20 | App.create($scope.app, function (err, data) { 21 | $scope.saving = false; 22 | if (err) { 23 | $scope.message = err.message || err.error || err; 24 | return 25 | } 26 | 27 | $scope.message = "Done."; 28 | $scope.saving = false; 29 | $scope.done = true; 30 | }); 31 | }; 32 | 33 | } 34 | ]); 35 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/AppSslController.js: -------------------------------------------------------------------------------- 1 | 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('AppSslController', [ 4 | '$scope', 5 | 'App', 6 | '$routeParams', 7 | function ($scope, App, $routeParams) { 8 | $scope.app = {vps: $routeParams.vps, _id: $routeParams.app }; 9 | $scope.message = ""; 10 | $scope.saving = false; 11 | $scope.done = false; 12 | 13 | $scope.save = function () { 14 | $scope.saving = true; 15 | $scope.message = ""; 16 | 17 | App.setSsl($scope.app, function (err, data) { 18 | $scope.saving = false; 19 | if (err) { 20 | $scope.message = err.message || err.error || err; 21 | return 22 | } 23 | $scope.done = true; 24 | $scope.saving = false; 25 | }); 26 | }; 27 | 28 | } 29 | ]); 30 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/ManageServicesController.js: -------------------------------------------------------------------------------- 1 | var uuid = require('uuid'); 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('ManageServicesController', [ 4 | '$scope', 5 | '$rootScope', 6 | 'Account', 7 | 'Payments', 8 | function ($scope, $rootScope, Account, Payments) { 9 | $scope.Math = window.Math; 10 | 11 | $scope.message = ""; 12 | $scope.hasNoCard = false; 13 | $scope.subMsg = ""; // subscription message 14 | $scope.buyMsg = ""; // purchase message 15 | 16 | // Pre load some data 17 | $scope.subscriptions = []; 18 | $scope.plans = []; 19 | $scope.card = null; 20 | 21 | Payments.getPlans(function (err, data) { 22 | if (err) { 23 | $scope.message = err.error; 24 | return; 25 | } 26 | $scope.plans = data; 27 | }); 28 | $scope.subs = function () { 29 | Payments.getSubscriptions(function (err, data) { 30 | if (err) { 31 | $scope.message = err.error; 32 | return; 33 | } 34 | $scope.subscriptions = data; 35 | }); 36 | }; 37 | $scope.subs(); 38 | Account.getCard(function (err, card) { 39 | if (err) { 40 | $scope.message = err.error; 41 | return; 42 | } 43 | if (!card || !card.last4) { 44 | $scope.hasNoCard = true; 45 | } 46 | }); 47 | 48 | 49 | $scope.addService = function (plan) { 50 | $scope.buyMsg = ""; 51 | plan.quantity = Math.floor(parseFloat(plan.quantity)); 52 | if (isNaN(plan.quantity) || plan.quantity < 1) { 53 | $scope.buyMsg = "Plan quantity is invalid."; 54 | return; 55 | } 56 | 57 | var conf = confirm('Please confirm this subscription.\n\nYou will be billed ' + plan.interval + 'ly at $' + ((plan.amount * plan.quantity)/100).toFixed(2) + ' for the following service:\n\n' +plan.quantity + 'x ' + plan.name); 58 | if (!conf) { 59 | return; 60 | } 61 | Payments.addSubscription(plan, function (err, subscriptions) { 62 | if (err) { 63 | $scope.buyMsg = err.error; 64 | return; 65 | } 66 | Account.get(function (err, account) { 67 | if (err) { 68 | return; 69 | } 70 | $rootScope.account = account; 71 | }); 72 | $scope.subscriptions = subscriptions; 73 | }); 74 | }; 75 | 76 | $scope.downgrade = function (sub) { 77 | $scope.subMsg = ""; 78 | sub.down = Math.floor(parseFloat(sub.down)); 79 | if (isNaN(sub.down) || sub.down < 1) { 80 | $scope.subMsg = "Downgrade quantity is invalid."; 81 | return; 82 | } 83 | if (sub.down > sub.quantity) { 84 | $scope.subMsg = "Downgrade quantity cannot exceed current subscription quantity."; 85 | return; 86 | } 87 | 88 | var conf = confirm("Please confirm your downgrade. ALL CREDITS will be lost and the changes will be applied IMMEDIATELY.\n\nREMOVE " + sub.down + "x " + sub.plan.name + "\n\nNew quantity will be " + (sub.quantity - sub.down) + "x"); 89 | if (!conf) { 90 | return; 91 | } 92 | var plan = { 93 | quantity: -sub.down, 94 | id: sub.plan.id, 95 | name: sub.plan.name 96 | }; 97 | Payments.addSubscription(plan, function (err, subscriptions) { 98 | if (err) { 99 | $scope.subMsg = err.error; 100 | return; 101 | } 102 | Account.get(function (err, account) { 103 | if (err) { 104 | return; 105 | } 106 | $rootScope.account = account; 107 | }); 108 | $scope.subscriptions = subscriptions; 109 | }); 110 | }; 111 | } 112 | ]); 113 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/MongoController.js: -------------------------------------------------------------------------------- 1 | 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('MongoController', [ 4 | '$scope', 5 | 'Vps', 6 | '$routeParams', 7 | '$log', 8 | function ($scope, Vps, $routeParams, $log) { 9 | $scope.vps = null; 10 | $scope.message = ""; 11 | $scope.loading = false; 12 | $scope.removed = false; 13 | $scope.installed = false; 14 | $scope.sshPassword = ""; 15 | 16 | var minport = 27000; 17 | var maxport = 27999; 18 | var notallowed = [27014, 27374, 27950]; 19 | var randPort = function () { 20 | var outport = Math.floor(Math.random() * (maxport - minport + 1)) + minport; 21 | // recursion 22 | if (notallowed.indexOf(outport) !== -1) { 23 | $log.debug('ports collided', outport); 24 | outport = randPort(); 25 | } 26 | return outport; 27 | }; 28 | $scope.portgen = function () { 29 | $scope.mongo.port = randPort(); 30 | }; 31 | 32 | $scope.mongo = { 33 | port: 27017, 34 | password: "", 35 | username: "", 36 | localOnly: true, 37 | rootPassword: "" 38 | }; 39 | 40 | Vps.get($routeParams.vps, function (err, vps) { 41 | if (err) { 42 | $scope.message = err.message || err.error || err; 43 | return; 44 | } 45 | $scope.vps = vps; 46 | }) 47 | 48 | $scope.install = function (params) { 49 | if ($scope.mongo.username && !$scope.mongo.password) { 50 | $scope.message = "Password is required when using a username."; 51 | return; 52 | } 53 | if ($scope.mongo.password && !$scope.mongo.username) { 54 | $scope.message = "Username is required when using a password."; 55 | return; 56 | } 57 | $scope.removed = false; 58 | $scope.loading = true; 59 | $scope.message = "Installing MongoDB..."; 60 | 61 | Vps.installMongo($scope.vps._id, $scope.mongo, function (err, res) { 62 | $scope.loading = false; 63 | if (err) { 64 | $scope.message = err.message || err.error || err || "Connection hung"; 65 | return; 66 | } 67 | $scope.installed = true; 68 | $scope.message = ""; 69 | }); 70 | }; 71 | 72 | $scope.uninstall = function () { 73 | $scope.installed = false; 74 | $scope.loading = true; 75 | $scope.message = "Removing MongoDB..."; 76 | 77 | Vps.uninstallMongo({ _id: $scope.vps._id, rootPassword: $scope.mongo.rootPassword}, function (err, res) { 78 | $scope.loading = false; 79 | if (err) { 80 | $scope.message = err.message || err.error || err; 81 | return; 82 | } 83 | $scope.mongo = res; 84 | $scope.vps.mongo = false; 85 | $scope.removed = true; 86 | $scope.message = ""; 87 | }); 88 | }; 89 | 90 | } 91 | ]); 92 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/NavController.js: -------------------------------------------------------------------------------- 1 | var hash = require('../../../lib/hash'); 2 | 3 | exports = module.exports = function (ngApp) { 4 | ngApp.controller('NavController', [ 5 | '$scope', 6 | '$rootScope', 7 | '$location', 8 | 'Account', 9 | function ($scope, $rootScope, $location, Account) { 10 | $scope.signin = { 11 | email: "", 12 | password: "" 13 | }; 14 | $scope.signup = { 15 | email: "", 16 | password: "" 17 | }; 18 | $scope.confirming = { 19 | _id: "", 20 | conf: "" 21 | }; 22 | $scope.resetPass; 23 | $scope.message = ""; 24 | 25 | Account.get(function (err, account) { 26 | if (err && window.location.hash && window.location.hash !== '#/') { 27 | window.open('/#/', '_self'); 28 | return; 29 | } 30 | if (!account && window.location.hash && window.location.hash !== '#/') { 31 | window.open('/#/', '_self'); 32 | return; 33 | } 34 | $rootScope.account = account; 35 | }); 36 | 37 | 38 | $scope.login = function () { 39 | $scope.message = ""; 40 | 41 | if (!$scope.signin.email) { 42 | $scope.message = "Missing email"; 43 | return; 44 | } 45 | if (!$scope.signin.password) { 46 | $scope.message = "Missing password"; 47 | return; 48 | } 49 | 50 | Account.login({ email: $scope.signin.email, password: $scope.signin.password }, function (err, data) { 51 | if (err) { 52 | $scope.message = err.error; 53 | return; 54 | } 55 | $scope.signin = {}; 56 | $rootScope.account = data; 57 | $location.path('/list'); 58 | }); 59 | }; 60 | 61 | $scope.logout = function () { 62 | $scope.message = ""; 63 | Account.logout(function (err) { 64 | if (err) { 65 | $scope.message = err.error; 66 | return; 67 | } 68 | $rootScope.account = null; 69 | window.open('/#/', '_self'); 70 | }); 71 | }; 72 | 73 | $scope.register = function () { 74 | $scope.message = ""; 75 | Account.create($scope.signup, function (err, account) { 76 | if (err) { 77 | $scope.message = err.error; 78 | return; 79 | } 80 | // do not log them in. need to confirm account first. 81 | $scope.message = "Success! Check your email to confirm your account."; 82 | $scope.signup = {}; 83 | }); 84 | }; 85 | 86 | $scope.forgot = function () { 87 | $scope.message = ""; 88 | if (!$scope.signin.email) { 89 | $scope.message = "Put in your email first"; 90 | return; 91 | } 92 | Account.forgotPassword($scope.signin.email, function (err, data) { 93 | if (err) { 94 | $scope.message = err.error; 95 | return; 96 | } 97 | $scope.signin = {}; 98 | $scope.message = data.message; 99 | }); 100 | }; 101 | 102 | $scope.doPasswordReset = function () { 103 | $scope.message = ""; 104 | if (!$scope.resetPass.password) { 105 | $scope.message = "Password is required."; 106 | return; 107 | } 108 | if ($scope.resetPass.password !== $scope.resetPass.passwordConf) { 109 | $scope.message = "Passwords must match."; 110 | return; 111 | } 112 | 113 | Account.resetPassword($scope.resetPass._id, $scope.resetPass.conf, $scope.resetPass.password, function (err, account) { 114 | if (err) { 115 | $scope.message = err.error; 116 | return; 117 | } 118 | $rootScope.account = account; 119 | $scope.resetPass = {}; 120 | window.open('/#/', '_self'); 121 | }); 122 | }; 123 | } 124 | ]); 125 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/RedisController.js: -------------------------------------------------------------------------------- 1 | 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('RedisController', [ 4 | '$scope', 5 | 'Vps', 6 | '$routeParams', 7 | '$log', 8 | function ($scope, Vps, $routeParams, $log) { 9 | $scope.vps = null; 10 | $scope.message = ""; 11 | $scope.loading = false; 12 | $scope.removed = false; 13 | $scope.installed = false; 14 | $scope.sshPassword = ""; 15 | 16 | var minport = 7011; 17 | var maxport = 7470; 18 | var notallowed = [7022, 7023, 7025, 7047, 7080, 7262, 7306, 7307, 7312, 7396, 7400, 7401, 7402]; 19 | var randPort = function () { 20 | var outport = Math.floor(Math.random() * (maxport - minport + 1)) + minport; 21 | // recursion 22 | if (notallowed.indexOf(outport) !== -1) { 23 | $log.debug('ports collided', outport); 24 | outport = randPort(); 25 | } 26 | return outport; 27 | }; 28 | $scope.portgen = function () { 29 | $scope.redis.port = randPort(); 30 | }; 31 | 32 | $scope.redis = { 33 | port: 6379, 34 | password: "", 35 | generatePassword: true, 36 | noPassword: false, 37 | localOnly: true, 38 | rootPassword: "" 39 | }; 40 | 41 | Vps.get($routeParams.vps, function (err, vps) { 42 | if (err) { 43 | $scope.message = err.message || err.error || err; 44 | return; 45 | } 46 | $scope.vps = vps; 47 | }) 48 | 49 | $scope.install = function (params) { 50 | $scope.removed = false; 51 | $scope.loading = true; 52 | $scope.message = "Installing Redis..."; 53 | 54 | Vps.installRedis($scope.vps._id, $scope.redis, function (err, res) { 55 | $scope.loading = false; 56 | if (err) { 57 | $scope.message = err.message || err.error || err; 58 | return; 59 | } 60 | $scope.redis.password = res.password; 61 | $scope.vps.redis = true; 62 | $scope.installed = true; 63 | $scope.message = ""; 64 | }); 65 | }; 66 | 67 | $scope.uninstall = function () { 68 | $scope.installed = false; 69 | $scope.loading = true; 70 | $scope.message = "Removing Redis..."; 71 | 72 | Vps.uninstallRedis({ _id: $scope.vps._id, rootPassword: $scope.redis.rootPassword}, function (err, res) { 73 | $scope.loading = false; 74 | if (err) { 75 | $scope.message = err.message || err.error || err; 76 | return; 77 | } 78 | $scope.redis = res; 79 | $scope.vps.redis = false; 80 | $scope.removed = true; 81 | $scope.message = ""; 82 | }); 83 | }; 84 | 85 | } 86 | ]); 87 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/VpsCreateController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('VpsCreateController', [ 4 | '$scope', 5 | 'Vps', 6 | '$timeout', 7 | '$interval', 8 | function ($scope, Vps, $timeout, $interval) { 9 | $scope.vps = {}; 10 | $scope.message = ""; 11 | $scope.saving = false; 12 | $scope.done = false; 13 | $scope.logs = ""; 14 | $scope.logcheck = null; // timer 15 | var logElement = document.getElementById('server-logs'); 16 | var setScroll = function () { 17 | logElement.scrollTop = logElement.scrollHeight; 18 | }; 19 | var checkLogs = function () { 20 | Vps.get($scope.vps._id, function (err, vps) { 21 | if (err) { 22 | $scope.logs += err.message || err.error || err; 23 | } 24 | else if (vps) { 25 | $scope.logs = vps.logs; 26 | } 27 | 28 | if (vps && vps.status !== "install") { 29 | $interval.cancel($scope.logcheck); 30 | } 31 | // BAD 32 | $timeout(setScroll, 1); 33 | }); 34 | }; 35 | 36 | $scope.save = function () { 37 | $scope.saving = true; 38 | $scope.message = "Installing your server. This will take several minutes. Please do not leave the page."; 39 | 40 | $scope.logs = ""; 41 | $scope.logcheck = $interval(checkLogs, 3000); 42 | 43 | Vps.create($scope.vps, function (err, data) { 44 | $scope.saving = false; 45 | $interval.cancel($scope.logcheck); 46 | if (err) { 47 | $scope.message = err.message || err.error; 48 | if ($scope.logs) { 49 | $scope.logs += $scope.message; 50 | } 51 | if (data !== 400) { 52 | Vps.remove($scope.vps._id, function (err, data) { 53 | if (err) { 54 | console.error('error removing vps after failed creation', err); 55 | return; 56 | } 57 | console.log('removed vps after failed creation', data); 58 | }); 59 | } 60 | // BAD 61 | setScroll(); 62 | return; 63 | } 64 | $scope.message = "Done."; 65 | $scope.done = true; 66 | $scope.vps = data; 67 | }); 68 | }; 69 | 70 | } 71 | ]); 72 | }; 73 | -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/VpsListController.js: -------------------------------------------------------------------------------- 1 | var uuid = require('uuid'); 2 | exports = module.exports = function (ngApp) { 3 | ngApp.controller('VpsListController', [ 4 | '$scope', 5 | '$rootScope', 6 | '$location', 7 | 'Vps', 8 | 'Account', 9 | function ($scope, $rootScope, $location, Vps, Account) { 10 | $scope.$location = $location; 11 | $scope.vpses = null; 12 | $scope.message = ""; 13 | 14 | Vps.getAll(function (err, vpses) { 15 | if (err) { 16 | $scope.message = err.error; 17 | return; 18 | } 19 | $scope.vpses = vpses; 20 | }); 21 | 22 | $scope.hidekey = function () { 23 | delete $rootScope.account.sshkey_pub; 24 | }; 25 | 26 | $scope.viewSshKey = function () { 27 | $scope.message = ""; 28 | Account.get("sshkey_pub", function (err, account) { 29 | if (err) { 30 | $scope.message = err.error; 31 | return; 32 | } 33 | $rootScope.account = account; 34 | }); 35 | }; 36 | 37 | $scope.rekeygen = function () { 38 | $scope.message = ""; 39 | var really = confirm('Confirm ssh key regeneration.\n\nThis can never be undone.'); 40 | if (!really) { 41 | return; 42 | } 43 | Account.keygen(function (err, account) { 44 | if (err) { 45 | $scope.message = err.error; 46 | return; 47 | } 48 | $rootScope.account = account; 49 | }); 50 | }; 51 | } 52 | ]); 53 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/controllers/VpsViewController.js: -------------------------------------------------------------------------------- 1 | exports = module.exports = function (ngApp) { 2 | ngApp.controller('VpsViewController', [ 3 | '$scope', 4 | '$routeParams', 5 | '$interval', 6 | 'Vps', 7 | 'App', 8 | function ($scope, $routeParams, $interval, Vps, App) { 9 | $scope.isUpgrading = false; 10 | $scope.message = ""; 11 | $scope.vps = null; 12 | 13 | var getvps = function () { 14 | $scope.message = ""; 15 | Vps.get($routeParams._id, function (err, vps) { 16 | $scope.message = ""; 17 | if (err) { 18 | $scope.vps = {}; 19 | $scope.message = err.message || err.error || err; 20 | return; 21 | } 22 | // likely a static html page response 23 | if (typeof vps.info === 'string') { 24 | vps.info = { error: vps.info }; 25 | } 26 | if (!vps.info || vps.info.error) { 27 | $scope.message = "Unable to retrieve server stats. Your server is not reachable. "; 28 | if (vps.info) { 29 | if (vps.info.message) { 30 | $scope.message += vps.info.message + ' '; 31 | } 32 | if (vps.info.error && vps.info.error.message) { 33 | $scope.message += vps.info.error.message; 34 | } 35 | } 36 | } 37 | // making sure proper objects are available for view. 38 | if (!vps.info) { 39 | vps.info = { apps: [] }; 40 | } 41 | if (!vps.info.apps) { 42 | vps.info.apps = []; 43 | } 44 | vps.info.apps.forEach(function (a) { 45 | a.env = JSON.stringify(a.env); 46 | }); 47 | $scope.vps = vps || $scope.vps; 48 | }); 49 | }; 50 | // $interval(getvps, 8000); 51 | getvps(); 52 | 53 | // remove vps 54 | $scope.remove = function () { 55 | $scope.message = ''; 56 | var conf = confirm("Really remove this server?"); 57 | if (!conf) { 58 | return; 59 | } 60 | Vps.remove($scope.vps._id, function (err) { 61 | if (err) { 62 | $scope.message = err.message || err.error || err; 63 | return; 64 | } 65 | window.open('/#/list', '_self'); 66 | }); 67 | }; 68 | 69 | $scope.updateSheep = function () { 70 | $scope.message = ''; 71 | $scope.isUpgrading = true; 72 | Vps.updateSheep($scope.vps._id, { password: $scope.password }, function (err, vps) { 73 | $scope.password = ""; 74 | $scope.isUpgrading = false; 75 | if (err) { 76 | $scope.message = err.message || err.error || err; 77 | return; 78 | } 79 | getvps(); 80 | $scope.showUpdatePanel = false; 81 | }); 82 | }; 83 | 84 | $scope.removeApp = function (app) { 85 | var conf = confirm("Really remove this app?"); 86 | if (!conf) { 87 | return; 88 | } 89 | app.processing = true; 90 | app.message = ""; 91 | // in case they reinstalled the sheep on this box and apps remained 92 | app.vps = $scope.vps._id; 93 | App.remove(app, function (err, result) { 94 | app.processing = false; 95 | if (err) { 96 | app.message = err.message || err.error || err; 97 | return; 98 | } 99 | getvps(); 100 | }); 101 | }; 102 | 103 | $scope.action = function (app, action) { 104 | app.processing = true; 105 | app.message = ""; 106 | App.action({ 107 | action: action, 108 | vps: app.vps, 109 | _id: app._id 110 | }, function (err, result) { 111 | app.processing = false; 112 | if (err) { 113 | app.message = err.message || err.error || err; 114 | return; 115 | } 116 | getvps(); 117 | }); 118 | }; 119 | 120 | $scope.setEnv = function (app) { 121 | app.processing = true; 122 | app.message = ""; 123 | var newEnv; 124 | try { 125 | var newEnv = JSON.parse(app.newEnv); 126 | } 127 | catch (ignored) { 128 | app.message = "Invalid JSON."; 129 | app.processing = false; 130 | return; 131 | } 132 | App.setEnv({ 133 | vps: app.vps, 134 | _id: app._id 135 | }, newEnv, function (err, result) { 136 | app.processing = false; 137 | if (err) { 138 | app.message = err.message || err.error || err; 139 | return; 140 | } 141 | getvps(); 142 | }); 143 | }; 144 | 145 | 146 | } 147 | ]); 148 | }; 149 | -------------------------------------------------------------------------------- /paastor-server/public/js/directives/pa-enter.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | exports = module.exports = function () { 3 | return { 4 | link: function (scope, element, attrs) { 5 | element.bind("keypress", function (event) { 6 | if (event.which === 13 && !event.shiftKey) { 7 | scope.$apply(function () { 8 | scope.$eval(attrs.paEnter); 9 | }); 10 | event.preventDefault(); 11 | } 12 | }); 13 | } 14 | }; 15 | }; -------------------------------------------------------------------------------- /paastor-server/public/js/readable-time.js: -------------------------------------------------------------------------------- 1 | exports = module.exports = function () { 2 | return function(seconds) { 3 | var day, format, hour, minute, month, week, year; 4 | seconds = parseInt(seconds, 10); 5 | minute = 60; 6 | hour = minute * 60; 7 | day = hour * 24; 8 | week = day * 7; 9 | year = day * 365; 10 | month = year / 12; 11 | format = function(number, string) { 12 | string = number === 1 ? string : "" + string + "s"; 13 | return "" + number + " " + string; 14 | }; 15 | switch (false) { 16 | case !(seconds < minute): 17 | return format(seconds, 'second'); 18 | case !(seconds < hour): 19 | return format(Math.floor(seconds / minute), 'minute'); 20 | case !(seconds < day): 21 | return format(Math.floor(seconds / hour), 'hour'); 22 | case !(seconds < week): 23 | return format(Math.floor(seconds / day), 'day'); 24 | case !(seconds < month): 25 | return format(Math.floor(seconds / week), 'week'); 26 | case !(seconds < year): 27 | return format(Math.floor(seconds / month), 'month'); 28 | default: 29 | return format(Math.floor(seconds / year), 'year'); 30 | } 31 | }; 32 | }; -------------------------------------------------------------------------------- /paastor-server/public/p2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/p2.xcf -------------------------------------------------------------------------------- /paastor-server/public/pages/changelog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Changelog - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Changelog

27 |

Changes to Paastor will be displayed here.

28 |

2014-11-12 Create app from CLI

29 |

New CLI command:

30 |
pstr create-app [server] [app]

31 |

2014-10-18

32 |

CLI open sourced

33 |

Improved CLI performance and bug fixes. The CLI tool pstr is now open source on Github.

34 |

35 | An alpha version of a library now exists, when `npm install paastor` is run without the 36 | `-g` global option. 37 |


38 |

2014-09-21

39 |

MongoDB

40 |

Paastor now supports an experimental service allowing you to install MongoDB in one step.

41 |

MongoDB can be setup for remote connections or local-only access.


42 |

2014-09-16

43 |

Redis

44 |

Paastor now supports an experimental service allowing you to install Redis in one step.

45 |

Redis can be setup for remote connections or local-only access.


46 |

2014-09-11

47 |

CLI tool renamed

48 |

$ paastor [commands] and the npm package paastor-cli have been renamed.

49 |

Now install with

50 |
$   npm install -g paastor
51 |

and use the CLI like

52 |
$   pstr [commands]
53 |







54 | 62 | 74 | 75 | -------------------------------------------------------------------------------- /paastor-server/public/pages/concepts.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Basic overview of Paastor Node.js deployment cycle - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Paastor Concepts

27 |

Overview

28 |

Paastor

29 |

A service with a CLI npm install -g paastor that helps you deploy Node.js apps in minimal steps.

30 |

Paastor will install the Sheep service on your server, then you can add as many apps as you need.

31 |

32 | A thin UI on the web lets you start and stop apps, manage environment variables, install MongoDB 33 | and Redis, and upload SSL certificates. 34 |

35 |

Sheep

36 |

A deployment and app management service on your server.

37 |

Paastor securely sends commands and apps to your server via Sheep.

38 |

Sheep keeps your apps running and restarts them when they crash.

39 |

Sheep has a proxy that supports SSL and an API for Paastor to manage your apps.

40 |

Becoming a Sheep does not mean your server is locked down in any way.


41 |

CLI

42 |

A command line interface (CLI) to control your apps and servers on the Paastor service.

43 |







44 | 52 | 64 | 65 | -------------------------------------------------------------------------------- /paastor-server/public/pages/contact.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Email and contact for Paastor - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Contact


27 |

hello@paastor.com

28 |







29 | 37 | 49 | 50 | -------------------------------------------------------------------------------- /paastor-server/public/pages/docs.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Node.js server deployment documentation - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Paastor Documentation

27 |

5 Minute Quickstart Usage Guide

28 |

Basic Concepts

29 |

pstr, the Paastor CLI

30 |

Your Server, a Sheep - what gets installed

31 |

Installing Redis

32 |

Installing MongoDB

33 |

SSL setup

34 |

FAQ - frequently asked questions

35 |

Changelog

36 |







37 | 45 | 57 | 58 | -------------------------------------------------------------------------------- /paastor-server/public/pages/faq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FAQ - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Frequently Asked Questions

27 |

(FAQ)


28 |

Why do you need my root password?

29 |

30 | Your root password enables Paastor to securely log into your server and install all of the 31 | dependencies required to run a Node.js app, MongoDB, or Redis. Things like opening ports 32 | and installing packages need to be done as root. 33 |


34 |

Can I trust you with my root password?

35 |

36 | Yes, but technically you don't need to. As soon as Paastor does it's thing, you can change 37 | your root password, if it makes you feel better. However,Paastor does not store your root password. 38 |

39 |

It may help to know:

40 |
46 |

Will my apps run as root?

47 |

No, they run as a forever-monitor subprocess of Sheep, which is spawned by forever (-g).


48 |

How do I detect if a request was HTTPS or HTTP

49 |

50 | Since HTTPS traffic to your apps (if you're using SSL) will come through a proxy, 51 | it will not appear to be secure from your application's perspective. 52 |

53 |

To detect HTTPS behind the Sheep proxy, look at thereferrer header.

54 |
referrer: https://www.example.com

55 |







56 | 64 | 76 | 77 | -------------------------------------------------------------------------------- /paastor-server/public/pages/mongo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Super fast MongoDB installation - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

MongoDB on Paastor

27 |

Paastor now supports simple MongoDB deployments. With a few clicks, you can have MongoDB running on any of your servers.

28 |

29 | From the Server Manager, hit the MongoDB checkbox for one of your servers and fill out the required 30 | fields. Take note of any security information you set - it will not be saved by Paastor. In 31 | a few moments, it will be installed and you will be ready to connect. 32 |

33 |

Remote access to MongoDB

34 |

Often people use MongoDB in a trusted environment and do not allow it to receive remote connections.

35 |

If you opt for remote access, be aware of how to connect, and that it may be slightly different than connecting to local or cloud based MongoDB services. This is because local and 36 | cloud systems shield you from some of the normal MongoDB administration, and create 37 | granular permissions at the database level. 38 |

39 |

Paastor creates an admin user which you can use to connect to any database, and create new users for those databases.

40 |

However, you must specify that you are connecting as an admin user. This is because 41 | MongoDB stores database permissions inside each database. 42 |

43 |

You must tell MongoDB that your authSource is admin.

44 |
Querystring method
45 |
var mongoose = require('mongoose');
46 |  
47 | var mongoUri = "mongodb://username:password@3.3.3.3:27017/somedatabase?authSource=admin";
48 | mongoose.connect(mongoUri);
49 |
Options object method
50 |
var mongoose = require('mongoose');
51 |  
52 | var mongoUri = "mongodb://username:password@3.3.3.3:27017/somedatabase";
53 | var options = {
54 |       auth: { authSource: 'admin' }
55 | };
56 | mongoose.connect(mongoUri, options);

57 |

Creating a MongoDB database

58 |

New databases are created immediately when you connect to them. There is no need to create one.

59 |







60 | 68 | 80 | 81 | -------------------------------------------------------------------------------- /paastor-server/public/pages/pstr-cli.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | pstr, the Paastor command line deployment tool - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

pstr - the Paastor CLI tool

27 |

Installation

28 |
$   npm install -g paastor
29 |

List of commands

30 |
$   pstr --help
 31 |   
 32 | Usage: pstr [options] [command]
 33 |  
 34 | Commands:
 35 |  
 36 | login [options] 
 37 |   Sign into Paastor (prompts for credentials or use -u, --user and -p, --pass)
 38 |  
 39 | logout 
 40 |   Sign out of Paastor
 41 |  
 42 | servers 
 43 |   Get a list of servers for this account
 44 |  
 45 | logs [server] [app]
 46 |   Get the logs for a server (when no app param) or an app on the server
 47 |  
 48 | server [_id]
 49 |   Get detailed info about a server
 50 |  
 51 | push [options] [server] [app]
 52 |   Push an app to your server (both must already exist)
 53 |  
 54 | create-app [server] [app]
 55 |   Create an app
 56 |  
 57 | stop [server] [app]
 58 |   Stop an app
 59 |  
 60 | start [server] [app]
 61 |   Start an app
 62 |  
 63 | restart [server] [app]
 64 |   Stop then immediately start an app
 65 |  
 66 | setenv [server] [app]
 67 |   Initiate the process of setting an app environment variable (must restart app to take effect)
 68 |  
 69 | install-node [server] [version]
 70 |   Trigger the installation of a version of Node.js, to be available to apps.
 71 |  
 72 |  
 73 | Options:
 74 |  
 75 |   -h, --help     output usage information
 76 |   -V, --version  output the version number
 77 |  
 78 |  
 79 |  
80 |

Disabling NPM install

81 |

Sometimes you might has special packages or other reasons for wanting to disable npm install.

82 |

When you use the pstr push [server] [app] command, Sheep will attempt to run npm install using the version of Node specified in your package.json engines.node.

83 |

This can be turned off with the --no-npm flag.

84 |
$   pstr push myserver myapp --no-npm
85 |







86 | 94 | 106 | 107 | -------------------------------------------------------------------------------- /paastor-server/public/pages/redis.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Super fast Redis installation - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Redis on Paastor

27 |

With a few clicks, you can have a Redis instance running on any of your servers.

28 |

29 | From the Server Manager, hit the Redis checkbox for one of your servers and fill out the required 30 | fields. In a few moments you will have Redis installed. 31 |

32 |
Changing the password / lost password
33 |

34 | If you lose the Redis password, want to change it, or want to remove it, log into the 35 | server as root and edit requirepass in /etc/redis/redis.conf. 36 |


37 |







38 | 46 | 58 | 59 | -------------------------------------------------------------------------------- /paastor-server/public/pages/ssl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Easy SSL setup for your Node.js apps - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

SSL on Paastor

27 |
SSL is available on paid accounts only.
You don't have to pay very much, but you have to be paying something!
28 |

Add SSL certs and keys in the Server Manager.

29 |

30 | SSL certificates can be re-uploaded an unlimited number of times from the web UI - 31 | in case it changes, or you make a mistake. 32 |

33 |

What happens on the server

34 |

Sheep contains a proxy and a router with support for SSL.

35 |

36 | When you add SSL to an app, the proxy will use the certificates during the requests on behalf 37 | of your app, then route the traffic to your app on process.env.PAASTOR_PORT. 38 |

39 |

This setup is similar to nginx or other proxy servers.


40 |







41 | 49 | 61 | 62 | -------------------------------------------------------------------------------- /paastor-server/public/pages/usage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Usage guide: fast and easy deployment of Node.js apps - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

Usage

27 |

How to deploy a node app to your own infrastructure in 5 minutes using Paastor

28 |

Deploy to cloud servers, VPS, dedicated servers, and more.



29 |

1. Sign up

30 |

Begin by creating an accountand verifying your email address.


31 |

2. Obtain a server

32 |

33 | The most common option is to purchase a VPS (virtual private server) plan from a hosting company. In many 34 | cases you can run multiple Node.js apps for $2 - $10 per month on a VPS. 35 |

36 |

VPS hosting is very competitive and very cheap compared to cloud hosting. Examples of hosting companies are: Linode, Digital Ocean, Chicago VPS, and many more.Server Bear and LowEndBox are tools to help you compare VPS hosts. (Paastor is not affiliated with any of the services 37 | mentioned.) 38 |

39 |

The only officially supported server OS on Paastor (for now) isUbuntu 14.04.

40 |

Next, be sure to create a DNS "A" record with your DNS provider, and point to your server's IP address, for the domain you intend to serve.


41 |

3. Add your server to Paastor

42 |

43 | Log in to Paastor and press the 'New Server' button from the Server Manager screen. 44 | Fill out all the fields. This will install the Sheep service on your server and 45 | allow you to push apps to the server. 46 |


47 |

4. Create an app on the server in Paastor

48 |

From the Paastor UI, add an app to your server. You must add an app from the UI before pushing code.

49 |

Yourpackage.json must have the following fields (these are example values):

50 |
{
 51 |     // a single startup script
 52 |     "main": "aStartupScript.js",
 53 |     // list of domains for the Sheep proxy router
 54 |     "domains": ["example.com", "www.example.com"],
 55 |     "engines": {
 56 |         // a single node version - no ranges
 57 |         "node": "0.10.31"
 58 |     }
 59 | }

60 |

5. Install thepstr command line tool

61 |
$  npm install -g paastor

62 |

6. Log in on the CLI

63 |
$   pstr login

64 |

7. (optional) Install the right version of Node for your app

65 |

Usepstr install-node [server] [version] to add a version of Node to your server.

66 |
$   pstr install-node myserver1 0.10.28
67 |

Depending on the version, it may be installed quickly, or may need to compile from source.


68 |

8. Push your application

69 |

Usepstr push [server] [app] to push the app in the current directory to the specified server.

70 |
$  pstr push myserver1 someapp
71 |
push myserver1 someapp
 72 |    Checking package.json
 73 |      package.json exists
 74 |      version ok 0.10.28
 75 |      Domains look ok
 76 |    Checking server...
 77 |      Found myserver
 78 |      Status ok
 79 |      0.10.31 installed
 80 |    Creating package from current directory...
 81 |      Package created. 10.46mb
 82 |    Prepping package for sending...
 83 |      Package is ready to send.
 84 |    Uploading and installing...
 85 |      Ok
 86 |    Stopping app...
 87 |      Stopped.
 88 |    Starting app...
 89 |      Started
 90 |    Cleaning up package...
 91 |      Package cleaned.
 92 |    Push complete.

93 |

9. (optional) Check the logs

94 |
Server logs
95 |
$  pstr logs myserver1
96 |
Application logs
97 |
$  pstr logs myserver1 someapp

98 |

Help

99 |

All CLI commands can be seen by runningpstr --help.


100 |

Open source

101 |

It's on the roadmap to release many parts of Paastor under an open source license.

102 |

Until then, refer to thedocumentation about the files Paastor puts on your server.

103 |







104 | 112 | 124 | 125 | -------------------------------------------------------------------------------- /paastor-server/public/pages/vision.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | About Paastor: solving the Node.js production deployment problem - Paastor for Node.js 5 | Paastor for Node.js 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |

About Paastor

27 |
Support / Contact Information
28 |
Terms of Service and Acceptable Use

29 |

The Paastor Vision


30 |

Node.js is awesome, but there's a problem:

31 |
Setting up Node in production is a time suck.
32 |
33 | PaaS services make it easy - but they're expensive and locked down, and that won't work 34 | for everyone. 35 |

36 |

Paastor solves the problem.

37 |

Virtual servers are super cheap. So with your virtual server, you can:

38 |
1. Provision a Node.js-capable production server in one step.
39 |
2. Deploy apps from the CLI in one step.
40 |
3. Keep apps up and restart them automatically when they die.
41 |
4. Use web sockets.
42 |
5. Host multiple Node apps, with multiple Node versions, on the same box.
43 |
6. Use your own SSL certificates.
44 |
7. Use your own domain.
45 |
8. Retain full control of your server.
46 |

with the added bonus of:

47 |
One-click Redis setup
48 |
One-click MongoDB setup
49 |







50 | 58 | 70 | 71 | -------------------------------------------------------------------------------- /paastor-server/public/redis-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/redis-white.png -------------------------------------------------------------------------------- /paastor-server/public/redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/redis.png -------------------------------------------------------------------------------- /paastor-server/public/sman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruffrey/paastor/8e83ea8acabf33a121aca419d2a067c8b81cff1c/paastor-server/public/sman.png -------------------------------------------------------------------------------- /paastor-server/routes/home.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | var debug = require('debug')('paastor'); 4 | var config = require('../config'); 5 | 6 | /* GET home page. */ 7 | router.get('/', function(req, res) { 8 | res.render('index', { title: 'Paastor' }); 9 | }); 10 | router.get('/conf/:_id/:conf', function(req, res, next) { 11 | req.Account 12 | .findOne({ _id: req.params._id }) 13 | .exec(function (err, account) { 14 | console.log(err, account); 15 | var genericMessage = new Error("Invalid ID or confirmation code. It may have already been used."); 16 | genericMessage.status = 404; 17 | if (err) { 18 | debug('confirmation error', err); 19 | return res.render('error', { 20 | error: genericMessage 21 | }); 22 | } 23 | if (!account) { 24 | return res.render('error', { 25 | error: genericMessage 26 | }); 27 | } 28 | console.log(account.conf); 29 | account.conf = null; 30 | account.save(function (err, saved) { 31 | if (err) { 32 | return next(err); 33 | } 34 | res.render('conf', { 35 | title: 'Email confirmed', 36 | message: 'Sign in to continue.' 37 | }); 38 | 39 | 40 | // admin notification that an account has been confirmed 41 | req.mandrill('/messages/send', { 42 | message: { 43 | to: [{email: config.email.from, name: 'Paastor'}], 44 | from_email: config.email.from, 45 | subject: "[Paastor] - confirmed", 46 | text: "Confirmed account: " + saved.email + " (" + saved._id + ")" 47 | } 48 | }, 49 | function (err, data) { 50 | if (err) { 51 | debug('mandrill error', err, data); 52 | return next(err); 53 | } 54 | 55 | debug('Account confirmation notification to admin.', saved.email, saved._id); 56 | }); 57 | 58 | 59 | }); 60 | }); 61 | }); 62 | router.get('/password-reset/:_id/:conf', function(req, res, next) { 63 | req.Account 64 | .findOne({ _id: req.params._id, conf: req.params.conf }) 65 | .exec(function (err, account) { 66 | var genericMessage = new Error("Invalid ID or reset code."); 67 | genericMessage.status = 404; 68 | if (err) { 69 | debug('password reset error', err); 70 | return next(genericMessage); 71 | } 72 | if (!account) { 73 | return next(genericMessage); 74 | } 75 | res.render('reset', { 76 | title: 'Password reset', 77 | message: 'Change your password, then log in again.', 78 | conf: account.conf, 79 | _id: account._id 80 | }); 81 | }); 82 | }); 83 | module.exports = router; 84 | -------------------------------------------------------------------------------- /paastor-server/spec/paastor-credentials.json.example: -------------------------------------------------------------------------------- 1 | {"email": "asdf", "password": "asdf"} -------------------------------------------------------------------------------- /paastor-server/spec/seed-stripe.js: -------------------------------------------------------------------------------- 1 | var config = require('../config'); 2 | var stripe = require('stripe')(config.stripe.secret); 3 | var async = require('async'); 4 | 5 | var plans = []; 6 | 7 | var pricePerServer = 0.99; 8 | 9 | for (var i=0; i < 51; i++) { 10 | 11 | var plan = { 12 | currency: 'usd', 13 | id: 'server-' + i, 14 | interval: 'year', 15 | name: i + (i === 1 ? ' server' : ' servers @' + pricePerServer), 16 | amount: Math.floor( pricePerServer * i * 12 * 100), 17 | statement_description: 'PAASTOR' 18 | }; 19 | plans.push(plan); 20 | } 21 | 22 | async.each(plans, function (plan, cb) { 23 | stripe.plans.create(plan, function (err, data) { 24 | if (err) { 25 | console.error(' ERROR', err, plan.id); 26 | } 27 | cb(); 28 | }); 29 | }, function (err, data) { 30 | if (err) { 31 | console.error('ERROR', err); 32 | return; 33 | } 34 | console.log('\nDONE'); 35 | }); -------------------------------------------------------------------------------- /paastor-server/spec/sheep-client.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | require('../sheep/bin/www'); 3 | 4 | var SheepClient = require('../sheep-client'); 5 | var sheep = new SheepClient('http://localhost:3000', 'asdf'); 6 | var should = require('should'); 7 | var uuid = require('node-uuid'); 8 | var rimraf = require('rimraf'); 9 | var path = require('path'); 10 | 11 | var request = require('supertest'); 12 | 13 | describe('sheep-client', function () { 14 | this.timeout(30000); 15 | 16 | after(function deleteTmpCrap() { 17 | var paastorTmp = path.join(__dirname, '../tmp/'); 18 | var sheepTmp = path.join(__dirname, '../sheep/tmp/'); 19 | rimraf.sync(paastorTmp); 20 | rimraf.sync(sheepTmp); 21 | }); 22 | 23 | describe('getting information about the sheep vps', function () { 24 | it('responds with an object of expected properties', function (done) { 25 | sheep.info(function (err, info) { 26 | info.should.be.an.Object; 27 | info.uptime.should.be.a.Number; 28 | info.freemem.should.be.a.Number; 29 | info.totalmem.should.be.a.Number; 30 | info.cpus.should.be.an.Array; 31 | (info.cpus.length > 0).should.be.ok; 32 | info.type.should.be.a.String; 33 | info.release.should.be.a.String; 34 | info.arch.should.be.a.String; 35 | info.platform.should.be.a.String; 36 | done(); 37 | }); 38 | }); 39 | }); 40 | 41 | describe('getting all apps on a vps', function () { 42 | it('lists them in an array', function (done) { 43 | sheep.getAllApps(function (err, apps) { 44 | if(err) { 45 | return done(err); 46 | } 47 | should.exist(apps); 48 | apps.should.be.an.Array; 49 | done(); 50 | }); 51 | }); 52 | }); 53 | 54 | describe('createApp', function () { 55 | var appParams = { 56 | _id: "someApp-" + uuid.v4(), 57 | vps: "someVps-" + uuid.v4(), 58 | gitUrl: 'https://github.com/ruffrey/wwx.git', 59 | gitBranch: 'master', 60 | script: 'app.js', 61 | port: 4003, 62 | env: { NODE_ENV: "development" }, 63 | domains: ['five.github.io'] 64 | }; 65 | 66 | after(function (done) { 67 | sheep.removeApp(appParams._id, done); 68 | }); 69 | 70 | it('works', function (done) { 71 | sheep.createApp(appParams, function (err, newApp) { 72 | if(err) { 73 | return done(err); 74 | } 75 | 76 | newApp._id.should.equal(appParams._id); 77 | 78 | // defined by the sheep 79 | newApp.path.should.be.a.String; 80 | 81 | // See if the app is running 82 | request('http://localhost:4003') 83 | .get('/') 84 | .expect(200, done); 85 | 86 | }); 87 | }); 88 | }); 89 | 90 | describe('deleting an app', function () { 91 | var appParams = { 92 | _id: "someApp-" + uuid.v4(), 93 | vps: "someVps-" + uuid.v4(), 94 | gitUrl: 'https://github.com/ruffrey/wwx.git', 95 | gitBranch: 'master', 96 | script: 'app.js', 97 | port: 4003, 98 | env: { NODE_ENV: "test" }, 99 | domains: ['five.github.io'] 100 | }; 101 | 102 | before(function (done) { 103 | sheep.createApp(appParams, function (err, newApp) { 104 | appParams = newApp; 105 | done(err); 106 | }); 107 | }); 108 | 109 | it('checks that the app exists before we delete it', function (done) { 110 | sheep.getApp(appParams._id, function (err, app) { 111 | should.not.exist(err); 112 | app.should.be.an.Object.and.not.an.Array; 113 | app._id.should.be.a.String; 114 | app._id.should.equal(appParams._id); 115 | done(); 116 | }); 117 | }); 118 | 119 | it('removes the app', function (done) { 120 | 121 | sheep.removeApp(appParams._id, function (err) { 122 | should.not.exist(err); 123 | sheep.getApp(appParams._id, function (err, body) { 124 | err.should.be.an.Object; 125 | body.error.status.should.equal(404); 126 | done(); 127 | }); 128 | }); 129 | }); 130 | 131 | }); 132 | }); -------------------------------------------------------------------------------- /paastor-server/spec/sheep-ssh-client.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var should = require('should'); 3 | var SheepSshClient = require('../sheep-ssh-client'); 4 | var vpsCredentials = require('./vps-credentials.json'); 5 | var uuid = require('uuid'); 6 | 7 | if (!vpsCredentials.hostname || !vpsCredentials.rootPassword) { 8 | console.warn("VPS test server has not been setup properly. Check spec/vps-credentials.json. Tests will be skipped."); 9 | return; 10 | } 11 | 12 | var client; 13 | 14 | describe('sheep-ssh-client', function () { 15 | this.timeout(12000); 16 | it('connects', function (done) { 17 | new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, function (err, output) { 18 | if (err) { 19 | return done(err); 20 | } 21 | output.should.be.a.String; 22 | output.should.not.be.empty; 23 | done(); 24 | }); 25 | }); 26 | 27 | describe('apt-get update', function () { 28 | this.timeout(1000 * 60 * 1); 29 | before(function (done) { 30 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 31 | }); 32 | it('works', function (done) { 33 | client.aptUpdate(function (err, data) { 34 | if (err) { 35 | return done(err); 36 | } 37 | done(); 38 | }); 39 | }); 40 | }); 41 | 42 | describe('installing git', function () { 43 | this.timeout(1000 * 30); 44 | before(function (done) { 45 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 46 | }); 47 | it('works', function (done) { 48 | client.installGit(function (err, data) { 49 | if (err) { 50 | return done(err); 51 | } 52 | done(); 53 | }); 54 | }); 55 | }); 56 | 57 | describe('installing node.js', function () { 58 | this.timeout(1000 * 60); 59 | before(function (done) { 60 | client = new SheepSshClient( 61 | vpsCredentials.hostname, 62 | vpsCredentials.rootPassword, 63 | done 64 | ); 65 | }); 66 | it('works', function (done) { 67 | client.installNode(function (err, data) { 68 | if (err) { 69 | return done(err); 70 | } 71 | done(); 72 | }); 73 | }); 74 | }); 75 | 76 | describe('installing mongo', function () { 77 | this.timeout(1000 * 30); 78 | before(function (done) { 79 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 80 | }); 81 | it('works', function (done) { 82 | client.installMongo(function (err, data) { 83 | if (err) { 84 | return done(err); 85 | } 86 | done(); 87 | }); 88 | }); 89 | }); 90 | 91 | describe('installing redis', function () { 92 | this.timeout(1000 * 30); 93 | before(function (done) { 94 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 95 | }); 96 | it('works', function (done) { 97 | client.installRedis(function (err, data) { 98 | if (err) { 99 | return done(err); 100 | } 101 | done(); 102 | }); 103 | }); 104 | }); 105 | 106 | describe.only('installing sheep', function () { 107 | this.timeout(1000 * 60 * 2); 108 | before(function (done) { 109 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 110 | }); 111 | it('works', function (done) { 112 | 113 | var vps = { 114 | _id: "my-vps-id-" + uuid.v4(), 115 | host: vpsCredentials.hostname, 116 | infrastructure: "aws-east", 117 | secret: "asdf" 118 | }; 119 | 120 | client.installSheep(vps, function (err, data) { 121 | if (err) { 122 | return done(err); 123 | } 124 | done(); 125 | }); 126 | }); 127 | }); 128 | 129 | 130 | describe('installing paastor', function () { 131 | this.timeout(1000 * 60 * 2); 132 | before(function (done) { 133 | client = new SheepSshClient(vpsCredentials.hostname, vpsCredentials.rootPassword, done); 134 | }); 135 | it('works', function (done) { 136 | client.installPaastor(function (err, data) { 137 | if (err) { 138 | return done(err); 139 | } 140 | done(); 141 | }); 142 | }); 143 | }); 144 | 145 | }); -------------------------------------------------------------------------------- /paastor-server/spec/vps-credentials.json.example: -------------------------------------------------------------------------------- 1 | {"hostname": "127.0.0.1", "rootPassword": "her"} -------------------------------------------------------------------------------- /paastor-server/views/conf.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1=title 5 | br 6 | h4=message 7 | br 8 | br -------------------------------------------------------------------------------- /paastor-server/views/error.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message || error.message || 'The page you are trying to reach was not found.' 5 | h2= error.status 6 | if (process.env.NODE_ENV !== 'production') 7 | pre #{error.stack} 8 | -------------------------------------------------------------------------------- /paastor-server/views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | div(ng-view) 5 | 6 | br 7 | br 8 | br 9 | -------------------------------------------------------------------------------- /paastor-server/views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html(ng-app="paastor") 3 | head 4 | block vars 5 | - meta = meta || { keywords: "nodejs, paas, deployment, production, forever", "description": "Deploy and keep up Node.js apps, MongoDB and Redis, on your own server."}; 6 | 7 | if (title) 8 | title= title + " - Paastor for Node.js" 9 | if (error) 10 | title= error.message 11 | else 12 | title= "Paastor for Node.js" 13 | 14 | meta(charset="utf8") 15 | meta(name="viewport" content="width=device-width, initial-scale=1") 16 | meta(name="keywords" content=meta.keywords) 17 | meta(name="description" content=meta.description) 18 | 19 | link(rel="icon" type="image/png" href="/favicon.png") 20 | link(rel="shortcut icon" type="image/png" href="/favicon.png") 21 | link(href="https://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet") 22 | link(rel='stylesheet' href='/css/bootstrap-lgr.css') 23 | link(rel='stylesheet' href='/css/animate.css') 24 | link(rel='stylesheet' href='/css/style.css') 25 | 26 | script(src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js") 27 | script(src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js") 28 | 29 | script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular.min.js") 30 | script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular-route.min.js") 31 | script(src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-beta.17/angular-resource.min.js") 32 | script(src="https://js.stripe.com/v2/") 33 | script(src="/build/js/app.js") 34 | body(ng-controller="NavController") 35 | block content 36 | 37 | br 38 | br 39 | br 40 | br 41 | br 42 | br 43 | br 44 | 45 | #footer 46 | .row 47 | .col-xs-4(ng-show="!account.email") 48 | span.help-block 49 | strong: a(href="/") Paastor 50 | |    51 | span.hidden-xs: small A PaaS-like experience with your own servers. 52 | 53 | .col-xs-4(ng-show="account.email") 54 | span.help-block 55 | a(href="/#/list"): strong 56 | span.hidden-xs Paastor 57 | | Server Manager 58 | 59 | .col-xs-4.center: span.help-block 60 | a(href="/pages/vision.html") About 61 | |      62 | a(href="/pages/docs.html") Docs 63 | 64 | 65 | .col-xs-4.right 66 | span.help-block(ng-show="account.email") 67 | small.hidden-xs: small {{ account.email }} 68 | |    69 | a.btn.btn-xs.btn-default(href="javascript:void(0)" ng-click="logout()") Sign Out 70 | script(async). 71 | if (document.location.hostname === 'paastor.com') { 72 | if (document.location.protocol === 'http:') { 73 | window.open(document.location.href.replace('http:', 'https:'), '_self'); 74 | } 75 | // google analytics 76 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); 77 | 78 | ga('create', 'UA-54875912-1', 'auto'); 79 | ga('send', 'pageview'); 80 | } 81 | -------------------------------------------------------------------------------- /paastor-server/views/pages/changelog.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Changelog"; 5 | 6 | block content 7 | .container 8 | h1 Changelog 9 | 10 | p Changes to Paastor will be displayed here. 11 | 12 | h3 2014-11-12 Create app from CLI 13 | p New CLI command: 14 | pre: code pstr create-app [server] [app] 15 | 16 | br 17 | h3 2014-10-18 18 | h4 CLI open sourced 19 | p Improved CLI performance and bug fixes. The CLI tool 20 | code pstr 21 | | is now 22 | a(href="https://github.com/paastor/paastor") open source on Github. 23 | p An alpha version of a library now exists, when `npm install paastor` is run without the 24 | | `-g` global option. 25 | br 26 | h3 2014-09-21 27 | h4 MongoDB 28 | p Paastor now supports an experimental service allowing you to install MongoDB in one step. 29 | p MongoDB can be setup for remote connections or local-only access. 30 | br 31 | 32 | h3 2014-09-16 33 | h4 Redis 34 | p Paastor now supports an experimental service allowing you to install Redis in one step. 35 | p Redis can be setup for remote connections or local-only access. 36 | 37 | br 38 | 39 | h3 2014-09-11 40 | h4 CLI tool renamed 41 | p 42 | code $ paastor [commands] 43 | | and the npm package 44 | code paastor-cli 45 | | have been renamed. 46 | p Now install with 47 | pre: code $ npm install -g paastor 48 | p and use the CLI like 49 | pre: code $ pstr [commands] 50 | 51 | -------------------------------------------------------------------------------- /paastor-server/views/pages/concepts.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Basic overview of Paastor Node.js deployment cycle"; 5 | 6 | block content 7 | .container 8 | h1 Paastor Concepts 9 | p: em Overview 10 | 11 | h3#paastor Paastor 12 | p: em A service with a CLI 13 | code npm install -g paastor 14 | | that helps you deploy Node.js apps in minimal steps. 15 | p Paastor will install the Sheep service on your server, then you can add as many apps as you need. 16 | p A thin UI on the web lets you start and stop apps, manage environment variables, install MongoDB 17 | | and Redis, and upload SSL certificates. 18 | 19 | h3#sheep Sheep 20 | p: em A deployment and app management service on your server. 21 | p Paastor securely sends commands and apps to your server via Sheep. 22 | p Sheep keeps your apps running and restarts them when they crash. 23 | p Sheep has a proxy that supports SSL and an API for Paastor to manage your apps. 24 | p Becoming a Sheep does not mean your server is locked down in any way. 25 | 26 | br 27 | h3#cli CLI 28 | p: em A command line interface (CLI) to control your apps and servers on the Paastor service. 29 | -------------------------------------------------------------------------------- /paastor-server/views/pages/contact.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Email and contact for Paastor"; 5 | 6 | block content 7 | .container 8 | h1 Contact 9 | 10 | br 11 | p hello@paastor.com 12 | 13 | -------------------------------------------------------------------------------- /paastor-server/views/pages/docs.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Node.js server deployment documentation"; 5 | 6 | block content 7 | .container 8 | h1 Paastor Documentation 9 | 10 | h3: a(href="/pages/usage.html") 5 Minute Quickstart Usage Guide 11 | h3: a(href="/pages/concepts.html") Basic Concepts 12 | h3: a(href="/pages/pstr-cli.html") 13 | code pstr 14 | | , the Paastor CLI 15 | h3: a(href="/pages/sheep-system.html") Your Server, a Sheep - what gets installed 16 | h3: a(href="/pages/redis.html") Installing Redis 17 | h3: a(href="/pages/mongo.html") Installing MongoDB 18 | h3: a(href="/pages/ssl.html") SSL setup 19 | h3: a(href="/pages/faq.html") FAQ - frequently asked questions 20 | h3: a(href="/pages/changelog.html") Changelog 21 | 22 | 23 | -------------------------------------------------------------------------------- /paastor-server/views/pages/faq.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "FAQ"; 5 | 6 | block content 7 | .container 8 | h1 Frequently Asked Questions 9 | h2 (FAQ) 10 | 11 | br 12 | 13 | h3#save-root-password Why do you need my root password? 14 | p Your root password enables Paastor to securely log into your server and install all of the 15 | | dependencies required to run a Node.js app, MongoDB, or Redis. Things like opening ports 16 | | and installing packages need to be done as root. 17 | 18 | br 19 | 20 | h3#root-trust Can I trust you with my root password? 21 | p Yes, but technically you don't need to. As soon as Paastor does it's thing, you can change 22 | | your root password, if it makes you feel better. However, 23 | strong Paastor does not store your root password 24 | | . 25 | p It may help to know: 26 | ul 27 | li The root password is transferred to Paastor over https. 28 | li It is used for logging into the server via SSH and necessary to install the Sheep service. 29 | li It is not saved in a database anywhere, even temporarily, and Paastor does not output the password to log files. 30 | li Because it is not saved, you must re-enter your root password to make substantial changes on the server - like installing MongoDB, or upgrading Sheep. This also highlights that Sheep and your apps do not run as root (best practice), and cannot perform these root tasks. 31 | 32 | br 33 | 34 | h3#run-as-root Will my apps run as root? 35 | p No, they run as a forever-monitor subprocess of Sheep, which is spawned by forever (-g). 36 | 37 | br 38 | 39 | 40 | h3#detect-ssl How do I detect if a request was HTTPS or HTTP 41 | p Since HTTPS traffic to your apps (if you're using SSL) will come through a proxy, 42 | | it will not appear to be secure from your application's perspective. 43 | p To detect HTTPS behind the Sheep proxy, look at the 44 | code referrer 45 | | header. 46 | 47 | pre: code referrer: https://www.example.com 48 | 49 | br 50 | -------------------------------------------------------------------------------- /paastor-server/views/pages/mongo.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Super fast MongoDB installation"; 5 | 6 | block content 7 | .container 8 | h1 MongoDB on Paastor 9 | 10 | p Paastor now supports simple MongoDB deployments. With a few clicks, you can have MongoDB running on any of your servers. 11 | 12 | p From the Server Manager, hit the MongoDB checkbox for one of your servers and fill out the required 13 | | fields. Take note of any security information you set - it will not be saved by Paastor. In 14 | | a few moments, it will be installed and you will be ready to connect. 15 | 16 | h3 Remote access to MongoDB 17 | p Often people use MongoDB in a trusted environment and do not allow it to receive remote connections. 18 | P If you opt for remote access, be aware of how to connect, and that it 19 | strong may be slightly different 20 | | than connecting to local or cloud based MongoDB services. This is because local and 21 | | cloud systems shield you from some of the normal MongoDB administration, and create 22 | | granular permissions at the database level. 23 | p 24 | strong Paastor creates an admin user which you can use to connect to any database, 25 | | and create new users for those databases. 26 | 27 | p 28 | strong However, 29 | | you must specify that you are connecting as an admin user. This is because 30 | | MongoDB stores database permissions inside each database. 31 | 32 | p You must tell MongoDB that your 33 | code authSource 34 | | is 35 | code admin 36 | | . 37 | 38 | h6.help-block Querystring method 39 | pre: code var mongoose = require('mongoose'); 40 | | 41 | | var mongoUri = "mongodb://username:password@3.3.3.3:27017/somedatabase?authSource=admin"; 42 | | mongoose.connect(mongoUri); 43 | 44 | h6.help-block Options object method 45 | 46 | pre: code var mongoose = require('mongoose'); 47 | | 48 | | var mongoUri = "mongodb://username:password@3.3.3.3:27017/somedatabase"; 49 | | var options = { 50 | | auth: { authSource: 'admin' } 51 | | }; 52 | | mongoose.connect(mongoUri, options); 53 | 54 | br 55 | h3 Creating a MongoDB database 56 | p New databases are created immediately when you connect to them. There is no need to create one. 57 | -------------------------------------------------------------------------------- /paastor-server/views/pages/pstr-cli.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "pstr, the Paastor command line deployment tool"; 5 | 6 | block content 7 | .container 8 | 9 | h1 10 | code pstr 11 | | - the Paastor CLI tool 12 | 13 | h3 Installation 14 | pre: code $ npm install -g paastor 15 | 16 | h3 List of commands 17 | pre: code $ pstr --help 18 | | 19 | | Usage: pstr [options] [command] 20 | | 21 | | Commands: 22 | | 23 | | login [options] 24 | | Sign into Paastor (prompts for credentials or use -u, --user and -p, --pass) 25 | | 26 | | logout 27 | | Sign out of Paastor 28 | | 29 | | servers 30 | | Get a list of servers for this account 31 | | 32 | | logs [server] [app] 33 | | Get the logs for a server (when no app param) or an app on the server 34 | | 35 | | server [_id] 36 | | Get detailed info about a server 37 | | 38 | | push [options] [server] [app] 39 | | Push an app to your server (both must already exist) 40 | | 41 | | create-app [server] [app] 42 | | Create an app 43 | | 44 | | stop [server] [app] 45 | | Stop an app 46 | | 47 | | start [server] [app] 48 | | Start an app 49 | | 50 | | restart [server] [app] 51 | | Stop then immediately start an app 52 | | 53 | | setenv [server] [app] 54 | | Initiate the process of setting an app environment variable (must restart app to take effect) 55 | | 56 | | install-node [server] [version] 57 | | Trigger the installation of a version of Node.js, to be available to apps. 58 | | 59 | | 60 | | Options: 61 | | 62 | | -h, --help output usage information 63 | | -V, --version output the version number 64 | | 65 | | 66 | | 67 | 68 | h3#no-npm Disabling NPM install 69 | p Sometimes you might has special packages or other reasons for wanting to disable 70 | code npm install 71 | | . 72 | p When you use the 73 | code pstr push [server] [app] 74 | | command, Sheep will attempt to run 75 | code npm install 76 | | using the version of Node specified in your 77 | code package.json 78 | | 79 | code engines.node 80 | | . 81 | p This can be turned off with the 82 | code --no-npm 83 | | flag. 84 | pre: code $ pstr push myserver myapp --no-npm 85 | -------------------------------------------------------------------------------- /paastor-server/views/pages/redis.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Super fast Redis installation"; 5 | 6 | block content 7 | .container 8 | h1 Redis on Paastor 9 | 10 | p With a few clicks, you can have a Redis instance running on any of your servers. 11 | 12 | p From the Server Manager, hit the Redis checkbox for one of your servers and fill out the required 13 | | fields. In a few moments you will have Redis installed. 14 | 15 | 16 | h5 Changing the password / lost password 17 | p If you lose the Redis password, want to change it, or want to remove it, log into the 18 | | server as root and edit 19 | code requirepass 20 | | in 21 | code /etc/redis/redis.conf 22 | | . 23 | 24 | br -------------------------------------------------------------------------------- /paastor-server/views/pages/sheep-system.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Sheep service for Node.js management"; 5 | 6 | block content 7 | .container 8 | h1 Your server, a "Sheep" 9 | 10 | p Sheep is a service which Paastor installs on your server. 11 | p It keeps your apps running, lets you deploy apps, and securely provides a way to get 12 | | information about your system, like CPU usage, memory, and log files. 13 | 14 | h3#system Installed files 15 | 16 | h5.monospace /root/sheep/ 17 | p The API and proxy. 18 | 19 | h5.monospace /root/system.json 20 | p A few bits of information about this system, like the hashed and salted API key. 21 | 22 | h5.monospace /root/sheep_apps/ 23 | p Your applications live in this folder. 24 | 25 | h5.monospace /root/sheep.log, /root/sheep-out.log, /root/sheep-err.log 26 | p The proxy and API logs. 27 | 28 | h5.monospace /root/sheep_logs/ 29 | p Application logs live in this folder. 30 | 31 | h5.monospace /root/sheep_apps/apps.json 32 | p This is the primary file Sheep uses to keep track of your apps. It is highly recommended that 33 | | you do not edit this file, rather use the CLI and Paastor web UI to perform management tasks 34 | | as intended. 35 | p It is recommended that you backup this file in production. 36 | | Some app configuration info may be recovered after a system failure by 37 | | simply re-adding them and rebooting the server. However losing data is quite possible. 38 | | Especially things like SSL certificates and environment variables. 39 | 40 | h3 Other changes made to the server 41 | p 42 | strong nvm, 43 | | Node.js and npm are installed. 44 | p A cron task is setup to start start when your server boots. 45 | p Forever.js (-g) is used to keep your Sheep running. 46 | p Forever-monitor is used from Sheep to keep individual apps running. 47 | p Web servers like Apache and nginx are uninstalled. 48 | p When installing MongoDB or Redis, the appropriate ports are opened (if you select those options). 49 | br 50 | 51 | br 52 | 53 | h3#multiple-node-versions Using multiple versions of Node.js 54 | p Paastor supports having multiple versions of Node.js running on the same server. 55 | p For example, you can have one app running under 0.8.3 and another app running under 0.10.31. 56 | p By default, a 0.10.x version of Node installed during the provisioning process. 57 | p During 58 | code pstr push 59 | | there is a check that your 60 | code engines.node 61 | | version is already on the server. You will receive an error if it is not yet installed. 62 | 63 | p Install a new version from the CLI: 64 | pre: code $ pstr install-node 0.10.24 65 | 66 | br 67 | 68 | 69 | h2 Your apps running on a Sheep 70 | p You can run multiple apps on a Sheep server. 71 | p Here is basic information about your apps. 72 | 73 | h3#engines-node 74 | span.monospace engines.node 75 | | formatting 76 | p Every app must have a 77 | strong single version 78 | | specified in the 79 | code engines.node 80 | | field in the 81 | code package.json 82 | | file. 83 | 84 | h5 Correct 85 | pre: code { 86 | | "engines": { "node": "0.10.31" } 87 | | } 88 | 89 | h5 Incorrect 90 | pre: code { 91 | | "engines": { "node": ">=0.10.31" } 92 | | } 93 | 94 | p In the future, we hope to add more verbose version checking, to fully support the 95 | code package.json 96 | | spec. 97 | 98 | 99 | h3#env Environment variables 100 | 101 | h5.monospace PAASTOR_PORT 102 | p The environment variable  103 | code PAASTOR_PORT 104 | |  is the port your application should listen on. It is assigned automatically by Sheep 105 | | when you create an app. This is done to avoid port collisions. 106 | p The Sheep proxy will divert all HTTP and web socket requests on ports 80 and 443 (if SSL is setup), for 107 | | the 108 | code domains 109 | |  you specify, to  110 | code http://127.0.0.1:<PAASTOR_PORT> 111 | | . 112 | 113 | h5.monospace NODE_ENV 114 | p By default the NODE_ENV is 115 | code "production" 116 | | but this can be overriden by a custom environment variable. 117 | 118 | h5 Custom 119 | p You can set environment variables at the application level from the UI or the CLI. 120 | 121 | p To see environment variable changes reflected, 122 | strong restart the application 123 | | . 124 | p From the CLI, you will be prompted for the environment variable name and value. 125 | pre: code $ paastor setenv [server] [app] 126 | pre: code Environment variable name: <app env key>\n 127 | | Environment variable value: <new env value>\n 128 | 129 | br 130 | 131 | h2#troubleshooting Troubleshooting a dead Sheep or dead apps 132 | p Sometimes bad things happen and your app ...or a bug in Sheep... may cause the whole thing to die. If 133 | | that happens (sorry!) there are some steps you can take to fix stuff. 134 | 135 | h5 Check forever 136 | p Sheep should be kept alive by 137 | a(href="https://github.com/nodejitsu/forever") forever 138 | | . SSH into your server as root and run 139 | a(href="https://github.com/nodejitsu/forever") forever CLI commands. 140 | pre: code $ ssh -l root 3.3.3.3 141 | | 142 | | root@3.3.3.3's password: ********* 143 | | Welcome to Ubuntu 14.04 LTS . . . 144 | | 145 | | $ forever list 146 | | [ sheep should be listed here ] 147 | | 148 | | $ forever logs 0 149 | | [ logs will be printed if sheep is running under forever ] 150 | 151 | h5 Check the app log files 152 | p Normally the 153 | code pstr 154 | | CLI provides logs through the following commands: 155 | pre: code $ pstr logs [server] 156 | | $ pstr logs [server] [app] 157 | 158 | p If Sheep dies, you won't be able to get logs from 159 | code pstr 160 | | . 161 | p SSH into the server as root and check 162 | code /root/sheep_logs/ 163 | | . 164 | 165 | h5 Reboot 166 | p Rebooting the server is often the fastest way to fix things. 167 | p On reboot, 168 | strong Sheep will restart any apps 169 | | that were running when it died. 170 | 171 | h5 Contact support 172 | p If you have tried everything, contact hello@paastor.com for assistance. 173 | 174 | br 175 | -------------------------------------------------------------------------------- /paastor-server/views/pages/ssl.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Easy SSL setup for your Node.js apps"; 5 | 6 | block content 7 | .container 8 | 9 | h1 SSL on Paastor 10 | blockquote 11 | strong SSL is available on paid accounts only. 12 | br 13 | | You don't have to pay very much, but you have to be paying something! 14 | 15 | 16 | p Add SSL certs and keys in the Server Manager. 17 | p SSL certificates can be re-uploaded an unlimited number of times from the web UI - 18 | | in case it changes, or you make a mistake. 19 | 20 | h3 What happens on the server 21 | p Sheep contains a proxy and a router with support for SSL. 22 | p When you add SSL to an app, the proxy will use the certificates during the requests on behalf 23 | | of your app, then route the traffic to your app on 24 | code process.env.PAASTOR_PORT 25 | | . 26 | p This setup is similar to nginx or other proxy servers. 27 | br 28 | -------------------------------------------------------------------------------- /paastor-server/views/pages/usage.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "Usage guide: fast and easy deployment of Node.js apps"; 5 | 6 | block content 7 | .container 8 | h1 Usage 9 | h2 How to deploy a node app to your own infrastructure in 5 minutes using Paastor 10 | h4 Deploy to cloud servers, VPS, dedicated servers, and more. 11 | br 12 | img.img-responsive(src="/diagram.png") 13 | br 14 | h3 1. Sign up 15 | p 16 | strong Begin by creating an account 17 | | and verifying your email address. 18 | 19 | br 20 | h3 2. Obtain a server 21 | p The most common option is to purchase a VPS (virtual private server) plan from a hosting company. In many 22 | | cases you can run multiple Node.js apps for $2 - $10 per month on a VPS. 23 | p VPS hosting is very competitive and very cheap compared to cloud hosting. Examples of hosting companies are: Linode, Digital Ocean, Chicago VPS, and many more. 24 | a(href="http://serverbear.com" target="_blank") Server Bear 25 | |  and  26 | a(href="http://lowendbox.com" target="_blank") LowEndBox 27 | | are tools to help you compare VPS hosts. (Paastor is not affiliated with any of the services 28 | | mentioned.) 29 | p The only officially supported server OS on Paastor (for now) is 30 | strong Ubuntu 14.04. 31 | p Next, be sure to create a DNS "A" record with your DNS provider, and point to your server's IP address, for the domain you intend to serve. 32 | 33 | 34 | br 35 | h3 3. Add your server to Paastor 36 | p Log in to Paastor and press the 'New Server' button from the Server Manager screen. 37 | | Fill out all the fields. This will install the Sheep service on your server and 38 | | allow you to push apps to the server. 39 | 40 | br 41 | h3 4. Create an app on the server in Paastor 42 | p From the Paastor UI, add an app to your server. You must add an app from the UI before pushing code. 43 | p Your 44 | code package.json 45 | | must have the following fields (these are example values): 46 | 47 | pre: code { 48 | | // a single startup script 49 | | "main": "aStartupScript.js", 50 | | // list of domains for the Sheep proxy router 51 | | "domains": ["example.com", "www.example.com"], 52 | | "engines": { 53 | | // a single node version - no ranges 54 | | "node": "0.10.31" 55 | | } 56 | | } 57 | 58 | 59 | 60 | br 61 | h3 5. Install the 62 | code pstr 63 | | command line tool 64 | pre: code $ npm install -g paastor 65 | 66 | 67 | br 68 | h3 6. Log in on the CLI 69 | pre: code $ pstr login 70 | 71 | 72 | br 73 | h3 7. (optional) Install the right version of Node for your app 74 | p Use 75 | code pstr install-node [server] [version] 76 | | to add a version of Node to your server. 77 | pre: code $ pstr install-node myserver1 0.10.28 78 | p Depending on the version, it may be installed quickly, or may need to compile from source. 79 | 80 | 81 | br 82 | h3 8. Push your application 83 | p Use 84 | code pstr push [server] [app] 85 | | to push the app in the current directory to the specified server. 86 | 87 | pre: code $ pstr push myserver1 someapp 88 | pre: code push myserver1 someapp 89 | | Checking package.json 90 | | package.json exists 91 | | version ok 0.10.28 92 | | Domains look ok 93 | | Checking server... 94 | | Found myserver 95 | | Status ok 96 | | 0.10.31 installed 97 | | Creating package from current directory... 98 | | Package created. 10.46mb 99 | | Prepping package for sending... 100 | | Package is ready to send. 101 | | Uploading and installing... 102 | | Ok 103 | | Stopping app... 104 | | Stopped. 105 | | Starting app... 106 | | Started 107 | | Cleaning up package... 108 | | Package cleaned. 109 | | Push complete. 110 | 111 | br 112 | 113 | h3 9. (optional) Check the logs 114 | h5 Server logs 115 | pre: code $ pstr logs myserver1 116 | h5 Application logs 117 | pre: code $ pstr logs myserver1 someapp 118 | 119 | br 120 | h3 Help 121 | p All CLI commands can be seen by running 122 | code pstr --help 123 | | . 124 | 125 | br 126 | h3 Open source 127 | p It's on the roadmap to release many parts of Paastor under an open source license. 128 | p Until then, refer to the 129 | a(href="/pages/docs.html#system") documentation 130 | | about the files Paastor puts on your server. 131 | -------------------------------------------------------------------------------- /paastor-server/views/pages/vision.jade: -------------------------------------------------------------------------------- 1 | extends ../layout 2 | 3 | block append vars 4 | - title = "About Paastor: solving the Node.js production deployment problem"; 5 | - meta.keywords = "vps, " + meta.keywords 6 | 7 | block content 8 | .container 9 | h1 About Paastor 10 | 11 | h5: a(href="/pages/contact.html") Support / Contact Information 12 | h5: a(href="/pages/terms.html") Terms of Service and Acceptable Use 13 | 14 | br 15 | 16 | h2 The Paastor Vision 17 | br 18 | h2 Node.js is awesome, but there's a problem: 19 | h5 Setting up Node in production is a time suck. 20 | h5 PaaS services make it easy - but they're expensive and locked down, and that won't work 21 | | for everyone. 22 | 23 | br 24 | 25 | h2 Paastor solves the problem. 26 | 27 | h3 Virtual servers are super cheap. So with your virtual server, you can: 28 | 29 | h5 1. Provision a Node.js-capable production server in one step. 30 | h5 2. Deploy apps from the CLI in one step. 31 | h5 3. Keep apps up and restart them automatically when they die. 32 | h5 4. Use web sockets. 33 | h5 5. Host multiple Node apps, with multiple Node versions, on the same box. 34 | h5 6. Use your own SSL certificates. 35 | h5 7. Use your own domain. 36 | h5 8. Retain full control of your server. 37 | 38 | h3 with the added bonus of: 39 | h5 One-click Redis setup 40 | h5 One-click MongoDB setup 41 | 42 | -------------------------------------------------------------------------------- /paastor-server/views/parts/ssl.jade: -------------------------------------------------------------------------------- 1 | p To enable HTTPS, paste in the contents of the certification files. SSL data will only be 2 | | saved on your server - not on Paastor. 3 | p Depending on your setup, you will likely also use the SSL certificate in your application HTTP server. 4 | | Setting the information here allows the Sheep instance to proxy requests to your app. 5 | label Private key (mydomain.key) 6 | textarea.form-control(ng-disabled="saving" ng-model="app.key" rows="3" 7 | placeholder="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----") 8 | br 9 | label Key password 10 | span.help-block Only necessary if you used a password when creating the key. 11 | input.form-control(type="password" ng-disabled="saving" ng-model="app.passphrase" 12 | placeholder="********") 13 | br 14 | label Private cert (mydomain.crt) 15 | textarea.form-control(type="text" ng-disabled="saving" ng-model="app.cert" rows="3" 16 | placeholder="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----") 17 | br 18 | 19 | label Certificate Authority (CA) cert - optional (bundle.crt) 20 | span.help-block This may include multiple CA certificates. Paste them all here. 21 | textarea.form-control(type="text" ng-disabled="saving" ng-model="app.ca" rows="6" 22 | placeholder="-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----") -------------------------------------------------------------------------------- /paastor-server/views/reset.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1=title 5 | br 6 | if (message) 7 | h3= message 8 | .alert.alert-block.alert-info.center(ng-show="message") {{ message }} 9 | 10 | if (_id && conf) 11 | .row 12 | .col-sm-4 13 | input.form-control(type="password" placeholder="New password" ng-model="resetPass.password") 14 | br 15 | input.form-control(type="password" placeholder="Confirm password" ng-model="resetPass.passwordConf") 16 | input(type="hidden" ng-init="resetPass._id = '"+_id+"'" ng-model="resetPass._id") 17 | input(type="hidden" ng-init="resetPass.conf = '"+conf+"'" ng-model="resetPass.conf") 18 | br 19 | button.btn.btn-danger(ng-click="doPasswordReset()") Reset Password 20 | -------------------------------------------------------------------------------- /paastor-server/views/templates/404.jade: -------------------------------------------------------------------------------- 1 | h1 Paastor can't help you now 2 | br 3 | h6 The screen you're trying to reach was 4 | strong not found. 5 | br 6 | p Better turn back. 7 | -------------------------------------------------------------------------------- /paastor-server/views/templates/account-edit.jade: -------------------------------------------------------------------------------- 1 | h3 My Account 2 | br 3 | .row 4 | .col-sm-4.col-sm-offset-1 5 | h4 Email 6 | span.help-block {{ account.email }} 7 | br 8 | hr 9 | .alert.alert-info.center(ng-show="message") {{ message }} 10 | .row 11 | .col-sm-6.col-sm-offset-1 12 | h4 Credit card 13 | span.help-block Current: 14 | span(ng-show="!card.last4") none 15 | span(ng-show="card.last4") {{ card.type }} \#{{ card.last4 }} 16 | button.btn.btn-xs.btn-primary(ng-show="!changeCard" ng-click="changeCard = true") Update Card 17 | .well(ng-show="changeCard") 18 | h4 Update credit card 19 | br 20 | input.form-control(type="text" placeholder="Card number" ng-model="newCard.number") 21 | br 22 | input.form-control(type="text" placeholder="Cardholder name" ng-model="newCard.name") 23 | br 24 | input.form-control(type="text" placeholder="CVC security code" ng-model="newCard.cvc") 25 | br 26 | .form-inline 27 | .form-group.col-xs-6 28 | input.form-control( 29 | type="text" 30 | placeholder="Month" 31 | ng-model="newCard.exp_month" 32 | ) 33 | .form-group.col-xs-6 34 | input.form-control( 35 | type="text" 36 | placeholder="Year" 37 | ng-model="newCard.exp_year" 38 | ) 39 | br 40 | br 41 | br 42 | button.btn.btn-primary.btn-sm(ng-click="setCard()") Set as billing card 43 | .col-sm-3.col-sm-offset-1 44 | h4 Password 45 | input.form-control(type="password" placeholder="New password" ng-model="password") 46 | br 47 | input.form-control(type="password" placeholder="Confirm password" ng-model="passwordConf") 48 | br 49 | button.btn.btn-danger.btn-xs(ng-click="changePassword()") Change password 50 | -------------------------------------------------------------------------------- /paastor-server/views/templates/app-create.jade: -------------------------------------------------------------------------------- 1 | h5: a(ng-href="/#/vps/{{ app.vps }}" ng-show="!done && !saving") 2 | i.fa.fa-angle-left 3 | | {{ app.vps }} 4 | div(ng-show="!done && !saving") 5 | 6 | h1 Add an App 7 | 8 | .alert.alert-info(ng-show="message && !done") {{ message }} 9 | div(ng-show="!done && !saving") 10 | 11 | .row 12 | .col-sm-5 13 | h3 Required information 14 | br 15 | label Application name (_id) 16 | span.help-block Only letters, numbers, and dashes (-) allowed. 17 | input.form-control(type="text" ng-disabled="saving" ng-model="app._id" placeholder="my-app") 18 | 19 | br 20 | br 21 | label Application environment 22 | span.help-block Must be a JSON object. 23 | textarea.form-control.monospace(rows="4" ng-disabled="saving" ng-model="app.env" 24 | placeholder="{\n \"NODE_ENV\": \"production\"\n}" 25 | ) 26 | 27 | .col-sm-6.col-sm-offset-1 28 | h3 SSL options 29 | i.fa.pull-right(ng-class="{ 'fa-lock': showssl, 'fa-unlock': !showssl }") 30 | span(ng-show="account.limit_servers > 1") 31 | button.btn.btn-success.btn-xs(ng-click="showssl = true" ng-show="!showssl") Show 32 | button.btn.btn-info.btn-xs(ng-click="showssl = false" ng-show="showssl") Hide 33 | p(ng-show="account.limit_servers < 2") 34 | a(href="/#/manage-services") Get on a paid account to enable SSL. 35 | | Having a paid account will allow you to upload SSL certificates. 36 | 37 | div(ng-show="showssl") 38 | br 39 | include ../parts/ssl 40 | 41 | br 42 | br 43 | 44 | .row 45 | .col-xs-12.right 46 | button.btn.btn-primary.btn-lg(ng-click="save()" ng-disabled="saving") Create application 47 | span.help-block on server 48 | strong {{ app.vps }} 49 | 50 | 51 | br 52 | div(ng-show="saving") 53 | i.fa.fa-circle-o-notch.fa-spin.fa-4x 54 | br 55 | br 56 | 57 | div(ng-show="done") 58 | h1 Done 59 | 60 | p Apps must have a 61 | code package.json 62 | |  file with a main script, at least one domain specified, and a node version. 63 | pre: code { 64 | | // a single startup script 65 | | "main": "aStartupScript.js", 66 | | 67 | | // list of domains for the Sheep proxy router 68 | | "domains": ["example.com", "www.example.com"], 69 | | 70 | | "engines": { 71 | | // a single node version - no ranges 72 | | "node": "0.10.31" 73 | | } 74 | | } 75 | 76 | p To push code: 77 | pre(style="width: 300px"): code $ npm install -g paastor 78 | | $ pstr push [server] [app] 79 | br 80 | 81 | a.btn.btn-primary(ng-href="/#/vps/{{ app.vps }}") Ok 82 | br 83 | 84 | 85 | br 86 | br 87 | -------------------------------------------------------------------------------- /paastor-server/views/templates/app-ssl.jade: -------------------------------------------------------------------------------- 1 | h5: a(ng-href="/#/vps/{{ app.vps }}" ng-show="!done && !saving") 2 | i.fa.fa-angle-left 3 | | {{ app.vps }} 4 | div(ng-show="!done && !saving") 5 | 6 | h1 SSL for {{ app._id }} 7 | 8 | .alert.alert-info(ng-show="message && !done") {{ message }} 9 | div(ng-show="!done && !saving") 10 | 11 | p(ng-show="account.limit_servers < 2") 12 | a(href="/#/manage-services") Get on a paid account to enable SSL. 13 | | Having a paid account will allow you to upload SSL certificates. 14 | 15 | div(ng-show="account.limit_servers > 1") 16 | include ../parts/ssl 17 | 18 | br 19 | br 20 | 21 | .row 22 | .col-xs-12.right 23 | button.btn.btn-primary.btn-lg(ng-click="save()" ng-disabled="saving") Set SSL 24 | span.help-block on server 25 | strong {{ app.vps }} 26 | | for app 27 | strong {{ app._id }} 28 | 29 | 30 | br 31 | div(ng-show="saving") 32 | i.fa.fa-circle-o-notch.fa-spin.fa-4x 33 | br 34 | br 35 | 36 | div(ng-show="done") 37 | h1 Done 38 | 39 | .alert.alert-success 40 | i.fa.fa-info-circle 41 | |   The app must be restarted for changes to take effect. 42 | a.btn.btn-primary(ng-href="/#/vps/{{ app.vps }}") Ok 43 | br 44 | 45 | 46 | br 47 | br 48 | -------------------------------------------------------------------------------- /paastor-server/views/templates/home.jade: -------------------------------------------------------------------------------- 1 | .alert.alert-info.center(ng-show="message") {{ message }} 2 | 3 | .row 4 | 5 | .col-md-4 6 | div(ng-show="!account.email") 7 | h1 Paastor 8 | h3 Sign up 9 | input.form-control(type="text" placeholder="email" ng-model="signup.email") 10 | br 11 | input.form-control(type="password" placeholder="password" ng-model="signup.password") 12 | br 13 | p: a(href="/pages/terms.html" target="_blank") Terms 14 | button.btn.btn-success(ng-click="register()") Accept terms and create account 15 | br 16 | br 17 | .col-md-4 18 | h5.center Deploy Node.js apps to your own servers in one line, and keep them running if they crash. 19 | pre: code $ pstr push [server] [app] 20 | 21 | .panel(style='padding: 20px') 22 | p For a limited time, your 23 | h5.center: strong FIRST SERVER IS FREE 24 | p then just 25 | h2.center $0.99 / mo 26 | h5.center including SSL, MongoDB, and Redis 27 | .col-md-4(ng-show="!account.email") 28 | 29 | h4 Sign in 30 | input.form-control(type="text" placeholder="email" ng-model="signin.email" pa-enter="login()") 31 | br 32 | input.form-control(type="password" placeholder="password" ng-model="signin.password" pa-enter="login()") 33 | br 34 | button.btn.btn-primary(ng-click="login()") Sign in 35 | a.pull-right(href="javascript:void(0)" ng-click="forgot()") Forgot password 36 | 37 | br 38 | br 39 | .container.center 40 | h4 After deploying your apps from the CLI, manage them on the server dashboard. 41 | 42 | .row 43 | 44 | .col-md-4 45 | 46 | h6 List servers 47 | pre: code $ pstr servers 48 | 49 | h6 See apps and details 50 | pre: code $ pstr server my-server 51 | 52 | h6 Get server or app logs 53 | pre: code $ pstr logs my-server myapp 54 | 55 | h6 Stop an app 56 | pre: code $ pstr stop my-server myapp 57 | 58 | h6 Start an app 59 | pre: code $ pstr start my-server myapp 60 | 61 | h6 Use more than one version of Node.js 62 | pre: code $ pstr install-node my-server 0.10.31 63 | 64 | h6 Push code 65 | pre: code $ pstr push my-server myapp 66 | 67 | h6: a(href="/pages/docs.html") and more... 68 | .col-md-8 69 | br 70 | a(href="/dash.png" target="_blank"): img.img-responsive.img-thumbnail(src="/dash.png") 71 | 72 | br 73 | br 74 | .row 75 | .col-md-8 76 | a(href="/sman.png" target="_blank"): img.img-responsive.img-thumbnail(src="/sman.png") 77 | .col-md-4 78 | h3 See servers in one spot 79 | h5 All of your infrastructure united. 80 | h5 Restart apps, set environment variables, and install Mongo or Redis in a jiffy. 81 | 82 | br 83 | br 84 | h3 Features 85 | .row 86 | .col-md-4 87 | h5 88 | i.fa.fa-check 89 | | Easy and fast CLI deployments 90 | h5 91 | i.fa.fa-check 92 | | Web sockets 93 | h5 94 | i.fa.fa-check 95 | | Clustering 96 | h5 97 | i.fa.fa-check 98 | | Use any server host 99 | h5 100 | i.fa.fa-check 101 | | No lock-in 102 | h5 103 | i.fa.fa-check 104 | | Highly affordable 105 | .col-md-4 106 | h5 107 | i.fa.fa-check 108 | | Deploy MongoDB in one step 109 | h5 110 | i.fa.fa-check 111 | | Deploy Redis in one step 112 | h5 113 | i.fa.fa-check 114 | | Unlimited apps per server 115 | h5 116 | i.fa.fa-check 117 | | Multiple versions of Node.js per server 118 | h5 119 | i.fa.fa-check 120 | | Use your own SSL certificates 121 | .col-md-4 122 | h5 123 | i.fa.fa-check 124 | | Install SSL in one step 125 | h5 126 | i.fa.fa-check 127 | | No scripts to manage 128 | h5 129 | i.fa.fa-check 130 | | Easily track apps and servers on different infrastructures 131 | h5 132 | i.fa.fa-check 133 | | No learning curve 134 | h5 135 | i.fa.fa-check 136 | | Apps are restarted when they crash 137 | 138 | 139 | br -------------------------------------------------------------------------------- /paastor-server/views/templates/manage-services.jade: -------------------------------------------------------------------------------- 1 | .alert.alert-warning(ng-show="hasNoCard") 2 | h3.white 3 | i.fa.fa-credit-card 4 | |    5 | | It looks like you don't have a credit card on file. 6 | |    7 | a.btn.btn-warning.pull-right(href="/#/account") Add a card 8 | 9 | .row 10 | .col-sm-6 11 | h3 Upgrade Services 12 | p These are the subscriptions available for purchase. 13 | p Purchases are immediately charged to the credit card on file. Your service limit 14 | | will be raised instantly. 15 | 16 | table.table.table-responsive 17 | thead 18 | tr 19 | th Plan 20 | th Price 21 | th Qty 22 | th 23 | tbody 24 | tr(ng-repeat="plan in plans" ng-init="plan.quantity = 0") 25 | td: h6 {{ plan.name }} 26 | td: h6 {{ (plan.amount * Math.floor(plan.quantity)) / 100 | currency }} 27 | | per {{ plan.interval }} 28 | td.col-xs-5 29 | .input-group(ng-show="!hasNoCard") 30 | input.form-control.input-xs.right(type="number" min="0" step="1" ng-model="plan.quantity" placeholder="Qty") 31 | span.input-group-btn 32 | button.btn.btn-primary(ng-click="addService(plan)") Buy 33 | a.btn.btn-primary(href="/#/account" ng-show="hasNoCard") Add Card 34 | 35 | .alert.alert-info.center(ng-show="buyMsg") {{ buyMsg }} 36 | 37 | p.help-block More services coming soon. 38 | 39 | .col-sm-6 40 | .well 41 | h4 Current services 42 | p Your account has the following service limits: 43 | p 44 | img.img-1x(src="/favicon.png") 45 | |    46 | | {{ account.limit_servers }} {{ account.limit_servers === 1 ? " server" : " servers" }} 47 | |   (1 free) 48 | 49 | .well 50 | h4 Manage my subscriptions 51 | span.help-block(ng-show="!subscriptions.length") none 52 | table.table.table-responsive 53 | tbody 54 | tr(ng-repeat="sub in subscriptions" ng-init="showDowngrade = false; sub.down = 0") 55 | td {{ sub.quantity }} 56 | td {{ sub.plan.name }} 57 | td {{ sub.plan.amount * sub.quantity / 100 | currency }} per {{ sub.plan.interval }} 58 | td(ng-show="sub.quantity && !showDowngrade") 59 | button.btn.btn-warning.btn-xs(ng-click="showDowngrade = true") 60 | i.fa.fa-level-down 61 | td.col-xs-7(ng-show="sub.quantity && showDowngrade") 62 | | How many? 63 | .input-group 64 | input.form-control.input-xs(type="number" min="0" max="{{ sub.quantity }}" step="1" ng-model="sub.down" placeholder="Qty") 65 | span.input-group-btn 66 | button.btn.btn-danger(ng-click="downgrade(sub)") Remove 67 | br 68 | button.btn.btn-default.btn-xs(ng-click="showDowngrade = false; sub.down = 0;") Cancel 69 | 70 | .alert.alert-block.alert-info.center(ng-show="subMsg") {{ subMsg }} 71 | 72 | p.help-block 73 | strong Warning 74 | br 75 | | Service downgrades will be applied immediately and any paid credits will be lost. 76 | -------------------------------------------------------------------------------- /paastor-server/views/templates/mongo.jade: -------------------------------------------------------------------------------- 1 | h4(ng-show="!loading"): a(ng-href="/#/list") 2 | i.fa.fa-angle-left 3 | |  servers 4 | 5 | h1(ng-show="loading && message") {{ message }} 6 | 7 | span.help-block(ng-show="!vps || loading"): i.fa.fa-circle-o-notch.fa-spin.fa-4x 8 | 9 | 10 | div(ng-show="vps && !vps.mongo && !loading && !removed && !installed") 11 | h1 Install MongoDB 12 | span.help-block version 2.4 13 | h5 (experimental) 14 | .alert.alert-info.center(ng-show="message") {{ message }} 15 | 16 | br 17 | .row 18 | 19 | .col-sm-6 20 | 21 | label New MongoDB username 22 | 23 | input.form-control(type="text" ng-model="mongo.username" placeholder="admin1234") 24 | span.help-block Username must be alphanumeric only. 25 | 26 | br 27 | 28 | label New MongoDB password 29 | input.form-control(type="password" ng-model="mongo.password" placeholder="**********") 30 | span.help-block Password should be long and alphanumeric only. 31 | span.help-block: strong For your protection, Paastor does not store your MongoDB credentials. 32 | 33 | .col-sm-6 34 | label Port 35 | span.help-block By default, MongoDB runs on port 36 | strong 27017 37 | | . It is recommended to change 38 | | the default port if you plan to expose MongoDB 39 | | to remote connections. 40 | .input-group 41 | input.form-control(type="number" step="1" ng-model="mongo.port" placeholder="27017") 42 | .input-group-btn 43 | button.btn.btn-default(ng-click="portgen()") Port 44 | i.fa.fa-refresh 45 | br 46 | .row 47 | .col-sm-6 48 | 49 | label Access 50 | span.help-block MongoDB can be installed just for local apps on the server, 51 | | or it can be made available to apps on other servers, too. 52 | .btn-group 53 | button.btn.btn-sm(ng-click="mongo.localOnly = true" 54 | ng-class="{ 'active btn-success': mongo.localOnly, 'btn-default': !mongo.localOnly }") 55 | | Local access only 56 | button.btn.btn-sm(ng-click="mongo.localOnly = false" 57 | ng-class="{ 'active btn-warning': !mongo.localOnly && !mongos.noPassword, 'btn-default': mongo.localOnly, 'active btn-danger': mongo.noPassword && !mongo.localOnly }") 58 | | Enable remote access 59 | 60 | .col-sm-6 61 | label Root Password 62 | span.help-block For installation. This will not be saved by Paastor. 63 | input.form-control(type="password" ng-model="mongo.rootPassword" placeholder="**********") 64 | 65 | br 66 | .animated.pulse.alert.alert-danger(ng-show="!mongo.localOnly && !mongo.password && !mongo.username") 67 | | You have selected to have a remotely available MongoDB instance without a 68 | | username and password. 69 | span(ng-show="mongo.port === 27017") It is also on the default port. 70 | 71 | 72 | br 73 | p: strong Take note of the username, password and port. 74 | | Paastor does not store these, for security reasons. 75 | 76 | div.pull-right.right 77 | button.btn.btn-primary(ng-click="install()") Install and reboot 78 | span.help-block on server 79 | strong {{ vps._id }} 80 | 81 | br 82 | div(ng-show="installed") 83 | h1 MongoDB was installed 84 | .alert.alert-info.center(ng-show="message") {{ message }} 85 | 86 | 87 | br 88 | 89 | 90 | p(ng-show="!mongo.localOnly") 91 | i.fa.fa-warning 92 | |    93 | strong You must 94 | a(href="/pages/docs.html#mongo") authenticate using the admin database 95 | | or the credentials you just setup 96 | strong will not work 97 | | . 98 | 99 | p MongoDB databases are created on-the-fly as you connect. So as long as you 100 | a(href="/pages/docs.html#mongo") authenticate correctly 101 | | you are ready to start using the database. 102 | 103 | 104 | a.btn.btn-primary(ng-href="/#/vps/{{ vps._id }}") Ok 105 | 106 | 107 | div(ng-show="vps && vps.mongo && !loading && !installed") 108 | h1 Remove MongoDB 109 | .alert.alert-info.center(ng-show="message") {{ message }} 110 | p: strong All settings and data will be deleted. 111 | br 112 | .row 113 | .col-sm-4 114 | input.form-control(type="password" ng-model="mongo.rootPassword" placeholder="Root password") 115 | br 116 | button.btn.btn-danger(ng-click="uninstall()") Uninstall and delete data 117 | span.help-block from server 118 | strong {{ vps._id }} 119 | 120 | 121 | div(ng-show="removed") 122 | .alert.alert-info.center(ng-show="message") {{ message }} 123 | h1 MongoDB was removed 124 | p MongoDB has been successfully removed from the server. 125 | br 126 | a.btn.btn-primary(ng-href="/#/vps/{{ vps._id }}") Ok 127 | 128 | -------------------------------------------------------------------------------- /paastor-server/views/templates/redis.jade: -------------------------------------------------------------------------------- 1 | h4(ng-show="!loading"): a(ng-href="/#/list") 2 | i.fa.fa-angle-left 3 | |  servers 4 | 5 | h1(ng-show="loading && message") {{ message }} 6 | 7 | span.help-block(ng-show="!vps || loading"): i.fa.fa-circle-o-notch.fa-spin.fa-4x 8 | 9 | 10 | div(ng-show="vps && !vps.redis && !loading && !removed && !installed") 11 | h1 Install Redis 12 | h5 (experimental) 13 | .alert.alert-info.center(ng-show="message") {{ message }} 14 | 15 | br 16 | .row 17 | 18 | .col-sm-6 19 | label Access 20 | span.help-block Redis can be installed just for local apps on the server, 21 | | or it can be made available to apps on other servers, too. 22 | .btn-group 23 | button.btn.btn-sm(ng-click="redis.localOnly = true" 24 | ng-class="{ 'active btn-success': redis.localOnly, 'btn-default': !redis.localOnly }") 25 | | Local access only 26 | button.btn.btn-sm(ng-click="redis.localOnly = false" 27 | ng-class="{ 'active btn-warning': !redis.localOnly && !redis.noPassword, 'btn-default': redis.localOnly, 'active btn-danger': redis.noPassword && !redis.localOnly }") 28 | | Enable remote access 29 | .col-sm-6 30 | label Port 31 | span.help-block By default, Redis runs on port 32 | strong 6379 33 | | . It is recommended to change 34 | | the default port if you plan to expose Redis 35 | | to remote connections. 36 | .input-group 37 | input.form-control(type="number" step="1" ng-model="redis.port" placeholder="6379") 38 | .input-group-btn 39 | button.btn.btn-default(ng-click="portgen()") Port 40 | i.fa.fa-refresh 41 | br 42 | .row 43 | .col-sm-6 44 | label Redis Password 45 | span.help-block By default, Redis has no password because 46 | | it is intended for use in trusted environments. 47 | | When setting a password, you may use a random system-generated 48 | | password (recommended), or set your own custom password. 49 | strong Paastor will not save the password 50 | | . 51 | 52 | .btn-group 53 | 54 | button.btn.btn-sm(ng-click="redis.noPassword = true; redis.generatePassword = false; redis.password = '';" 55 | ng-class="{ 'active btn-warning': redis.noPassword && redis.localOnly, 'btn-default': !redis.noPassword, 'active btn-danger': redis.noPassword && !redis.localOnly }") 56 | | No password 57 | 58 | button.btn.btn-sm(ng-click="redis.generatePassword = true; redis.noPassword = false; redis.password = '';" 59 | ng-class="{ 'active btn-success': redis.generatePassword && !redis.noPassword, 'btn-default': !redis.generatePassword || redis.noPassword }") 60 | | System generated 61 | 62 | button.btn.btn-sm(ng-click="redis.generatePassword = false; redis.noPassword = false; redis.password = '';" 63 | ng-class="{ 'active btn-warning': !redis.generatePassword && !redis.noPassword, 'btn-default': redis.generatePassword || redis.noPassword }") 64 | | Custom 65 | span.help-block(ng-show="!redis.noPassword && !redis.generatePassword") 66 | | Passwords may be alphanumeric and include underscore or dash. 67 | input.form-control(type="text" ng-model="redis.password" 68 | maxlength="512" placeholder="Long and secure Redis password" 69 | ng-show="!redis.noPassword && !redis.generatePassword") 70 | .col-sm-6 71 | label Root Password 72 | span.help-block For installation. This will not be saved by Paastor. 73 | input.form-control(type="password" ng-model="redis.rootPassword" placeholder="**********") 74 | 75 | br 76 | 77 | .alert.alert-danger.animated.pulse( 78 | ng-show="redis.noPassword && !redis.localOnly" 79 | ) 80 | i.fa.fa-warning 81 | |   You are about to install a remotely accessible Redis instance 82 | | with no password. 83 | span(ng-show="redis.port == 6379") It is also on the default port. 84 | | Is that correct? 85 | div.pull-right.right 86 | button.btn.btn-primary(ng-click="install()") Install and reboot 87 | span.help-block on server 88 | strong {{ vps._id }} 89 | 90 | div(ng-show="installed") 91 | h1 Redis was installed 92 | .alert.alert-info.center(ng-show="message") {{ message }} 93 | 94 | p Take note of the password and port. 95 | strong Paastor does not store these, for security reasons. 96 | 97 | p If you forget the password or port, you can log into the server and check the 98 | code /etc/redis/redis.conf 99 | | file. 100 | br 101 | 102 | h6.help-block port 103 | h5 {{ redis.port }} 104 | br 105 | h6.help-block password 106 | .row(ng-show="redis.password"): .col-md-4 107 | textarea.form-control {{ redis.password }} 108 | h5(ng-show="!redis.password") (no password) 109 | 110 | br 111 | a.btn.btn-primary(ng-href="/#/vps/{{ vps._id }}") Ok 112 | 113 | 114 | div(ng-show="vps && vps.redis && !loading && !installed") 115 | h1 Remove Redis 116 | .alert.alert-info.center(ng-show="message") {{ message }} 117 | p: strong All settings and data will be deleted. 118 | br 119 | .row 120 | .col-sm-4 121 | input.form-control(type="password" ng-model="redis.rootPassword" placeholder="Root password") 122 | br 123 | button.btn.btn-danger(ng-click="uninstall()") Uninstall and delete data 124 | span.help-block from server 125 | strong {{ vps._id }} 126 | 127 | 128 | div(ng-show="removed") 129 | .alert.alert-info.center(ng-show="message") {{ message }} 130 | h1 Redis was removed 131 | p Redis has been successfully removed from the server. 132 | br 133 | a.btn.btn-primary(ng-href="/#/vps/{{ vps._id }}") Ok 134 | 135 | -------------------------------------------------------------------------------- /paastor-server/views/templates/vps-create.jade: -------------------------------------------------------------------------------- 1 | div(ng-show="!done && !saving") 2 | h1 Add a server 3 | br 4 | p This should be a fresh 5 | strong Ubuntu 14.04 server 6 | | . 7 | p Expect it to be modified and to be used soley as a 8 | a(href="/pages/sheep-system.html" target="_blank") Sheep instance. 9 | br 10 | .row 11 | .col-sm-6 12 | label Server info 13 | span.help-block Only letters, numbers, and dashes (-) allowed for the identifier name. 14 | input.form-control(type="text" ng-model="vps._id" placeholder="Unique server name (_id)") 15 | input.form-control(type="text" ng-model="vps.infrastructure" placeholder="Hosting infrastructure name") 16 | 17 | .col-sm-6 18 | label Security 19 | span.help-block   20 | input.form-control(type="text" ng-model="vps.ip" placeholder="IP address") 21 | input.form-control(type="password" ng-model="vps.password" placeholder="root password (will not be saved)") 22 | span.help-block: a(href="/pages/faq.html#save-root-password" target="_blank") 23 | i.fa.fa-info-circle 24 | | Why do you need my root password? 25 | 26 | br 27 | .row 28 | .col-sm-6 29 | a(href="/#/list" tabindex="-1") Cancel 30 | .col-sm-6.right 31 | button.btn.btn-primary(ng-click="save()") Create 32 | 33 | br 34 | 35 | div(ng-show="saving") 36 | i.fa.fa-cog.fa-spin.fa-4x 37 | br 38 | br 39 | 40 | div(ng-show="done") 41 | h1 Done 42 | p: a.btn.btn-primary(ng-href="/#/vps/{{ vps._id }}") View server 43 | 44 | .alert.alert-info(ng-show="message") {{ message }} 45 | 46 | pre#server-logs(ng-show="logs"): code {{ logs }} 47 | -------------------------------------------------------------------------------- /paastor-server/views/templates/vps-list.jade: -------------------------------------------------------------------------------- 1 | .alert.alert-info.center(ng-show="message") {{ message }} 2 | 3 | .btn-group.pull-right 4 | a.btn.btn-xs.btn-default(href="/#/account") My Account 5 | a.btn.btn-xs.btn-default(href="/#/manage-services") My Subscriptions 6 | 7 | br.visible-xs 8 | 9 | h3 Paastor Server Manager 10 | 11 | a.btn.btn-primary.btn-sm(href="/#/vps" 12 | ng-show="vpses && vpses.length < account.limit_servers") New server 13 | a.btn.btn-primary.btn-sm(href="/#/manage-services" 14 | ng-show="vpses && vpses.length >= account.limit_servers") Upgrade plan to add servers 15 | br 16 | span.help-block(ng-show="!vpses"): i.fa.fa-5x.fa-circle-o-notch.fa-spin 17 | br 18 | 19 | table.table.table-striped.table-hover(ng-show="vpses") 20 | thead: tr 21 | th Server 22 | th Infrastructure 23 | th IP 24 | th Redis 25 | th MongoDB 26 | tbody 27 | tr.clickable(ng-repeat="vps in vpses" ng-click="$location.path('/vps/' + vps._id)") 28 | td: a(ng-href="/#/vps/{{ vps._id }}") {{ vps._id }} 29 | td {{ vps.infrastructure }} 30 | td {{ vps.ip }} 31 | 32 | td: a.btn.btn-default.btn-sm(ng-href="/#/vps/{{ vps._id }}/redis") 33 | i.fa.fa-check-square-o(ng-if="vps.redis") 34 | i.fa.fa-square-o(ng-if="!vps.redis") 35 | 36 | td: a.btn.btn-default.btn-sm(ng-href="/#/vps/{{ vps._id }}/mongo") 37 | i.fa.fa-check-square-o(ng-if="vps.mongo") 38 | i.fa.fa-square-o(ng-if="!vps.mongo") 39 | 40 | span.help-block.center(ng-show="!vpses.length") 41 | em You have not added any servers yet. 42 | -------------------------------------------------------------------------------- /paastor-sheep/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | system.json 3 | *.log 4 | -------------------------------------------------------------------------------- /paastor-sheep/lib/hash.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var crypto = require('crypto'); 3 | exports = module.exports = function (pass) { 4 | return crypto.createHash('sha256').update(pass).digest('base64'); 5 | }; 6 | -------------------------------------------------------------------------------- /paastor-sheep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sheep", 3 | "version": "0.3.47", 4 | "private": true, 5 | "scripts": { 6 | "start": "DEBUG=sheep:proxy,sheep:request,sheep:api,sheep:http node proxy.js" 7 | }, 8 | "dependencies": { 9 | "async": "^0.9.0", 10 | "body-parser": "~1.0.0", 11 | "connect": "^3.2.0", 12 | "debug": "~0.7.4", 13 | "forever-monitor": "^1.3.0", 14 | "http-proxy": "^1.2.0", 15 | "nodejs-disks": "^0.2.1", 16 | "pem": "^1.4.1", 17 | "rimraf": "^2.2.8", 18 | "semver": "^3.0.1", 19 | "stripcolorcodes": "^0.1.0", 20 | "tarball-extract": "0.0.3", 21 | "urlrouter": "^0.5.4" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /paastor-sheep/scripts/sheep: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | @reboot root sh /root/start.sh >> cron.log 2>&1 4 | -------------------------------------------------------------------------------- /paastor-sheep/scripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ $(ps aux | grep $USER | grep node | grep -v grep | wc -l | tr -s "\n") -eq 0 ] 4 | then 5 | echo "$(date) Forever not running, will try to start the app." 6 | NODE_ENV=production DEBUG=sheep:proxy,sheep:request,sheep:api,sheep:http /usr/local/nvm/v0.10.31/bin/node /usr/local/bin/forever -l /root/sheep.log -o sheep-out.log -e sheep-err.log -a -m 10000 --plain start /root/sheep/proxy.js 7 | else 8 | echo "$(date) Node or Forever is running, no need to start." 9 | fi 10 | -------------------------------------------------------------------------------- /pack: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | # 4 | 5 | echo 'Cleaning build dir...' 6 | rm -R build/tmp/ 7 | echo 'Done pre-cleaning' 8 | echo 'Making output folders...' 9 | mkdir build/ 10 | mkdir build/tmp/ 11 | echo 'Done making output folders' 12 | echo 'Versioning sheep...' 13 | cd sheep/ && SHEEP_VER=$(npm version patch) 14 | git push origin HEAD 15 | echo $SHEEP_VER 16 | cd ../ 17 | echo 'Done versioning sheep' 18 | echo 'Copying app...' 19 | cp -R sheep/ build/tmp/ 20 | echo 'Done copying app' 21 | echo 'Uglifying...' 22 | ./paastor/node_modules/.bin/uglifyjs -mt -o build/tmp/api.js -v build/tmp/api.js 23 | ./paastor/node_modules/.bin/uglifyjs -mt -o build/tmp/proxy.js -v build/tmp/proxy.js 24 | echo 'Done uglifying' 25 | echo 'Creating archive...' 26 | currentSheep="./build/tmp/sheep-$SHEEP_VER.zip" 27 | latestSheep="./build/tmp/sheep.zip" 28 | 29 | zip -r -q $latestSheep ./build/tmp/ 30 | cp $latestSheep $currentSheep 31 | echo 'Done archiving' 32 | 33 | echo 'Success' 34 | --------------------------------------------------------------------------------