Host Key Rotation
TLDR - Quick Summary
What: Rotate SSH host keys on a single-instance SFTP Gateway 3.x deployment
Method: Export backup via API, generate new keys, import via API, restart Java service
Key point: The database is the source of truth for host keys, not the filesystem — you must use the backup/restore API
Downtime: Brief service restart disconnects active SFTP sessions (~10 seconds)
Introduction
SSH host keys are the cryptographic identity of your SFTP server. When clients connect, they verify the server's host key fingerprint to ensure they're talking to the legitimate server and not an attacker performing a man-in-the-middle attack. Over time, you may need to rotate these keys for security compliance, after a potential compromise, or as part of routine key hygiene.
This guide walks you through rotating SSH host keys on a single-instance SFTP Gateway 3.x deployment. The process is straightforward but requires understanding how SFTP Gateway manages keys internally, which differs from a standard SSH server.
Why This Guide Exists
On a traditional Linux server, you'd simply regenerate the files in /etc/ssh/ and restart sshd. SFTP Gateway 3.x works differently: it stores the authoritative host keys in its database, not on the filesystem. The files you see in /opt/sftpgw/ are just a working copy that gets recreated each time the Java service starts.
This means you can't just replace files on disk. Instead, you need to update the database through SFTP Gateway's backup/restore API, then restart the service to load the new keys. This guide shows you exactly how to do that.
What You'll Accomplish
By the end of this guide, you will have:
- Created a rollback artifact containing your current keys (so you can restore them if needed)
- Generated fresh cryptographic keys for all supported algorithms
- Imported the new keys into SFTP Gateway's database
- Verified that clients see the new fingerprints
The entire process takes about 10-15 minutes and requires a brief service restart that will disconnect active SFTP sessions.
How SFTP Gateway Manages Host Keys
Before diving into the procedure, it helps to understand the architecture. This knowledge will make troubleshooting easier if something goes wrong.
┌─────────────────────────────────────────┐
│ SFTP Gateway VM │
│ │
│ ┌─────────────────────────────────┐ │
│ │ Database │ │
│ │ (Source of Truth) │ │
│ │ hostkeys section │ │
│ └──────────────┬──────────────────┘ │
│ │ │
│ │ Java reads on start │
│ ▼ │
│ ┌─────────────────────────────────┐ │
│ │ /opt/sftpgw/ (Working Copy) │ │
│ │ ssh_host_rsa, ssh_host_ed25519│ │
│ └─────────────────────────────────┘ │
│ │
└─────────────────────────────────────────┘
The database stores the authoritative host keys in a section called hostkeys. When the Java service (sftpgw-admin-api) starts, it reads these keys from the database and writes them to /opt/sftpgw/ where the SFTP subsystem can use them.
This architecture exists because SFTP Gateway supports High Availability deployments where multiple nodes share the same database. By storing keys in the database, all nodes automatically use identical keys without manual file synchronization.
For a single VM, this means any key rotation must go through the database. The SFTP Gateway backup/restore API provides access to this data in YAML format, which is how we'll perform the rotation.
Prerequisites
Before starting, make sure you have:
- Admin access to SFTP Gateway web UI - You'll need the admin username and password
- SSH access to the VM - Required for getting API client credentials and restarting the Java service
- A safe place to store backup files - The rollback YAML is your safety net; keep it secure
You'll also need these command-line tools (typically pre-installed on macOS/Linux):
curl- For API callsssh-keygen- For generating new keysjq- For parsing JSON (optional but helpful)base64- For encoding keys (included in macOS/Linux)
Rotation Procedure
This section walks through each step of the rotation process. We recommend reading through the entire procedure once before starting, so you understand what's coming.
Step 1: Export Current Backup (Create Your Safety Net)
The first and most important step is creating a rollback artifact. This backup contains your current host keys and allows you to restore them if anything goes wrong during the rotation.
Never skip this step. If the rotation fails or causes problems, you'll need this file to restore service.
Via Web UI:
- Log into the SFTP Gateway web admin portal
- Navigate to Settings > Backup & Recovery
- Click Export
- Save the file as
backup-YYYYMMDD-pre-rotation.yml
Via API:
First, get the API client credentials from the server:
ssh -p 2222 ec2-user@your-sftpgw.example.com \
"sudo grep -E 'security.client' /opt/sftpgw/application.properties"
This returns values like:
security.client-id=ABC123...
security.client-secret=XYZ789...
Now authenticate using Basic Auth with the client credentials, plus form data with your admin credentials:
# Set your credentials (URL-encode special characters in password, e.g., ! becomes %21)
CLIENT_ID="your-client-id"
CLIENT_SECRET="your-client-secret"
ADMIN_USER="admin"
ADMIN_PASS="yourpassword" # URL-encoded if it contains special characters
# Get access token
TOKEN=$(curl -s -X POST "https://your-sftpgw.example.com/backend/login" \
-u "${CLIENT_ID}:${CLIENT_SECRET}" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password&username=${ADMIN_USER}&password=${ADMIN_PASS}&scope=read" \
--insecure | jq -r '.access_token')
echo "Token: ${TOKEN:0:20}..." # Show first 20 chars to verify
# Export backup
curl -s -X GET "https://your-sftpgw.example.com/backend/3.0.0/backup" \
-H "Authorization: Bearer $TOKEN" \
--insecure \
-o backup-$(date +%Y%m%d)-pre-rotation.yml
echo "Backup saved to: backup-$(date +%Y%m%d)-pre-rotation.yml"
Note: Use
--insecureif the server uses a self-signed certificate. In production, configure proper TLS certificates.
Store this backup file somewhere safe. You'll reference it if you need to roll back.
Step 2: Create Minimal Rollback File
The full backup contains all SFTP Gateway settings (users, folders, configurations, etc.). For a faster rollback that only affects host keys, extract just the hostkeys section into a separate file.
This step is optional but recommended. A minimal rollback file is easier to work with and won't accidentally overwrite other settings if you need to restore.
# Extract the hostkeys section (from "hostkeys:" to the next top-level key)
sed -n '/^hostkeys:/,/^[a-zA-Z]/p' backup-*-pre-rotation.yml | sed '$d' > rollback-hostkeys-only.yml
# Add the required version header
{
echo '!<2022-05-05>'
echo 'version: "2022-05-05"'
cat rollback-hostkeys-only.yml
} > rollback-hostkeys.yml
Example rollback-hostkeys.yml structure:
The backup uses a list format with base64-encoded keys:
!<2022-05-05>
version: "2022-05-05"
hostkeys:
- keyName: "ssh_host_ed25519"
keyValue: "LS0tLS1CRUdJTi..." # Base64-encoded private key
- keyName: "ssh_host_ed25519.pub"
keyValue: "LS0tLSBCRUdJTi..." # Base64-encoded SSH2 format public key
- keyName: "ssh_host_rsa"
keyValue: "LS0tLS1CRUdJTi..."
- keyName: "ssh_host_rsa.pub"
keyValue: "LS0tLSBCRUdJTi..."
# ... etc for ecdsa_256, ecdsa_384, ecdsa_521
Note: The version header (
!<2022-05-05>andversion: "2022-05-05") is required for imports to work.
Step 3: Generate New Host Keys
Now you'll create the new cryptographic keys that will replace the existing ones. Generate these on your local machine, not on the server. This keeps the private keys off the network until they're securely transmitted via the API.
SFTP Gateway uses five key types to support different client configurations and security levels:
- RSA 4096-bit - Widely compatible, works with older clients
- ECDSA 256/384/521 - Modern elliptic curve keys, good balance of security and performance
- Ed25519 - Newest and most secure, but requires modern clients
# Create a temporary directory for the new keys
KEYDIR=$(mktemp -d)
cd "$KEYDIR"
# Generate all key types used by SFTP Gateway
ssh-keygen -t rsa -b 4096 -f ssh_host_rsa -N "" -C "sftpgw-$(date +%Y%m%d)"
ssh-keygen -t ecdsa -b 256 -f ssh_host_ecdsa_256 -N "" -C "sftpgw-$(date +%Y%m%d)"
ssh-keygen -t ecdsa -b 384 -f ssh_host_ecdsa_384 -N "" -C "sftpgw-$(date +%Y%m%d)"
ssh-keygen -t ecdsa -b 521 -f ssh_host_ecdsa_521 -N "" -C "sftpgw-$(date +%Y%m%d)"
ssh-keygen -t ed25519 -f ssh_host_ed25519 -N "" -C "sftpgw-$(date +%Y%m%d)"
echo "Keys generated in: $KEYDIR"
ls -la
The -N "" flag creates keys without a passphrase, which is required for automated server use. The comment (-C) includes the date to help identify when keys were created.
Step 4: Create Import YAML
With the new keys generated, package them into a YAML file that SFTP Gateway can import. The import format requires:
- A version header (
!<2022-05-05>andversion: "2022-05-05") - Keys in list format with
keyNameandkeyValuepairs - All key values base64-encoded
- Public keys converted to SSH2 format before base64 encoding
# Still in the key directory
OUTPUT="new-hostkeys.yml"
# Start with version header
cat > "$OUTPUT" << 'EOF'
!<2022-05-05>
version: "2022-05-05"
hostkeys:
EOF
# Add each key type
for keytype in ssh_host_rsa ssh_host_ecdsa_256 ssh_host_ecdsa_384 ssh_host_ecdsa_521 ssh_host_ed25519; do
# Private key - base64 encode the entire file
PRIV_B64=$(base64 < "$keytype")
echo "- keyName: \"$keytype\"" >> "$OUTPUT"
echo " keyValue: \"$PRIV_B64\"" >> "$OUTPUT"
# Public key - convert to SSH2 format, then base64 encode
PUB_SSH2=$(ssh-keygen -e -f "${keytype}.pub" -m SSH2)
PUB_B64=$(echo "$PUB_SSH2" | base64)
echo "- keyName: \"${keytype}.pub\"" >> "$OUTPUT"
echo " keyValue: \"$PUB_B64\"" >> "$OUTPUT"
done
echo "Created: $OUTPUT"
echo "Size: $(wc -c < "$OUTPUT") bytes"
The generated file should look like:
!<2022-05-05>
version: "2022-05-05"
hostkeys:
- keyName: "ssh_host_rsa"
keyValue: "LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0t..."
- keyName: "ssh_host_rsa.pub"
keyValue: "LS0tLSBCRUdJTiBTU0gyIFBVQkxJQyBLRVkgLS0tLQpD..."
# ... etc
Step 5: Import New Keys
This is the step that actually updates the database with your new keys. After this completes, the database will contain the new keys, but the running service will still be using the old ones until you restart it.
Via Web UI:
- Navigate to Settings > Backup & Recovery
- Click Import
- Select the
new-hostkeys.ymlfile - Verify the import log shows success
Via API:
curl -s -X POST "https://your-sftpgw.example.com/backend/3.0.0/backup" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/x-yaml" \
--data-binary @new-hostkeys.yml \
--insecure
A successful import returns a JSON array confirming each key was loaded:
["Key ssh_host_ed25519 loaded successfully","Key ssh_host_ecdsa_384 loaded successfully",...]
If you see errors about "missing type id property 'version'", make sure your YAML includes the version header.
Step 6: Restart the Java Service
The database now contains your new keys, but the SFTP service is still using the old ones loaded in memory. Restart the Java service to make it reload keys from the database.
Note: This will briefly disconnect any active SFTP sessions. Plan accordingly if you have users actively transferring files.
SSH into the VM and run (note: SFTP Gateway uses port 2222 for SSH by default):
ssh -p 2222 ec2-user@your-sftpgw.example.com
sudo systemctl restart sftpgw-admin-api
# Verify it's running
sudo systemctl status sftpgw-admin-api
# Check logs if needed
sudo journalctl -u sftpgw-admin-api -n 30
The service should restart within a few seconds. If it fails to start, check the logs for errors and consider rolling back to your backup.
Step 7: Verify New Keys
The final step is confirming that clients now see the new fingerprints. This verification ensures the entire process completed successfully.
From your local machine, scan the server's keys:
ssh-keyscan your-sftpgw.example.com 2>/dev/null | ssh-keygen -lf -
You should see fingerprints for multiple key types (RSA, ECDSA, Ed25519). Compare these to the fingerprints of the keys you generated in Step 3 to confirm they match.
Or check directly on the server (note: use the private key file, as the public keys are in SSH2 format):
sudo ssh-keygen -lf /opt/sftpgw/ssh_host_ed25519
If the fingerprints match your newly generated keys, the rotation is complete.
Rollback Procedure
If something goes wrong after importing new keys, you can restore the original keys using the backup files you created earlier. This section covers your options.
Option A: Import Rollback YAML (Recommended)
Use the minimal rollback file from Step 2. This only restores host keys without affecting other settings.
Via Web UI:
- Navigate to Settings > Backup & Recovery
- Click Import
- Select
rollback-hostkeys.yml - Restart Java:
sudo systemctl restart sftpgw-admin-api
Via API:
# Make sure your rollback file has the version header
curl -s -X POST "https://your-sftpgw.example.com/backend/3.0.0/backup" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/x-yaml" \
--data-binary @rollback-hostkeys.yml \
--insecure
# Restart service
ssh -p 2222 ec2-user@your-sftpgw "sudo systemctl restart sftpgw-admin-api"
Option B: Import Full Backup
If you don't have the minimal rollback file, use the full pre-rotation backup (it already has the version header):
curl -s -X POST "https://your-sftpgw.example.com/backend/3.0.0/backup" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/x-yaml" \
--data-binary @backup-YYYYMMDD-pre-rotation.yml \
--insecure
Note: This restores ALL settings from the backup, not just host keys. Any configuration changes made after the backup was taken will be lost.
Using the Automated Script
For convenience, we provide a script that automates the entire rotation process. It handles authentication, backup creation, key generation, import, and provides clear instructions for the manual restart step.
# From the repository root
./scripts/rotate-hostkeys-single.sh https://your-sftpgw.example.com
The script will:
- Prompt for your admin password (or read from
SFTPGW_PASSWORDenvironment variable) - Export a backup and create a rollback file
- Generate new keys
- Create and import the new key YAML
- Tell you to restart the Java service manually
After running the script, SSH into your server and restart the service:
sudo systemctl restart sftpgw-admin-api
Troubleshooting
Keys Don't Change After Import
The most common cause is forgetting to restart the Java service. The import updates the database, but the running service continues using keys loaded in memory until restarted.
Solution: Run sudo systemctl restart sftpgw-admin-api on the VM.
If you've restarted and keys still haven't changed, check the service logs:
sudo journalctl -u sftpgw-admin-api -n 50
Import Fails with "missing type id property 'version'"
The import YAML must include a version header at the very beginning.
Solution: Add these two lines at the start of your import file:
!<2022-05-05>
version: "2022-05-05"
Service Won't Start After Import
This usually indicates a problem with the YAML format (invalid syntax, missing keys, etc.).
Solution:
- Check logs:
sudo journalctl -u sftpgw-admin-api -n 100 - Roll back using your pre-rotation backup
- Review the import YAML for syntax errors and try again
Authentication Fails
API authentication requires both client credentials AND admin credentials:
Get client credentials from the server:
ssh -p 2222 ec2-user@your-server "sudo grep 'security.client' /opt/sftpgw/application.properties"Use Basic Auth with client-id:client-secret, plus form data with admin credentials:
curl -X POST "https://your-server/backend/login" \ -u "CLIENT_ID:CLIENT_SECRET" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=password&username=ADMIN&password=PASS&scope=read"URL-encode special characters in the password (e.g.,
!becomes%21)
For older versions (pre-3.5.0), use /backend/oauth/token instead of /backend/login.
Clients Get "Host Key Verification Failed"
This is expected behavior after rotation. Clients that previously connected have the old fingerprint cached in their known_hosts file.
Solution for clients:
# Remove the old key
ssh-keygen -R your-sftpgw.example.com
# Add the new key
ssh-keyscan your-sftpgw.example.com >> ~/.ssh/known_hosts
Or simply accept the new key when prompted on the next connection.
Client Notification Template
After successfully rotating keys, notify your users so they're not alarmed by host key warnings. Here's a template you can customize:
Subject: SFTP Host Key Change - Action Required
The SSH host keys for sftp.example.com have been rotated as part of
our security maintenance procedures.
On your next connection, you may see a warning about the host key
changing. This is expected behavior.
To update your known_hosts file, run:
ssh-keygen -R sftp.example.com
ssh-keyscan sftp.example.com >> ~/.ssh/known_hosts
Or simply accept the new key when prompted on your next connection.
New fingerprint (ED25519): SHA256:xxxxxxxxxxxx
If you have questions or concerns, contact support@example.com
Summary
Host key rotation on SFTP Gateway requires updating the database through the backup/restore API, then restarting the Java service. The key steps are:
- Backup first - Always create a rollback artifact before making changes
- Generate locally - Create new keys on your workstation, not the server
- Import via API - Use the backup import endpoint to update the database
- Restart service - The Java service must restart to load new keys
- Verify and notify - Confirm new fingerprints and inform your users
Keep your rollback files in a secure location. If you ever need to restore the original keys, you'll be glad you have them.