Guide

How to SSH into an EC2 instance from your phone (iPhone or Android)

You need four things: the instance's public DNS name, the right default username for its AMI, the private key imported into a mobile SSH app, and a security group that lets your phone's current IP reach port 22. The username and the security group are what actually break.

CC Chen Chen· Founder·2026-08-01·9 min read

The short answer {#short-answer}

To SSH into an EC2 instance from an iPhone or Android phone you need four things lined up:

  1. The host — the instance’s public IPv4 address or public DNS name (ec2-…​.compute.amazonaws.com), from the EC2 console’s instance details.
  2. The username — determined by the AMI, not by AWS. ec2-user for Amazon Linux, ubuntu for Ubuntu, admin for Debian.
  3. The private key — the .pem you downloaded at launch, imported into your mobile SSH client.
  4. A security group rule allowing TCP 22 inbound from wherever your phone currently is.

Then open your SSH app, add a host with those values, and connect. That’s the whole procedure — maybe ninety seconds of typing.

What people actually get stuck on is items 2 and 4. The wrong username produces Permission denied (publickey), which reads like a key problem and sends people off re-downloading keys for an hour. And a security group scoped to “My IP” — the console’s default suggestion — is pinned to your laptop’s home address, which is not the address your phone is using on LTE. The rest of this guide is mostly about those two.

The four things you need {#four-things}

Everything you need is on one page in the EC2 console: Instances → click the instance → Details.

WhatWhere it comes fromCommon gotcha
Public IPv4 / public DNSInstance details panelChanges on every stop/start unless you attach an Elastic IP
UsernameThe AMI you launchedNot shown in the console — you have to know your AMI
Private key (.pem)Downloaded once, at launchAWS does not keep a copy. Lost is lost
Port 22 inboundSecurity group → Inbound rules”My IP” pins it to one address

Two things worth knowing up front, because they bite later:

The .pem is downloadable exactly once. When you create a key pair, AWS hands you the private key in the browser and then forgets it. There is no “download again” button. If you’ve lost it, skip to when you don’t have the .pem.

The public IPv4 address is not stable. Stop an instance and start it again and you get a different address — the SSH host you saved on your phone silently points at nothing, or worse, at somebody else’s instance, which is why you’d then get a host key warning. Attach an Elastic IP or point a DNS record at the instance if you’re going to connect from a saved profile. (AWS bills public IPv4 addresses by the hour now, so this is a small ongoing cost rather than free — check current pricing for the exact rate.)

Getting the key onto your phone {#key-onto-phone}

This is the step with no obvious right answer, so people do the wrong one: they email the .pem to themselves. Now your production server’s private key lives permanently in two mail providers’ storage, indexed and searchable. Don’t.

Reasonable ways to move a .pem to a phone:

  • AirDrop (iPhone, from a Mac) — direct, no intermediary, nothing left behind on a server.
  • A password manager — 1Password, Bitwarden and friends all take file attachments or secure notes. This is the best option if you want to keep the key around for re-import later.
  • Copy the text and paste it into the app — most mobile SSH clients accept a pasted key body. Clear the clipboard afterwards.
  • A local file transfer to the SSH app’s own document storage.

Whatever you use, delete the intermediate copy once the key is imported. A key sitting in your Files app’s Downloads folder is a key that goes wherever that folder syncs.

The better approach: don’t move the key at all

There is a cleaner setup, and if you’re doing this for anything you care about, do this instead:

  1. Generate a new key pair on the phone, inside your SSH app. On iOS this can be a hardware-backed key that never leaves the Secure Enclave and requires Face ID for each use — it physically cannot be copied off the device, which a .pem obviously can.
  2. Copy the public half (the ssh-ed25519 AAAA… line) out of the app.
  3. Append it to ~/.ssh/authorized_keys on the instance, from your laptop, on a connection you already have working.

Now the phone has its own credential. If the phone is lost, you delete one line from authorized_keys and nothing else changes. If you’d moved the .pem, you’d be rotating the key everywhere.

The AWS key pair injected at launch is only ever written into authorized_keys once, at first boot — nothing stops you adding more keys to that file afterwards. You can also import a public key you generated yourself into AWS as a key pair (ImportKeyPair) so future instances launch with it. EC2 supports ED25519 as well as RSA key pairs for Linux instances.

The username is the #1 reason it fails {#username}

AWS does not have a universal SSH username. Each AMI vendor picks one, and the console does not tell you which.

AMIDefault username
Amazon Linux (all versions, incl. AL2023)ec2-user
Ubuntuubuntu
Debianadmin
RHELec2-user or root
CentOScentos or ec2-user
Fedorafedora or ec2-user
SUSEec2-user or root
Oracle Linuxec2-user
FreeBSDec2-user
Bitnami imagesbitnami

For anything not on this list, ask the AMI provider — a custom or marketplace AMI can use whatever its builder chose.

The failure mode is nasty because it is indistinguishable from a broken key: you get

Permission denied (publickey)

That message means the server rejected every key you offered for the account you named. Your key is probably fine; you asked for the wrong account. root@ fails this way on nearly every modern AMI, since direct root login is disabled by design and the injected key belongs to the unprivileged default user.

Before you touch the key, try the other username. It costs ten seconds and resolves this more often than anything else.

If you want the server’s own account of what happened, connect verbosely from a desktop with ssh -vvv and read what it says about Offering public key and the server’s reply — mobile clients rarely surface that level of detail.

Security groups vs. mobile IP addresses {#security-group}

Here is the part that makes EC2-from-a-phone different from EC2-from-a-laptop.

When you launch an instance, the console offers to create an inbound SSH rule scoped to “My IP”. It’s the security-conscious default and you should generally take it. But it captures the address of the browser you launched from — your home or office connection. Your phone is not on that connection. So:

  • On cellular, your phone comes from your carrier’s address pool. Different from your home IP, and typically shared and rotating under CGNAT — the address can change without you doing anything.
  • On someone else’s Wi-Fi, obviously different again.
  • Even on your own home Wi-Fi, your ISP may have rotated your address since you set the rule.

The symptom is a connection that just hangs and eventually times out, with no error message worth reading — because a security group drops disallowed packets rather than rejecting them, so your phone sits there waiting for a reply that will never come.

Your options, worst to best:

ApproachSecurityPractical on a phone
0.0.0.0/0 on port 22Poor — global scanner traffic, constant login attemptsAlways works
Carrier IP range allowlistMarginal — carrier ranges are huge and sharedFragile; ranges change
Update “My IP” each time from the phoneFine, but requires console access firstTedious, and impossible if you’re locked out of the console too
No public port 22 at all; reach it over a private networkBest — port 22 is unreachable from the internetWorks anywhere, no rule editing

If you do open 22 to the world, at minimum make sure password authentication is off (PasswordAuthentication no in /etc/ssh/sshd_config — it’s the default on AWS’s own AMIs) so the constant brute-force traffic has nothing to guess. Consider fail2ban to keep the log noise down. But recognize that this is mitigation, not a fix. The fix is further down.

Connecting, step by step {#connect}

With the pieces in hand:

  1. Copy the host. EC2 console → Instances → your instance → Public IPv4 DNS (ec2-…​.compute.amazonaws.com) or the public IPv4 address.
  2. Open your mobile SSH client and add a host.
    • Host: the DNS name or IP
    • Port: 22
    • Username: from the table above
    • Auth: the imported key, not a password
  3. Connect and accept the host key fingerprint. Your client will show you an unfamiliar fingerprint and ask whether to trust it — that’s TOFU, trust-on-first-use, and it’s the one moment where you’re vulnerable to being pointed at the wrong host. If you want to verify it properly, the real fingerprint is printed in the instance’s system log (Actions → Monitor and troubleshoot → Get system log) from first boot.
  4. You’re in. whoami should show the default user; sudo -i gets you root without a password on standard AMIs.

If you’re going to do this more than once, save the host as a profile. And if you use ~/.ssh/config on your laptop with entries like Host prod / HostName … / User ubuntu / IdentityFile …, note that the same information has to be entered into the mobile app separately — the phone doesn’t read your laptop’s config.

Doing real work once you’re in

The reason to have EC2 on your phone at all is the 11pm alert. Realistically that means:

# what's actually wrong
systemctl status nginx
journalctl -u myapp -n 100 --no-pager

# is it resources
df -h            # disk full is the single most common cause
free -m
top -b -n1 | head -20

# fix it
sudo systemctl restart myapp

Typing that on glass is the miserable part. This is where an SSH client with an AI assistant earns its place: you describe the situation in words, it proposes the command, and you read it and press run — or don’t. TermAI is deliberately assistant-style rather than agentic for exactly this reason: on a production box at 11pm, from a phone, with fat thumbs, “suggest and let me confirm” is the right amount of automation. Nothing executes because a model decided it should.

When you don’t have the .pem {#no-key}

AWS cannot re-issue a lost private key. But you are not necessarily locked out. Options, in rough order of how much they need from a phone:

SSM Session Manager. If the instance has the SSM agent running and an instance profile with AmazonSSMManagedInstanceCore, you can open a shell through the AWS console with no SSH key, no open port 22, and no public IP. This is the single most useful thing to set up before you need it. The console session works in a mobile browser, awkwardly.

EC2 Instance Connect. Pushes a temporary public key to the instance, valid for about a minute, authorized by IAM rather than by a key file. It requires the ec2-instance-connect package on the instance (preinstalled on recent Amazon Linux and Ubuntu images). From a laptop it’s aws ec2-instance-connect ssh --instance-id i-… --os-user ec2-user. From a phone, the CLI path isn’t realistic; the console’s browser client is the only mobile route.

EC2 Instance Connect Endpoint (EIC Endpoint). The 2023 addition that lets you reach instances that have only a private IP — no bastion, no public IPv4, no internet gateway path — with access controlled by IAM and every connection logged to CloudTrail. Excellent architecture, but again CLI-driven, so it’s a “set this up for your team” answer rather than a “rescue me from my phone” answer.

Detach and reattach the root volume. The last resort: stop the instance, detach its root EBS volume, attach it to a second instance you can reach, mount it, append a public key to home/<user>/.ssh/authorized_keys, reattach, boot. It works, it’s ugly, and it is not a phone procedure.

EC2 Serial Console. Direct console access for troubleshooting broken boots or a wrecked sshd config. It needs a password set for a user on the instance — it does not accept SSH keys — so it only helps if you set that up beforehand.

The pattern in all of these: the recovery mechanisms are things you enable before the outage. Turn on SSM on anything you might have to rescue from a phone.

The setup that actually survives being mobile {#tailscale}

Every problem above — rotating carrier IPs, security group edits, an SSH port exposed to the entire internet, public IPv4 charges — comes from the same root cause: you’re trying to reach the instance across the public internet, so the instance has to be publicly reachable.

Put the phone and the instance on the same private network instead:

  1. Install Tailscale on the EC2 instance (curl -fsSL https://tailscale.com/install.sh | sh, then sudo tailscale up). For a server, --ssh and an auth key are worth reading up on.
  2. Install Tailscale on the phone, same account.
  3. Remove the port 22 inbound rule from the security group entirely.
  4. Connect to the instance’s Tailscale address (100.x.y.z, or its MagicDNS name).

Now port 22 is closed to the internet, there’s nothing for scanners to find, your phone’s changing carrier IP is irrelevant because the connection isn’t identified by IP, and the instance doesn’t need a public IPv4 address at all. Access is revoked by removing a device from your tailnet rather than by editing key files.

The one thing to plan for: if Tailscale itself is down on the instance — bad update, network stack broken, disk full — you’ve removed your own way in. Keep SSM Session Manager enabled as the break-glass path. It goes through the SSM agent, not through your network, so it survives situations that kill SSH.

TermAI has Tailscale built in on both iOS and Android, so this is a toggle rather than a second app to juggle in the background. On stock iOS, running the Tailscale app alongside a separate SSH client also works fine — it’s just more moving parts.

Error messages, decoded {#errors}

What you seeWhat it meansFirst thing to try
Hangs, then times outPackets dropped — security group, NACL, or instance stoppedCheck the SG inbound rule against your phone’s current IP
Permission denied (publickey)Server rejected the key for that accountTry the correct username first, then the key
Connection refusedYou reached the host; nothing is listening on 22sshd is down, or it’s on a non-default port
Host key verification failedThe host key changedUsually a new instance on a recycled IP — verify before clearing
Connection closed by remote hostsshd accepted then dropped youOften a full disk or OOM on the instance
No matching host key typeClient and server disagree on algorithmsModern mobile clients rarely hit this; old RSA-SHA1-only servers do
Operation timed out on Wi-Fi but not cellular (or vice versa)Network-level filtering, or an SG rule matching only one of themCompare both networks’ public IPs

A useful discriminator: timeout vs. refused. A timeout means your packets never got a reply — a firewall problem, on AWS’s side or your network’s. Connection refused means the TCP handshake reached the machine and something said no — the instance is up and you have a service problem, not a network problem. Those lead to completely different investigations.

FAQ {#faq}

See the questions above for the short versions. Two more that come up:

Does the instance type matter? No. A t4g.nano and a c7i.metal accept SSH identically. What matters is the AMI (for the username) and the networking (for reachability).

Can I use SFTP to pull files off EC2 from my phone? Yes — SFTP runs over the same SSH connection and the same credentials, so if SSH works, SFTP works. It’s the sane way to grab a log file or a config off a box when you want to actually read it rather than squint at less on a phone screen.

Try TermAI

Free on iOS and Android. 5 AI requests/day on the free tier, plus unlimited SSH/SFTP and built-in Tailscale.

CC
Chen Chen — Founder of TermAI

Writes about mobile DevOps, terminal UX, and the surprising depth of "boring" infrastructure.

Was this useful? ← Back to blog