Networking Deep Dive - SSH and SCP for Secure DevOps Workflows


Hello, fellas! After exploring networking fundamentals and the OSI Model, we'll explore two essential tools in every DevOps engineer's toolkit: SSH (Secure Shell) and SCP (Secure Copy Protocol).
These protocols are the backbone of secure system administration, remote server management, and file transfers in modern DevOps workflows. Whether you're deploying applications, managing infrastructure, or automating tasks, mastering SSH and SCP is crucial for maintaining security while ensuring seamless operations.
In this blog post, we'll explore SSH key management, secure file transfers with SCP/SFTP, and advanced concepts like SSH tunneling and port forwarding. Each topic will include real-world DevOps use cases and examples to reinforce your understanding.
I know some of these concepts might feel overwhelming at first, but don’t worry—this blog is just to help you grasp the theory. In future posts, we’ll get hands-on with practical activities to make everything crystal clear.
So, let's get started on securing your DevOps workflows!
Introduction
🔹 SSH (Secure Shell) allows secure remote access to servers, crucial for DevOps tasks like deployment, automation, and troubleshooting.
🔹 SCP (Secure Copy Protocol) is used to transfer files between local and remote systems securely.
🔹 Port Forwarding & Tunneling enhances security by routing traffic through encrypted SSH channels.
1️⃣ SSH Key Management for Automated Deployments
What is SSH Key Authentication?
SSH keys are used for passwordless authentication, allowing secure access to remote servers without manually entering passwords. This is essential for automated deployments in DevOps.
Understanding SSH Keys
SSH key pairs consist of two parts:
Private Key: This is your secret key, which stays on your local machine. Never share it with anyone.
Public Key: This key can be shared freely and is placed on servers you want to access.
When you connect to a server, your private key and the server's public key are used in a cryptographic handshake that verifies your identity without transmitting your private key or password.
Setting Up SSH Key-Based Authentication
Step 1: Generate SSH Key Pair
Run the following command on your local machine (Linux/Mac/WSL/VS Code terminal):
# Generate a new 4096-bit RSA key pair
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# You'll be prompted to specify a file location (default is ~/.ssh/id_rsa)
# You'll also be asked to set a passphrase (recommended for security)
-t rsa
→ Uses the RSA encryption algorithm-b 4096
→ Creates a stronger 4096-bit key-C "your_email@example.com"
→ Adds a comment for identification
Press Enter to save the key to ~/.ssh/id_rsa
and leave the passphrase empty for automation.
Step 2: Copy SSH Key to Remote Server
Use ssh-copy-id
(or manually append the key) to allow access without passwords:
# Copy your public key to a server
ssh-copy-id -i ~/.ssh/id_rsa.pub ubuntu@192.168.1.100
If ssh-copy-id
is unavailable, manually add the key:
# First, display and copy your public key
cat ~/.ssh/id_rsa.pub
# Connect to the server and add the key
ssh ubuntu@192.168.1.100
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "ssh-rsa AAAA..." >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
DevOps Use Cases
DevOps Use Case 1: CI/CD Pipeline with SSH Keys
In a typical CI/CD pipeline, you need to deploy code to servers automatically. Here's how you might set it up with GitHub Actions and SSH keys:
Generate a deployment key:
ssh-keygen -t rsa -b 4096 -C "github-actions-deploy" -f ~/.ssh/github_actions
Add the public key to your deployment server:
ssh-copy-id -i ~/.ssh/github_actions.pub ubuntu@your-server-ip
Add the private key as a secret in GitHub Actions:
Go to your GitHub repository
Navigate to Settings > Secrets
Add a new secret named
SSH_PRIVATE_KEY
with the content of your private key
Create a GitHub Actions workflow file:
name: Deploy to Production on: push: branches: [ main ] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up SSH uses: webfactory/ssh-agent@v0.5.4 with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - name: Deploy to server run: | ssh -o StrictHostKeyChecking=no ubuntu@your-server-ip ' cd /var/www/myapp && git pull && npm install && pm2 restart app '
This setup allows your CI/CD pipeline to deploy code securely without storing passwords in your codebase.
DevOps Use Case 2: Infrastructure as Code with SSH Keys
When using tools like Terraform or Ansible to manage infrastructure, SSH keys are essential for secure automation:
Create a dedicated automation key:
ssh-keygen -t rsa -b 4096 -C "ansible-automation" -f ~/.ssh/ansible
Use the key in your Ansible inventory:
# inventory.ini [webservers] web1 ansible_host=192.168.1.101 web2 ansible_host=192.168.1.102 [all:vars] ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/ansible
Create a simple Ansible playbook:
# deploy.yml --- - hosts: webservers become: yes tasks: - name: Update apt cache apt: update_cache: yes - name: Install Nginx apt: name: nginx state: present - name: Start Nginx service: name: nginx state: started enabled: yes
Run your Ansible playbook:
ansible-playbook -i inventory.ini deploy.yml
This setup allows you to automate infrastructure management securely across multiple servers.
SSH Key Best Practices for DevOps
For secure DevOps operations:
Use strong keys: Generate 4096-bit RSA keys or Ed25519 keys.
Set passphrases: Always use passphrases for keys used by humans.
Use SSH agents: Use
ssh-agent
to avoid typing passphrases repeatedly.Rotate keys regularly: Establish a process for key rotation.
Audit access: Regularly review who has access to what.
Limit key scope: Use specific keys for specific purposes.
2️⃣ Securely Transfer Files with SCP & SFTP
What is SCP?
SCP (Secure Copy Protocol) is used to securely copy files between local and remote systems over SSH.
SCP for File Transfers
Copy File from Local Machine to Remote Server
scp myfile.txt user@remote-server-ip:/home/user/
Copy File from Remote Server to Local Machine
scp user@remote-server-ip:/home/user/myfile.txt .
Copy an Entire Directory
scp -r my_folder/ user@remote-server-ip:/home/user/
Summary
# Basic syntax
# scp source destination
# Copy a local file to a remote server
scp /path/to/local/file.txt ubuntu@192.168.1.100:/path/on/remote/
# Copy a remote file to local machine
scp ubuntu@192.168.1.100:/path/on/remote/file.txt /path/to/local/
# Copy directory recursively
scp -r /path/to/local/directory ubuntu@192.168.1.100:/path/on/remote/
# Use a specific identity file
scp -i ~/.ssh/id_rsa_prod /path/to/local/file.txt ubuntu@192.168.1.100:/path/on/remote/
# Copy between two remote servers (executed from your local machine)
scp -3 ubuntu@192.168.1.100:/path/file.txt ubuntu@192.168.1.101:/path/
What is SFTP? (Secure File Transfer Protocol)
SFTP is an interactive file transfer session over SSH.
Step-by-Step: Use SFTP
1️⃣ Connect to Remote Server
sftp user@remote-server-ip
2️⃣ Upload a File
put myfile.txt
3️⃣ Download a File
get remote_file.txt
4️⃣ Exit SFTP
exit
DevOps Use Cases
DevOps Use Case 1: Automated Backup System
Let's create a simple automated backup system using SCP:
Create a backup script:
#!/bin/bash # backup.sh # Configuration BACKUP_DIR="/var/backups/$(date +%Y-%m-%d)" DB_NAME="myapp_db" DB_USER="dbuser" REMOTE_SERVER="ubuntu@backup-server" REMOTE_PATH="/backup/storage" # Create backup directory mkdir -p $BACKUP_DIR # Backup database echo "Backing up database..." mysqldump -u $DB_USER -p $DB_NAME > $BACKUP_DIR/database.sql # Backup configuration files echo "Backing up configuration..." cp /etc/nginx/sites-available/* $BACKUP_DIR/ cp /etc/php/8.1/fpm/php.ini $BACKUP_DIR/ # Compress backup echo "Compressing backup..." tar -czf $BACKUP_DIR.tar.gz $BACKUP_DIR # Transfer backup to remote server echo "Transferring to remote server..." scp $BACKUP_DIR.tar.gz $REMOTE_SERVER:$REMOTE_PATH # Clean up echo "Cleaning up..." rm -rf $BACKUP_DIR rm $BACKUP_DIR.tar.gz echo "Backup completed successfully!"
Make the script executable:
chmod +x backup.sh
Schedule it with cron:
# Edit crontab crontab -e # Add a daily backup at 2 AM 0 2 * * * /path/to/backup.sh > /var/log/backup.log 2>&1
This setup ensures regular, secure backups of your critical data.
DevOps Use Case 2: Application Deployment Pipeline
Here's how to create a simple deployment pipeline for a web application using SCP:
Create a deployment script:
#!/bin/bash # deploy.sh # Configuration APP_NAME="mywebapp" BUILD_DIR="./dist" SERVER_USER="ubuntu" SERVERS=("192.168.1.101" "192.168.1.102") TARGET_DIR="/var/www/html" # Build the application (example for a Node.js app) echo "Building application..." npm ci npm run build # Deploy to each server for SERVER in "${SERVERS[@]}"; do echo "Deploying to $SERVER..." # Create a deployment directory ssh $SERVER_USER@$SERVER "mkdir -p $TARGET_DIR/$APP_NAME.new" # Copy files to the new directory scp -r $BUILD_DIR/* $SERVER_USER@$SERVER:$TARGET_DIR/$APP_NAME.new/ # Execute remote commands to finish deployment ssh $SERVER_USER@$SERVER " # Backup current version if [ -d $TARGET_DIR/$APP_NAME ]; then mv $TARGET_DIR/$APP_NAME $TARGET_DIR/$APP_NAME.old fi # Switch to new version mv $TARGET_DIR/$APP_NAME.new $TARGET_DIR/$APP_NAME # Update permissions chown -R www-data:www-data $TARGET_DIR/$APP_NAME # Restart web server systemctl restart nginx # Remove old version after successful restart if [ $? -eq 0 ] && [ -d $TARGET_DIR/$APP_NAME.old ]; then rm -rf $TARGET_DIR/$APP_NAME.old fi " echo "Deployment to $SERVER completed!" done echo "All deployments completed successfully!"
Make the script executable:
chmod +x deploy.sh
Run the deployment manually or integrate with CI/CD:
./deploy.sh
This script builds your application and securely deploys it to multiple servers, with a backup and rollback capability.
3️⃣ SSH Tunneling and Port Forwarding
What is SSH Port Forwarding?
SSH tunneling allows secure access to remote services through an encrypted SSH connection. It’s useful when accessing databases, private applications, or internal servers securely.
Understanding SSH Tunneling
SSH tunneling creates an encrypted channel between a local port and a remote port through an SSH connection. There are three main types of tunnels:
Local Port Forwarding: Forwards a local port to a remote destination.
Remote Port Forwarding: Forwards a remote port to a local destination.
Dynamic Port Forwarding: Creates a SOCKS proxy for flexible routing.
SSH Tunneling for Secure Access
Local Port Forwarding
Local port forwarding connects a port on your local machine to a port on a remote server or any server accessible from the remote:
# Basic syntax
# ssh -L local_port:destination_host:destination_port ssh_server
# Example: Access a remote MySQL server through SSH
ssh -L 3306:localhost:3306 ubuntu@192.168.1.100
# Example: Access a web server behind a bastion host
ssh -L 8080:internal-web-server:80 ubuntu@bastion-host
After establishing this tunnel, you can connect to localhost:3306
or localhost:8080
on your local machine, and the connection will be securely forwarded through the SSH server.
Remote Port Forwarding
Remote port forwarding is the reverse of local forwarding. It connects a port on the remote SSH server to a port on your local machine or any server accessible from your local machine:
# Basic syntax
# ssh -R remote_port:destination_host:destination_port ssh_server
# Example: Expose a local development server to a remote machine
ssh -R 8080:localhost:3000 ubuntu@192.168.1.100
# Example: Allow remote access to a local database
ssh -R 5432:localhost:5432 ubuntu@192.168.1.100
For remote port forwarding to work, you may need to enable GatewayPorts
in the SSH server configuration.
Dynamic Port Forwarding (SOCKS Proxy)
Dynamic port forwarding sets up a SOCKS proxy server on your local machine that routes traffic through the SSH connection:
# Basic syntax
# ssh -D local_port ssh_server
# Example: Create a SOCKS proxy on port 1080
ssh -D 1080 ubuntu@192.168.1.100
You can then configure your applications (like browsers) to use this SOCKS proxy (localhost:1080).
Persistent SSH Tunnels
For DevOps purposes, you often need persistent tunnels that stay active even if the connection drops. The autossh
tool is perfect for this:
# Install autossh
sudo apt update
sudo apt install autossh
# Create a persistent local port forward
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -L 3306:localhost:3306 ubuntu@192.168.1.100
# Create a persistent remote port forward
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -R 8080:localhost:3000 ubuntu@192.168.1.100
# Create a persistent SOCKS proxy
autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -D 1080 ubuntu@192.168.1.100
Creating SSH Tunnel Services
For even more reliability, you can create a systemd service to manage your tunnels:
# Create a systemd service file
sudo nano /etc/systemd/system/ssh-tunnel.service
Add the following content:
[Unit]
Description=SSH tunnel to remote server
After=network.target
[Service]
User=ubuntu
ExecStart=/usr/bin/autossh -M 0 -N -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -L 3306:localhost:3306 ubuntu@192.168.1.100
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl enable ssh-tunnel.service
sudo systemctl start ssh-tunnel.service
sudo systemctl status ssh-tunnel.service
DevOps Use Cases
DevOps Use Case 1: Securely Accessing Database in Production
As a DevOps engineer, you often need to access production databases securely without exposing database ports to the public internet:
Create a local port forwarding tunnel to access the database:
ssh -L 5432:localhost:5432 ubuntu@prod-bastion-server
Configure your database client to connect to localhost:5432:
# For PostgreSQL psql -h localhost -p 5432 -U dbuser -d mydb # For MySQL mysql -h localhost -P 5432 -u dbuser -p mydb
Create a script for quick access:
#!/bin/bash # db-tunnel.sh echo "Creating secure tunnel to production database..." ssh -L 5432:db-server:5432 ubuntu@prod-bastion-server -N & TUNNEL_PID=$! echo "Tunnel established (PID: $TUNNEL_PID)" echo "Connect to the database using: psql -h localhost -p 5432 -U dbuser -d mydb" echo "Press Ctrl+C to close the tunnel" # Wait for user to press Ctrl+C trap "kill $TUNNEL_PID; echo 'Tunnel closed'; exit" INT wait
This approach ensures that:
The database port is never exposed to the public internet
All traffic is encrypted through the SSH tunnel
Access requires SSH keys, providing an additional layer of security
DevOps Use Case 2: Development Environment with Remote Services
When developing applications that interact with multiple services, you can use SSH tunneling to create a local development environment that connects to remote services:
Create a script to set up multiple tunnels:
#!/bin/bash # dev-environment.sh # Configuration BASTION_SERVER="ubuntu@dev-bastion" # Start all tunnels echo "Setting up development environment tunnels..." # Redis tunnel ssh -L 6379:redis-server:6379 $BASTION_SERVER -N & REDIS_TUNNEL_PID=$! echo "Redis tunnel established (PID: $REDIS_TUNNEL_PID)" # MongoDB tunnel ssh -L 27017:mongodb-server:27017 $BASTION_SERVER -N & MONGO_TUNNEL_PID=$! echo "MongoDB tunnel established (PID: $MONGO_TUNNEL_PID)" # ElasticSearch tunnel ssh -L 9200:elasticsearch-server:9200 $BASTION_SERVER -N & ES_TUNNEL_PID=$! echo "ElasticSearch tunnel established (PID: $ES_TUNNEL_PID)" # RabbitMQ tunnel ssh -L 5672:rabbitmq-server:5672 $BASTION_SERVER -N & RABBIT_TUNNEL_PID=$! echo "RabbitMQ tunnel established (PID: $RABBIT_TUNNEL_PID)" echo "All tunnels established!" echo "Your application can now connect to these services on localhost" echo "Press Ctrl+C to close all tunnels" # Wait for user to press Ctrl+C trap "kill $REDIS_TUNNEL_PID $MONGO_TUNNEL_PID $ES_TUNNEL_PID $RABBIT_TUNNEL_PID; echo 'All tunnels closed'; exit" INT wait
Add tunnel information to your project documentation:
# Development Environment Setup ## Prerequisites - SSH access to the development bastion server - SSH key configured in your SSH agent ## Setup 1. Run the tunnel script: `./dev-environment.sh` 2. Configure your application to use the following connections: - Redis: localhost:6379 - MongoDB: localhost:27017 - ElasticSearch: localhost:9200 - RabbitMQ: localhost:5672 3. Run your application normally
This setup allows developers to:
Work with their local code while connecting to shared development services
Avoid installing complex dependencies locally
Test against realistic data and configurations
Maintain secure, encrypted connections to all services
Best Practices for SSH and SCP in DevOps
To ensure the security and reliability of your SSH and SCP usage in DevOps workflows, follow these best practices:
Security Best Practices
Use key-based authentication exclusively: Disable password authentication where possible.
Implement strong key policies:
Use 4096-bit RSA keys or Ed25519 keys
Set passphrases on keys, especially for human users
Rotate keys regularly
Configure SSH securely:
# Edit SSH server configuration sudo nano /etc/ssh/sshd_config # Recommended settings PasswordAuthentication no PermitRootLogin no PubkeyAuthentication yes MaxAuthTries 3 ClientAliveInterval 300 ClientAliveCountMax 2
Use SSH certificates for larger teams:
Implement an SSH Certificate Authority (CA)
Sign user keys with the CA
Configure servers to trust the CA
Implement jump hosts/bastion hosts:
Limit direct SSH access to servers
Route all SSH connections through bastion hosts
Implement enhanced logging on bastion hosts
Automation Best Practices
Use SSH config files for clarity and maintainability:
# ~/.ssh/config Host * ServerAliveInterval 60 ServerAliveCountMax 3 Host prod-* User ubuntu IdentityFile ~/.ssh/id_rsa_prod ProxyJump bastion-prod Host staging-* User ubuntu IdentityFile ~/.ssh/id_rsa_staging ProxyJump bastion-staging
Implement SSH multiplexing for performance:
# ~/.ssh/config Host * ControlMaster auto ControlPath ~/.ssh/cm_%h_%p_%r ControlPersist 10m
Use SSH agents for secure key management:
# Start SSH agent eval $(ssh-agent) # Add keys with timeout ssh-add -t 8h ~/.ssh/id_rsa
Create reusable scripts for common operations:
Backup scripts
Deployment scripts
Environment setup scripts
Document SSH practices and requirements:
Key rotation procedures
Access request processes
Troubleshooting guides
Conclusion
SSH and SCP are essential tools for DevOps workflows.
Using key-based authentication enhances security and automation.
Tunneling and port forwarding secure access to remote services.
Well done, guys! I hope this was a smooth ride for you—haha, just kidding! I know it might have felt like a lot, with all the concepts and examples we covered. But as I mentioned earlier, this blog is here to help you grasp the theory first. With continuous practice, SSH and SCP will become second nature to you.
By mastering these tools, you'll be able to build more secure, efficient automation pipelines and infrastructure management workflows. So, keep experimenting and applying these concepts in real-world scenarios!
Next up, we’re heading into the final topic of this networking series. In our next blog post, we'll dive into "Securing Your Web Connection: SSL and HTTPS for DevOps," where we’ll explore web security fundamentals and how to implement HTTPS for your applications. Trust me, you don’t want to miss this one!
Until next time, keep coding, automating, and advancing in DevOps! 😁
Peace out ✌️
Subscribe to my newsletter
Read articles from Rajratan Gaikwad directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Rajratan Gaikwad
Rajratan Gaikwad
I write about the art and adventure of DevOps, making complex topics in CI/CD, Cloud Automation, Infrastructure as Code, and Monitoring approachable and fun. Join me on my DevOps Voyage, where each post unpacks real-world challenges, explores best practices, and dives deep into the world of modern DevOps—one journey at a time!