azlin cp¶
Copy files and directories between local machine and azlin VMs with bidirectional transfer support.
Description¶
The azlin cp command provides secure file transfer using rsync over SSH. Transfer files to VMs, download results from VMs, or copy between VMs directly. Security filters automatically block sensitive files like SSH keys and credentials.
Usage¶
Arguments¶
SOURCE- Source file/directory (local,vm:path, orip:path)DESTINATION- Destination path (local,vm:path, orip:path)
Options¶
| Option | Description |
|---|---|
-r, --recursive | Copy directories recursively |
--dry-run | Preview what would be copied |
--exclude PATTERN | Exclude files matching pattern |
--resource-group, --rg TEXT | Azure resource group (for VM name resolution) |
-h, --help | Show help message |
Examples¶
Copy File to VM¶
Output:
Copying to my-vm (20.12.34.56)...
Source: /Users/ryan/report.pdf
Destination: /home/azureuser/documents/report.pdf
Transferring...
report.pdf: 100% [===================] 2.4 MB/s
✓ Transfer complete!
Files: 1
Size: 2.4 MB
Time: 1.2s
Copy File from VM¶
Copy Directory Recursively¶
Output:
Copying to my-vm (20.12.34.56)...
Source: /Users/ryan/my-project/
Destination: /home/azureuser/workspace/my-project/
Scanning directory...
Files found: 247
Total size: 15.3 MB
Transferring...
████████████████████████████████ 100%
✓ Transfer complete!
Files: 247
Size: 15.3 MB
Time: 8.4s
Speed: 1.8 MB/s
Preview Transfer (Dry Run)¶
Output:
DRY RUN - No files will be copied
Would transfer:
large-dataset.zip (450 MB)
From: /Users/ryan/large-dataset.zip
To: my-vm:/home/azureuser/large-dataset.zip
Estimated time: 3m 45s (at 2 MB/s)
Copy Between VMs¶
Exclude Patterns¶
# Copy project but exclude node_modules
azlin cp -r ./myapp/ my-vm:~/workspace/ --exclude 'node_modules' --exclude '.git'
Copy Using IP Address¶
Common Workflows¶
Deploy Application Code¶
# Build locally
npm run build
# Copy to VM
azlin cp -r ./dist/ my-vm:~/app/dist/
# Restart service
azlin connect my-vm
sudo systemctl restart myapp
Download Training Results¶
# Copy trained model from VM
azlin cp my-vm:~/ml-training/model.pkl ./models/
# Download logs
azlin cp my-vm:~/ml-training/training.log ./logs/
Backup VM Data¶
# Download important data
azlin cp -r my-vm:~/projects/ ./backups/vm-projects-$(date +%Y%m%d)/
azlin cp -r my-vm:~/data/ ./backups/vm-data-$(date +%Y%m%d)/
Multi-VM Distribution¶
# Deploy config to all VMs
for vm in $(azlin list --format json | jq -r '.[].name'); do
echo "Deploying to $vm..."
azlin cp ./config.yaml $vm:~/app/config.yaml
done
Sync Datasets¶
# Copy large dataset to training VMs
azlin cp -r ./datasets/ vm1:~/ml-data/
azlin cp -r ./datasets/ vm2:~/ml-data/
azlin cp -r ./datasets/ vm3:~/ml-data/
Security Filters¶
Automatically blocks these sensitive files:
SSH Keys¶
*.pem,*.keyid_rsa,id_rsa.pub,id_ed25519.ssh/*
Cloud Credentials¶
.aws/credentials,.azure/credentialscredentials.json,service-account.json.config/gcloud/*
Environment Files¶
.env,.env.*,.env.local,.env.production
Git Internals¶
.git/(use--exclude .gitto be explicit)
Bypass warning:
⚠ WARNING: Blocked sensitive files:
.env
.ssh/id_rsa
Sensitive files not transferred. Use --force to override (not recommended).
Performance¶
| File Size | Transfer Time (estimate) |
|---|---|
| 1 MB | 0.5-1 second |
| 10 MB | 5-10 seconds |
| 100 MB | 50-60 seconds |
| 1 GB | 8-10 minutes |
Varies by network speed and VM region
Optimization Tips¶
# Use compression for large files
gzip large-file.txt
azlin cp large-file.txt.gz my-vm:~/
# Exclude unnecessary files
azlin cp -r ./project/ my-vm:~/ \
--exclude 'node_modules' \
--exclude '.git' \
--exclude '*.log'
# Transfer archives instead of many small files
tar -czf project.tar.gz ./project/
azlin cp project.tar.gz my-vm:~/
Troubleshooting¶
Permission Denied¶
Problem: "Permission denied" error.
Solution:
# Verify destination is writable
azlin connect my-vm
ls -la ~/destination-path
# Use home directory first
azlin cp file.txt my-vm:~/
# Then move with sudo
azlin connect my-vm
sudo mv ~/file.txt /opt/app/
Connection Timeout¶
Problem: Transfer times out on large files.
Solution:
# Use compression
gzip large-file.dat
azlin cp large-file.dat.gz my-vm:~/
# Or split large files
split -b 100M huge-file.dat chunk-
for chunk in chunk-*; do
azlin cp $chunk my-vm:~/
done
# Reassemble on VM
azlin connect my-vm
cat chunk-* > huge-file.dat
Blocked Sensitive Files¶
Problem: Files not transferred due to security filters.
Solution:
# Review blocked files
azlin cp --dry-run ./project/ my-vm:~/
# Exclude sensitive files explicitly
azlin cp -r ./project/ my-vm:~/ --exclude '.env'
# For legitimate need to transfer secrets (use with caution)
# Consider using azlin env set instead
azlin env set my-vm API_KEY="value"
Comparison with SCP¶
| Feature | azlin cp | scp |
|---|---|---|
| VM name resolution | ✓ | ✗ (IP only) |
| Session name support | ✓ | ✗ |
| Security filters | ✓ | ✗ |
| Dry-run mode | ✓ | ✗ |
| Progress bar | ✓ | Limited |
| Recursive by default | With -r | With -r |
Examples by Use Case¶
Web Development¶
# Deploy frontend build
npm run build
azlin cp -r ./dist/ web-vm:~/app/public/
# Update API code
azlin cp -r ./api/ api-vm:~/app/api/
Data Science¶
# Upload training data
azlin cp -r ./datasets/ ml-vm:~/data/
# Download trained models
azlin cp -r ml-vm:~/models/ ./trained-models/
# Get training logs
azlin cp ml-vm:~/training.log ./logs/
DevOps¶
# Distribute configuration
for vm in $(azlin list --tag app=api --format json | jq -r '.[].name'); do
azlin cp ./nginx.conf $vm:/tmp/nginx.conf
azlin connect $vm "sudo mv /tmp/nginx.conf /etc/nginx/nginx.conf && sudo systemctl reload nginx"
done
Azure Bastion Support¶
azlin cp automatically detects and uses Azure Bastion for VMs without public IP addresses, providing the same seamless experience as azlin connect. No configuration or special flags required.
How It Works¶
When you copy files to/from a VM, azlin cp:
- Checks for public IP - If VM has public IP, uses direct connection (fastest)
- Auto-detects Bastion - If no public IP, searches for Azure Bastion in resource group
- Creates secure tunnel - Automatically establishes tunnel through Bastion (localhost:50000-60000)
- Transfers files - Routes rsync through tunnel transparently
- Cleans up - Automatically closes tunnel when transfer completes
No user action required - Works identically to VMs with public IPs.
Bastion Examples¶
Copy to Bastion-Only VM¶
# VM has no public IP, but Bastion exists in resource group
azlin cp dataset.tar.gz secure-vm:~/data/
Output:
VM secure-vm has no public IP, checking for Bastion...
✓ Found Bastion: azlin-bastion-eastus
Creating Bastion tunnel...
✓ Bastion tunnel established: azlin-bastion-eastus -> 127.0.0.1:52341
Copying to secure-vm (via Bastion)...
Source: /Users/ryan/dataset.tar.gz
Destination: /home/azureuser/data/dataset.tar.gz
Transferring...
dataset.tar.gz: 100% [===================] 2.1 MB/s
✓ Transfer complete!
Files: 1
Size: 450 MB
Time: 3m 35s
Connection: Bastion (azlin-bastion-eastus)
Cleaning up Bastion tunnel...
✓ Tunnel closed
Deploy to Zero-Trust Environment¶
# All VMs in production have no public IPs
azlin cp -r ./app/ prod-api-1:~/app/
azlin cp -r ./app/ prod-api-2:~/app/
azlin cp -r ./app/ prod-api-3:~/app/
# Bastion automatically used for all transfers
# No configuration changes needed
Performance Comparison¶
| Connection Type | Typical Speed | Use Case |
|---|---|---|
| Direct (public IP) | 10-50 MB/s | Development VMs, temporary instances |
| Bastion tunnel | 2-20 MB/s | Production VMs, compliance requirements |
Notes: - Bastion adds 10-30% overhead vs direct connection - Regional Bastion (same region as VM) performs best - Cross-region Bastion adds additional latency - Security benefits often outweigh performance impact
Bastion Troubleshooting¶
No Bastion Found¶
Problem: "VM has no public IP and no bastion is available"
Solution:
# Check if Bastion exists in resource group
az network bastion list \
--resource-group your-resource-group \
--query "[].{name:name, location:location, state:provisioningState}" \
--output table
# If no Bastion exists, see setup guide:
# https://rysweet.github.io/azlin/bastion/setup/
Slow Transfer via Bastion¶
Problem: Transfer much slower than expected
Solutions:
# 1. Check Bastion and VM are in same region
az vm show --resource-group rg --name vm --query location
az network bastion show --resource-group rg --name bastion --query location
# 2. Use compression for large files
gzip large-file.dat
azlin cp large-file.dat.gz vm:~/
# 3. Use archives instead of many small files
tar -czf project.tar.gz ./project/
azlin cp project.tar.gz vm:~/
azlin connect vm "tar -xzf ~/project.tar.gz"
Related Commands¶
azlin sync- Sync dotfiles from ~/.azlin/home/azlin connect- SSH to VM (also supports Bastion)azlin storage mount- Mount shared NFS storageazlin bastion create- Set up Azure Bastionazlin bastion status- Check Bastion availability