A robust GitHub Action for uploading a local directory to a remote server via SSH2 SFTP protocol. Built with TypeScript and comprehensive error handling.
- π TypeScript - Type-safe with comprehensive error handling
- π Multiple Auth Methods - Password, private key, or SSH agent authentication
- π Directory Upload - Upload entire directories with progress tracking
- πΎ Backup Support - Optional remote directory backup before upload
- π Retry Logic - Configurable connection retries with exponential backoff
- π Detailed Outputs - Track uploaded files count and operation status
- β‘ Concurrent Operations - Configurable promise limit for optimal performance
- π‘οΈ Security First - No secrets logged, secure connection handling
name: Deploy to Server
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Upload to Server
uses: 2ue/ssh2-to-remote-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
password: ${{ secrets.SERVER_PASSWORD }}
local_dir: './dist'
remote_base_dir: '/var/www/html'
- name: Upload with Backup
uses: 2ue/ssh2-to-remote-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
port: 2222
username: ${{ secrets.SERVER_USERNAME }}
privateKey: ${{ secrets.SSH_PRIVATE_KEY }}
passphrase: ${{ secrets.SSH_PASSPHRASE }}
local_dir: './build'
remote_base_dir: '/home/user/app'
remote_bak_path: '/home/user/backups'
retries: 3
retry_factor: 2
readyTimeout: 30000
debug: true
Input | Description | Example |
---|---|---|
host |
Remote server hostname or IP | example.com |
username |
SSH username | ubuntu |
local_dir |
Local directory to upload | ./dist |
remote_base_dir |
Remote destination directory | /var/www/html |
Input | Description | Example |
---|---|---|
password |
SSH password | ${{ secrets.PASSWORD }} |
privateKey |
SSH private key content | ${{ secrets.SSH_KEY }} |
agent |
Path to SSH agent socket | /tmp/ssh-agent.sock |
Input | Description | Default | Example |
---|---|---|---|
port |
SSH port | 22 |
2222 |
passphrase |
Private key passphrase | ${{ secrets.PASSPHRASE }} |
|
remote_bak_path |
Backup directory path | /backups |
|
forceIPv4 |
Force IPv4 connection | false |
true |
forceIPv6 |
Force IPv6 connection | false |
true |
readyTimeout |
SSH handshake timeout (ms) | 20000 |
30000 |
strictVendor |
Strict server vendor check | false |
true |
debug |
Enable debug logging | false |
true |
retries |
Connection retry attempts | 1 |
3 |
retry_factor |
Retry delay multiplier | 2 |
1.5 |
retry_minTimeout |
Min retry delay (ms) | 1000 |
2000 |
promiseLimit |
Concurrent operation limit | 10 |
5 |
Output | Description | Example |
---|---|---|
uploaded_files |
Number of files uploaded | 42 |
success |
Upload operation status | true |
error |
Error message if failed | Connection timeout |
Store sensitive information as GitHub repository secrets:
- Go to your repository β Settings β Secrets and variables β Actions
- Add the following secrets:
SERVER_HOST
- Your server hostnameSERVER_USERNAME
- SSH usernameSERVER_PASSWORD
- SSH password (if using password auth)SSH_PRIVATE_KEY
- SSH private key content (if using key auth)SSH_PASSPHRASE
- Private key passphrase (if needed)
For better security, use SSH key authentication:
# Generate SSH key pair
ssh-keygen -t rsa -b 4096 -C "github-actions@your-repo"
# Copy public key to server
ssh-copy-id -i ~/.ssh/id_rsa.pub user@server
# Add private key content to GitHub secrets as SSH_PRIVATE_KEY
cat ~/.ssh/id_rsa
name: Deploy React App
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install and Build
run: |
npm ci
npm run build
- name: Deploy to Server
uses: 2ue/ssh2-to-remote-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
privateKey: ${{ secrets.SSH_PRIVATE_KEY }}
local_dir: './build'
remote_base_dir: '/var/www/html'
remote_bak_path: '/var/backups/www'
- name: Check Deployment
if: success()
run: echo "β
Deployed ${{ steps.deploy.outputs.uploaded_files }} files successfully!"
name: Multi-Environment Deploy
on:
push:
branches: [ main, staging ]
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
environment:
- name: staging
branch: staging
host: staging.example.com
path: /var/www/staging
- name: production
branch: main
host: example.com
path: /var/www/html
steps:
- uses: actions/checkout@v4
if: github.ref == format('refs/heads/{0}', matrix.environment.branch)
- name: Deploy to ${{ matrix.environment.name }}
if: github.ref == format('refs/heads/{0}', matrix.environment.branch)
uses: 2ue/ssh2-to-remote-action@v1
with:
host: ${{ matrix.environment.host }}
username: ${{ secrets.SERVER_USERNAME }}
privateKey: ${{ secrets.SSH_PRIVATE_KEY }}
local_dir: './dist'
remote_base_dir: ${{ matrix.environment.path }}
remote_bak_path: '/backups/${{ matrix.environment.name }}'
retries: 3
debug: true
- Node.js 20+
- TypeScript
- Jest for testing
# Clone repository
git clone https://github.com/2ue/ssh2-to-remote-action.git
cd ssh2-to-remote-action
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run tests
npm test
# Run all checks
npm run all
src/
βββ config/ # Input validation and processing
βββ ssh/ # SSH connection management
βββ upload/ # File upload logic
βββ types/ # TypeScript type definitions
βββ main.ts # Main action logic
βββ index.ts # Entry point
__tests__/ # Test files
dist/ # Compiled output
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Make your changes and add tests
- Run the test suite:
npm run all
- Commit your changes:
git commit -m 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with ssh2-sftp-client
- Powered by GitHub Actions
- TypeScript support via @actions/core
- π Report Issues
- π‘ Request Features
- π Documentation
Made with β€οΈ for the GitHub Actions community