Installations
npm install ssh-deploy-release
Developer Guide
Typescript
No
Module System
CommonJS
Node Version
18.2.0
NPM Version
8.9.0
Score
64.6
Supply Chain
93.9
Quality
72.3
Maintenance
100
Vulnerability
95.8
License
Releases
Contributors
Unable to fetch Contributors
Languages
JavaScript (99.99%)
HTML (0.01%)
Developer
Download Statistics
Total Downloads
109,242
Last Day
103
Last Week
321
Last Month
1,907
Last Year
19,780
GitHub Statistics
36 Stars
95 Commits
10 Forks
7 Watching
5 Branches
8 Contributors
Bundle Size
1.04 MB
Minified
289.45 kB
Minified + Gzipped
Package Meta Information
Latest Version
4.0.1
Package Id
ssh-deploy-release@4.0.1
Unpacked Size
54.21 kB
Size
14.33 kB
File Count
11
NPM Version
8.9.0
Node Version
18.2.0
Total Downloads
Cumulative downloads
Total Downloads
109,242
Last day
33.8%
103
Compared to previous day
Last week
-40.9%
321
Compared to previous week
Last month
9.9%
1,907
Compared to previous month
Last year
20.2%
19,780
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
ssh-deploy-release
Deploy releases over SSH with rsync, archive ZIP / TAR, symlinks, SCP ...
Example :
/deployPath
|
├── www --> symlink to ./releases/<currentRelease>
|
├── releases
| ├── 2017-02-08-17-14-21-867-UTC
| ├── ...
| └── 2017-02-09-18-01-10-765-UTC
| ├── ...
| └── logs --> symlink to shared/logs
|
├── synchronized --> folder synchronized with rsync
|
└── shared
└── logs
Installation
npm install ssh-deploy-release
Usage
Deploy release
1const Application = require('ssh-deploy-release'); 2 3const options = { 4 localPath: 'src', 5 host: 'my.server.com', 6 username: 'username', 7 password: 'password', 8 deployPath: '/var/www/vhost/path/to/project' 9}; 10 11const deployer = new Application(options); 12deployer.deployRelease(() => { 13 console.log('Ok !') 14});
Remove release
1const Application = require('ssh-deploy-release'); 2 3const options = { 4 localPath: 'src', 5 host: 'my.server.com', 6 username: 'username', 7 password: 'password', 8 deployPath: '/var/www/vhost/path/to/project', 9 allowRemove: true 10}; 11 12const deployer = new Application(options); 13deployer.removeRelease(() => { 14 console.log('Ok !') 15});
Rollback to previous release
1const Application = require('ssh-deploy-release'); 2 3const options = { 4 localPath: 'src', 5 host: 'my.server.com', 6 username: 'username', 7 password: 'password', 8 deployPath: '/var/www/vhost/path/to/project' 9}; 10 11const deployer = new Application(options); 12deployer.rollbackToPreviousRelease(() => { 13 console.log('Ok !') 14});
The previous release will be renamed before updating the symlink of the current version, for example
2019-01-09-10-53-35-265-UTC
will become
2019-01-09-13-46-45-457-UTC_rollback-to_2019-01-09-10-53-35-265-UTC
.
If rollbackToPreviousRelease
is called several times, the current version
will switch between the last two releases.
current date + "_rollbackTo_"
will be prepended to the release name on each call of
rollbackToPreviousRelease
so be careful not to exceed the size limit of the folder name.
Use with Grunt
Platform support
You can use this to deploy from any platform supporting Node >= 8 to Linux servers (most UNIX systems should work as well but this hasn't been tested).
Due to how we implemented the deployment process on the remote environment (using shell command execution), supporting Windows would required a lot of specific code, which would make this package harder to maintain. We decided to focus on supporting Linux as its the platform most widely used by hosting providers.
Options
ssh-deploy-release uses ssh2 to handle SSH connections.
The options
object is forwarded to ssh2
methods,
which means you can set all ssh2
options:
options.debug
If true
, will display all commands.
Default : false
options.port
Port used to connect to the remote server.
Default : 22
options.host
Remote server hostname.
options.username
Username used to connect to the remote server.
options.password
Password used to connect to the remote server.
Default: null
options.privateKeyFile
Default: null
options.passphrase
For an encrypted private key, this is the passphrase used to decrypt it.
Default: null
options.agent
To connect using the machine's ssh-agent. The value must be the path to the ssh-agent socket (usually available in the
SSH_AUTH_SOCK
environment variable).
options.mode
archive
: Deploy an archive and decompress it on the remote server.
synchronize
: Use rsync. Files are synchronized in the options.synchronized
folder on the remote server.
Default : archive
options.archiveType
zip
: Use zip compression (unzip
command on remote)
tar
: Use tar gz compression (tar
command on remote)
Default : tar
options.archiveName
Name of the archive.
Default : release.tar.gz
options.deleteLocalArchiveAfterDeployment
Delete the local archive after the deployment.
Default : true
options.readyTimeout
SCP connection timeout duration.
Default : 20000
options.onKeyboardInteractive
Callback passed to ssh2
client event
keyboard-interactive
.
Type: function (name, descr, lang, prompts, finish)
Path
options.currentReleaseLink
Name of the current release symbolic link. Relative to deployPath
.
Defaut : www
options.sharedFolder
Name of the folder containing shared folders. Relative to deployPath
.
Default : shared
options.releasesFolder
Name of the folder containing releases. Relative to deployPath
.
Default : releases
options.localPath
Name of the local folder to deploy.
Default : www
⚠ ️In case you need to deploy your whole project directory, do NOT set localPath
to an empty string, null
or .
. Use process.cwd()
to have node generate an
absolute path. In addition to this, if you use the archive mode,
don't forget to exclude the generated archive
(you can define its name using options.archiveName).
Example:
1const Application = require('ssh-deploy-release'); 2const process = require('process'); 3 4const deployer = new Application({ 5 localPath: process.cwd(), 6 exclude: ['release.tar.gz'], 7 archiveName: 'release.tar.gz', 8 host: 'my.server.com', 9 username: 'username', 10 password: 'password', 11 deployPath: '/var/www/vhost/path/to/project', 12});
options.deployPath
Absolute path on the remote server where releases will be deployed. Do not specify currentReleaseLink (or www folder) in this path.
options.synchronizedFolder
Name of the remote folder where rsync synchronize release.
Used when mode
is 'synchronize'.
Default : www
options.rsyncOptions
Additional options for rsync process.
Default : ''
1rsyncOptions : '--exclude-from="exclude.txt" --delete-excluded'
options.compression
Enable the rsync --compression flag. This can be set to a boolean or an integer to explicitly set the compression level (--compress-level=NUM).
Default : true
Releases
options.releasesToKeep
Number of releases to keep on the remote server.
Default : 3
options.tag
Name of the release. Must be different for each release.
Default : Use current timestamp.
options.exclude
List of paths to not deploy.
Paths must be relative to localPath
.
The format slightly differ depending on the mode
:
- glob format for
mode: 'archive'
In order to exclude a folder, you have to explicitly ignore all its descending files using**
.
For example:exclude: ['my-folder/**']
Read glob documentation for more information.
- rsync exclude pattern format for
mode: 'synchronize'
In order to exclude a folder, you simply have to list it, all of its descendants will be excluded as well.
For example:exclude: ['my-folder']
For maximum portability, it's strongly advised to use both syntaxes when excluding folders.
For example: exclude: ['my-folder/**', 'my-folder']
Default : []
options.share
List of folders to "share" between releases. A symlink will be created for each item.
Item can be either a string or an object (to specify the mode to set to the symlink target).
1share: { 2 'images': 'assets/images', 3 'upload': { 4 symlink: 'app/upload', 5 mode: '777' // Will chmod 777 shared/upload 6 } 7}
Keys = Folder to share (relative to sharedFolder
)
Values = Symlink path (relative to release folder)
Default : {}
options.create
List of folders to create on the remote server.
Default : []
options.makeWritable
List of files to make writable on the remote server. (chmod ugo+w)
Default : []
options.makeExecutable
List of files to make executable on the remote server. (chmod ugo+x)
Default : []
options.allowRemove
If true, the remote release folder can be deleted with removeRelease
method.
Default: false
Callbacks
context object
The following object is passed to onXXX
callbacks :
1{ 2 // Loaded configuration 3 options: { }, 4 5 // Release 6 release: { 7 // Current release name 8 tag: '2017-01-25-08-40-15-138-UTC', 9 10 // Current release path on the remote server 11 path: '/opt/.../releases/2017-01-25-08-40-15-138-UTC', 12 }, 13 14 // Logger methods 15 logger: { 16 // Log fatal error and stop process 17 fatal: (message) => {}, 18 19 // Log 'subhead' message 20 subhead: (message) => {}, 21 22 // Log 'ok' message 23 ok: (message) => {}, 24 25 // Log 'error' message and continue process 26 error: (message) => {}, 27 28 // Log message, only if options.debug is true 29 debug: (message) => {}, 30 31 // Log message 32 log: (message) => {}, 33 34 // Start a spinner and display message 35 // return a stop() 36 startSpinner: (message) => { return {stop: () => {}}}, 37 }, 38 39 // Remote server methods 40 remote: { 41 // Excute command on the remote server 42 exec: (command, done, showLog) => {}, 43 44 // Excute multiple commands (array) on the remote server 45 execMultiple: (commands, done, showLog) => {}, 46 47 /* 48 * Upload local src file to target on the remote server. 49 * @param {string} src The path to the file to upload. 50 * May be either absolute or relative to the current working directory. 51 * @param {string} target The path of the uploaded file on the remote server. 52 * Must include the filename. The full directory hierarchy to the target must already exist. 53 * May be either absolute or relative to the remote user home directory. 54 * We strongly encourage you to use `options.deployPath` in your target path to produce an absolute path. 55 */ 56 upload: (src, target, done) => {}, 57 58 // Create a symbolic link on the remote server 59 createSymboliclink: (target, link, done) => {}, 60 61 // Chmod path on the remote server 62 chmod: (path, mode, done) => {}, 63 64 // Create folder on the remote server 65 createFolder: (path, done) => {}, 66 } 67}
Examples
onBeforeDeploy, onBeforeLink, onAfterDeploy, onBeforeRollback, onAfterRollback options.
Single command executed on remote
1onAfterDeploy: 'apachectl graceful'
Or with a function :
1onBeforeLink: context => `chgrp -R www ${context.release.path}`
List of commands executed on remote
1onAfterDeploy: [ 2 'do something on the remote server', 3 'and another thing' 4]
Or with a function :
1onBeforeLink: (context) => { 2 context.logger.subhead('Fine tuning permissions on newly deployed release'); 3 return [ 4 `chgrp -R www ${context.release.path}`, 5 `chmod g+w ${context.release.path}/some/path/that/needs/to/be/writable/by/www/group`, 6 ]; 7}
Custom callback
1onAfterDeploy: context => { 2 return Promise((resolve, reject) => { 3 setTimeout(function () { 4 // Do something 5 resolve(); 6 }, 5000); 7 }); 8}
options.onBeforeConnect
Executed before connecting to the SSH server to let you initiate a custom
connection. It must return a ssh2 Client instance, and call onReady
when that
connection is ready.
Type: function(context, onReady, onError, onClose): Client
Example: SSH jumps (connecting to your deployment server through a bastion)
1onBeforeConnect: (context, onReady, onError, onClose) => { 2 const bastion = new Client(); 3 const connection = new Client(); 4 5 bastion.on('error', onError); 6 bastion.on('close', onClose); 7 bastion.on('ready', () => { 8 bastion.forwardOut( 9 '127.0.0.1', 10 12345, 11 'www.example.com', 12 22, 13 (err, stream) => { 14 if (err) { 15 context.logger.fatal(`Error connection to the bastion: ${err}`); 16 bastion.end(); 17 onClose(); 18 return; 19 } 20 21 connection.connect({ 22 sock: stream, 23 user: 'www-user', 24 password: 'www-password', 25 }); 26 } 27 ); 28 }); 29 30 connection.on('error', (err) => { 31 context.logger.error(err); 32 bastion.end(); 33 }); 34 connection.on('close', () => { 35 bastion.end(); 36 }); 37 connection.on('ready', onReady); 38 39 bastion.connect({ 40 host: 'bastion.example.com', 41 user: 'bastion-user', 42 password: 'bastion-password', 43 }); 44 45 return connection; 46}
options.onBeforeDeploy
Executed before deployment.
Type: string | string[] | function(context, done): Promise | undefined
options.onBeforeLink
Executed before symlink creation.
Type: string | string[] | function(context, done): Promise | undefined
options.onAfterDeploy
Executed after deployment.
Type: string | string[] | function(context, done): Promise | undefined
options.onBeforeRollback
Executed before rollback to previous release.
Type: string | string[] | function(context, done): Promise | undefined
options.onAfterRollback
Executed after rollback to previous release.
Type: string | string[] | function(context, done): Promise | undefined
Known issues
Command not found or not executed
A command on a callback method is not executed or not found.
Try to add set -i && source ~/.bashrc &&
before your commmand :
onAfterDeploy:[
'set -i && source ~/.bashrc && my command'
]
See this issue : https://github.com/mscdex/ssh2/issues/77
Contributing
1# Build (with Babel) 2npm run build 3 4# Build + watch (with Babel) 5npm run build -- --watch 6 7# Launch tests (Mocha + SinonJS) 8npm test 9 10# Launch tests + watch (Mocha + SinonJS) 11npm test -- --watch
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE-MIT:0
- Info: FSF or OSI recognized license: MIT License: LICENSE-MIT:0
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 1/24 approved changesets -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 8 are checked with a SAST tool
Reason
14 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c
- Warn: Project is vulnerable to: GHSA-2j2x-2gpw-g8fm
- Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-wc69-rhjr-hc9g
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
Score
1.7
/10
Last Scanned on 2025-01-27
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More