Skip to main content

SSH Targets

SSH targets enable command execution on remote servers through secure shell connections. Xec provides advanced SSH features including connection pooling, tunneling, and automatic retry mechanisms.

Basic Configuration​

Define SSH hosts in the targets.hosts section:

targets:
hosts:
web-server:
host: web.example.com
username: deploy
privateKey: ~/.ssh/id_rsa

Connection Properties​

Essential Properties​

targets:
hosts:
server:
# Required
host: server.example.com # Hostname or IP address

# Authentication (at least one required)
username: deploy # SSH username
privateKey: ~/.ssh/id_rsa # Path to private key
password: ${secrets.password} # Password (use secrets!)

# Optional
port: 22 # SSH port (default: 22)
passphrase: ${secrets.phrase} # Key passphrase

Advanced Properties​

targets:
hosts:
advanced:
host: server.example.com
username: admin

# Connection settings
keepAlive: true # Keep connection alive
keepAliveInterval: 30000 # Keep-alive interval (ms)
timeout: 60000 # Connection timeout (ms)

# Execution settings
shell: /bin/bash # Shell to use
encoding: utf8 # Output encoding
maxBuffer: 10485760 # Max output buffer (bytes)
throwOnNonZeroExit: true # Throw on non-zero exit

# Working directory
workdir: /var/www/app # Default directory
cwd: /var/www/app # Alias for workdir

# Environment
env:
NODE_ENV: production
PATH: /usr/local/bin:$PATH

Authentication Methods​

Private Key Authentication​

Most secure and recommended method:

targets:
hosts:
secure:
host: secure.example.com
username: deploy
privateKey: ~/.ssh/deploy_key
passphrase: ${secrets.key_passphrase} # If key is encrypted

Multiple Key Attempts​

targets:
hosts:
multi-key:
host: server.example.com
username: admin
privateKey: |
~/.ssh/id_rsa
~/.ssh/id_ed25519
~/.ssh/deploy_key

Password Authentication​

Less secure, use only when necessary:

targets:
hosts:
legacy:
host: old-server.example.com
username: admin
password: ${secrets.legacy_password} # Never hardcode!

SSH Agent​

Use SSH agent for key management:

targets:
hosts:
agent:
host: server.example.com
username: deploy
# No privateKey specified - uses SSH agent

Connection Pooling​

Optimize performance with connection reuse:

targets:
hosts:
pooled:
host: busy-server.example.com
connectionPool:
enabled: true # Enable pooling
min: 2 # Minimum connections
max: 10 # Maximum connections
idleTimeout: 300000 # Idle timeout (5 min)
acquireTimeout: 30000 # Acquire timeout

Pool Configuration Examples​

# High-traffic server
targets:
hosts:
api:
host: api.example.com
connectionPool:
min: 5
max: 20
idleTimeout: 600000 # 10 minutes

# Low-traffic server
targets:
hosts:
backup:
host: backup.example.com
connectionPool:
min: 0
max: 2
idleTimeout: 60000 # 1 minute

Proxy Connections​

Connect through jump hosts:

targets:
hosts:
# Simple proxy
behind-firewall:
host: internal.example.com
proxy: bastion.example.com
username: deploy

# Proxy with authentication
secured:
host: secure-internal.example.com
proxy: user@jump.example.com:2222
privateKey: ~/.ssh/internal_key

Multi-Hop Proxy​

targets:
hosts:
deep-internal:
host: deep.internal.example.com
proxy: bastion1.example.com,bastion2.example.com
username: deploy

Sudo Execution​

Execute commands with elevated privileges:

targets:
hosts:
admin-server:
host: server.example.com
username: admin
sudo:
enabled: true
method: sudo # or 'su'
password: ${secrets.sudo_password}

Sudo Patterns​

# Passwordless sudo
targets:
hosts:
trusted:
host: trusted.example.com
sudo:
enabled: true
# No password needed

# Custom sudo command
targets:
hosts:
custom:
host: custom.example.com
sudo:
enabled: true
method: "doas" # BSD systems

SFTP Configuration​

Configure secure file transfer:

targets:
hosts:
file-server:
host: files.example.com
sftp:
enabled: true
concurrency: 5 # Parallel transfers
chunkSize: 32768 # Transfer chunk size
fastGet: true # Enable fast download
fastPut: true # Enable fast upload

Environment Variables​

Set environment for all commands:

targets:
hosts:
app-server:
host: app.example.com
env:
# Application settings
NODE_ENV: production
API_URL: https://api.example.com

# Path modifications
PATH: /opt/app/bin:$PATH
LD_LIBRARY_PATH: /opt/app/lib

# Locale settings
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8

Working Directory​

Control command execution location:

targets:
hosts:
project:
host: dev.example.com
workdir: /home/deploy/project

# All commands run in workdir
# xec in hosts.project "ls" β†’ runs in /home/deploy/project

Shell Configuration​

Customize shell behavior:

targets:
hosts:
# Use specific shell
zsh-server:
host: modern.example.com
shell: /bin/zsh

# No shell (direct execution)
direct:
host: minimal.example.com
shell: false

# Custom shell command
custom-shell:
host: special.example.com
shell: "/bin/bash --noprofile"

Timeout Configuration​

Prevent hanging connections:

targets:
hosts:
slow-server:
host: slow.example.com
timeout: 300000 # 5 minute timeout

fast-server:
host: fast.example.com
timeout: 5000 # 5 second timeout

Error Handling​

Configure error behavior:

targets:
hosts:
strict:
host: critical.example.com
throwOnNonZeroExit: true # Fail on any error

lenient:
host: test.example.com
throwOnNonZeroExit: false # Continue on error

Host Groups​

Organize related hosts:

targets:
hosts:
# Web servers
web-1:
host: web1.example.com
username: deploy
web-2:
host: web2.example.com
username: deploy
web-3:
host: web3.example.com
username: deploy

# Database servers
db-primary:
host: db1.example.com
username: dba
db-replica:
host: db2.example.com
username: dba

Dynamic Host Discovery​

Discover hosts at runtime:

targets:
hosts:
# From environment variable
$env: SSH_HOSTS

# From command output
$command: "terraform output -json servers | jq -r '.[]'"

# From file
$file: ./hosts.txt

Real-World Examples​

Production Web Server​

targets:
hosts:
production-web:
host: prod-web.example.com
username: deploy
privateKey: ~/.ssh/prod_deploy_key
port: 22

# Performance optimization
keepAlive: true
keepAliveInterval: 30000
connectionPool:
min: 2
max: 10
idleTimeout: 300000

# Environment
workdir: /var/www/app
env:
NODE_ENV: production
PORT: 3000

# Reliability
timeout: 60000
throwOnNonZeroExit: true

Development Server​

targets:
hosts:
dev-server:
host: dev.example.com
username: developer
privateKey: ~/.ssh/id_rsa

# Convenience settings
workdir: ~/projects
env:
NODE_ENV: development
DEBUG: "*"

# Lenient error handling
throwOnNonZeroExit: false

Bastion Access​

targets:
hosts:
internal-api:
host: 10.0.1.50
username: api-user
privateKey: ~/.ssh/internal_key
proxy: bastion.example.com

# Security
sudo:
enabled: false

# Restricted environment
env:
PATH: /usr/local/bin:/usr/bin:/bin

Troubleshooting​

Connection Debugging​

# Test connection
xec test hosts.production

# Verbose SSH output
xec --verbose in hosts.production "echo test"

# Check SSH configuration
xec config show --target hosts.production

Common Issues​

Permission Denied​

# Check authentication
targets:
hosts:
fixed:
host: server.example.com
username: correct_username # Verify username
privateKey: ~/.ssh/correct_key # Verify key path
# Check key permissions: chmod 600 ~/.ssh/correct_key

Connection Timeout​

# Increase timeout
targets:
hosts:
slow:
host: slow.example.com
timeout: 120000 # 2 minutes
keepAlive: true
keepAliveInterval: 10000

Proxy Issues​

# Debug proxy connection
targets:
hosts:
debug-proxy:
host: internal.example.com
proxy: -v bastion.example.com # Add -v for verbose

Security Best Practices​

1. Use Key Authentication​

# Good - key authentication
targets:
hosts:
secure:
privateKey: ~/.ssh/deploy_key

# Avoid - password authentication
targets:
hosts:
insecure:
password: "plaintext" # Never do this!

2. Secure Key Storage​

# Set proper permissions
chmod 600 ~/.ssh/deploy_key
chmod 700 ~/.ssh

3. Use Secrets Management​

targets:
hosts:
managed:
host: server.example.com
passphrase: ${secrets.ssh_passphrase}
sudo:
password: ${secrets.sudo_password}

4. Limit Environment Exposure​

targets:
hosts:
limited:
host: server.example.com
env:
# Only necessary variables
APP_ENV: production
# Avoid sensitive data in env

5. Use Connection Pooling​

# Reuse connections securely
targets:
hosts:
pooled:
connectionPool:
max: 5 # Limit concurrent connections
idleTimeout: 300000 # Close idle connections

Next Steps​

See Also​