Infrastructure
| Component | Address | Notes |
|---|---|---|
| n8n server | 54.151.191.198 | Amazon Linux, runs as node user inside Docker |
| ev-prod-vpn | 18.139.20.216 | Ubuntu AMI, user: ubuntu, IP whitelisted by TNG |
| TNG SFTP | sftp.tngdigital.com.my:10086 | Retains files for ~30 days only |
Problem
TNG provides settlement reports via SFTP with IP whitelisting. The n8n server has no static IP. Solution: route through ev-prod-vpn (whitelisted jump host).
Key insight: Docker user context
n8n runs as the node user inside its container, not as ec2-user on the host. The container has its own isolated filesystem — /home/ec2-user/ doesn’t exist inside it.
When n8n executes an SSH command, it runs as node inside the container. The SSH client therefore looks for keys at node’s home directory: /home/node/.ssh/. A key placed at /home/ec2-user/.ssh/ on the EC2 host is invisible to it. See ssh-how-it-works.
- SSH keys must be in
/home/node/.ssh/(inside the container), not/home/ec2-user/.ssh/(on the host) - File paths must exist inside the container filesystem
docker cpis required to move files between host and container- ev-prod-vpn runs Ubuntu, so the SSH user is
ubuntu, notec2-user
Warning
ev-prod-vpn user is
ubuntu, notec2-user— Amazon Linux usesec2-userbut ev-prod-vpn runs Ubuntu. Using the wrong user causes silent SSH authentication failure.
Working solution
Transfer command (runs via SSH to ev-prod-vpn)
echo -e "cd {folder}\nget {filename} /tmp/{filename}\nbye" | \
sshpass -p '{password}' sftp -o StrictHostKeyChecking=no -P {port} {user}@{host} && \
scp /tmp/{filename} n8n:/tmp/{filename} && \
ssh n8n "docker cp /tmp/{filename} n8n:/home/node/.n8n-files/{filename}"Three steps in one command:
- SFTP download: TNG → ev-prod-vpn
/tmp/ - SCP: ev-prod-vpn
/tmp/→ n8n host/tmp/ docker cp: n8n host/tmp/→ n8n container/home/node/.n8n-files/
SSH host alias on ev-prod-vpn
# ~/.ssh/config on ev-prod-vpn
Host n8n
HostName 54.151.191.198
User ec2-user
IdentityFile ~/.ssh/vpn-to-n8n
Workflow nodes
Schedule (9 AM daily)
→ Set Variables (dates, paths, credentials)
→ SSH to ev-prod-vpn (3-step command above)
→ Read/Write Files from Disk (/home/node/.n8n-files/{filename})
→ Upload to Google Drive (TnG Settlements Shared Drive)
→ Delete Temporary File (docker exec rm)
SSH key persistence
The SSH key must be volume-mounted into the container — keys copied in via docker cp are lost on container restart.
-v /home/ec2-user/.ssh/n8n-key:/home/node/.ssh/id_rsa:roFull docker run is saved in ~/run_docker.sh on the n8n host.
Google Drive: Shared Drive, not My Drive
Service accounts created after April 15, 2025 have zero storage quota on personal My Drive. Files must be uploaded to a Shared Drive instead. Add the service account as a Contributor to the Shared Drive.
Turn off the “Impersonate a User” option in the n8n credential — it requires Domain-wide Delegation, which is not configured.
Warning
Post-April-2025 service accounts cannot upload to My Drive — use a Shared Drive and add the service account as Contributor.
What didn’t work
| Attempt | Failure |
|---|---|
n8n native SFTP node with ProxyJump | SFTP library doesn’t read ~/.ssh/config |
| SSH tunnel + n8n SFTP node | File path access issues across Docker/host boundary |
cat file to stdout | Encoding issues with large CSVs |
Read/Write Files from Disk reading /tmp | n8n 2.0 breaking change: file access restricted to /home/node/.n8n-files by default |
| Google service account uploading to My Drive | 403 Forbidden — zero Drive quota for post-April-2025 service accounts |
| ”Impersonate a User” in n8n credential | unauthorized_client — requires Domain-wide Delegation |
SSH key copied in via docker cp | Key lost on container restart — must be volume-mounted |
Warning
n8n 2.0 breaking change: file access restricted to
/home/node/.n8n-files—/tmpis no longer accessible from Read/Write Files from Disk. This can surface silently when a container is recreated and loses a previousN8N_RESTRICT_FILE_ACCESS_TOoverride.
Operational risks
- EC2 instance termination — Docker named volumes (
n8n_data,n8n_files) and the SSH key live on the instance’s local disk. A restart is safe (--restart=always), but termination loses everything including workflows, credentials, and keys. Consider regular EBS snapshots or AMI backups.