How a web terminal works
A web terminal is a terminal emulator drawn inside a web page, connected over a WebSocket to a process on the server. On the server side, that process usually owns a pseudo-terminal (a PTY) running a normal shell such as bash. What you type travels to the shell, and what the shell prints travels back to the page.
The consequence is simple and worth keeping in mind for the rest of this guide: a full web terminal is a shell on your server that anyone who gets past the login page can use. It is exactly as secure as that login page, the connection to it, and the network it is reachable from.
SSH solves the same problem with a dedicated protocol, and after decades of scrutiny it is the most battle-tested way to get a shell on a remote Linux machine. The question is not which one to use, but which one to use for what, and how to reach either safely.
Your options, from plain SSH to dashboards
- Plain SSH. Every Linux distribution ships an SSH server, and macOS, Linux, and Windows 10 and later include the client. On a phone, apps such as Termius or Blink Shell do the same. It gives you a full shell, sudo, editors, and file transfer with scp or sftp.
- Tailscale SSH. If the server is on your tailnet, Tailscale can handle SSH authentication with your tailnet identity instead of keys you manage yourself.
- Cockpit. A web admin console for Linux from the Red Hat ecosystem, packaged in Debian and Ubuntu. It includes a full terminal, plus services, logs, storage, and updates, on port 9090.
- ttyd and Wetty. Small tools that expose a terminal in the browser and nothing else. Useful when you only want the shell, but you have to put authentication and HTTPS in front of them yourself.
- Dashboard terminals. Server dashboards include a terminal next to their other tools. Portainer and Dockge open a console inside a container. Homeio's terminal runs maintenance commands on the server itself, described in detail below.
Most people end up with two: SSH for real administration, and a browser terminal for quick checks from whatever device is at hand.
What Homeio's terminal can and can't do
Homeio's terminal, in the current release, is not a full shell. It runs one allowlisted command at a time: ls, cd, pwd, cat, echo, whoami, hostname, uname, uptime, df, free, docker, ping, ip, date, history, help, clear, and exit.
- Commands run without a shell, so pipes (
|), redirects (>),&&, and variables don't work. - Nothing interactive: no
vim,nano,htop, ortop, and nosudopassword prompts. - Each command has a 12-second timeout, so long-running jobs belong somewhere else.
Within those limits it covers the most common checks: df -h when the disk looks full, docker ps and docker logs when an app is down, docker restart to bring it back, ping and ip addr when the network misbehaves, and cat to read a config file. For editing files, Homeio's file manager has a code editor built in, which is a better tool for the job than a terminal editor over a browser anyway.
The allowlist keeps the terminal to maintenance jobs and prevents most accidents. It is not a security sandbox: docker is on the list, and anyone who can run docker commands can take over the host. Protect Homeio's login the way you would protect SSH.
A five-command check when an app is down
Most "my app stopped working" moments on a home server have one of four causes: the container crashed, the disk is full, memory ran out, or the network is down. These commands check all four in under a minute, and every one of them runs in Homeio's terminal as well as over SSH:
docker ps -a
docker logs --tail 50 immich_server
df -h
free -h
ping -c 3 1.1.1.1- 1.
docker ps -ashows whether the container is running, restarting in a loop, or exited, and with which exit code. - 2.
docker logs --tail 50shows the last thing the app said before it stopped. Replaceimmich_serverwith your container's name. - 3.
df -hcatches a full disk, the most common silent cause: databases stop writing and apps fail in confusing ways. Look for any filesystem at 100%. - 4.
free -hshows whether memory, and swap, is exhausted. - 5.
ping -c 3 1.1.1.1tells you whether the server can reach the internet at all, which rules the network in or out.
If the cause was temporary, docker restart followed by the container name brings the app back. If it crashes again, the logs from step two are what to search for or paste into a forum post.
When to reach for SSH instead
Keep SSH set up even if you mostly use a dashboard. You will need it for:
- Anything with
sudo: system updates withapt upgrade, installing packages, editing files outside your own folders. - Interactive programs: editors,
htop,btop,lazydocker, database shells. - Long jobs, such as a large
rsyncor a first backup, ideally insidetmuxso they survive a dropped connection. - Recovery. When the dashboard itself is down, SSH is how you get back in to find out why.
If you want a full terminal in the browser
When you want a complete shell in a browser tab, with sudo and interactive programs, Cockpit is the easiest well-maintained option on Debian and Ubuntu:
sudo apt install cockpitOpen https://your-server-ip:9090 and sign in with your normal Linux user; the Terminal page is a real shell. Accept the self-signed certificate warning on first visit, and reach Cockpit only from your home network or over a VPN, never through a forwarded port.
For long jobs in any terminal, browser or SSH, start them inside tmux so a closed tab or a dropped connection doesn't kill them:
tmux new -s backup # start a named session
# run the long command, then press Ctrl+B, then D to detach
tmux attach -t backup # reconnect later, from any terminalSet up SSH keys and turn off passwords
Password logins are the reason SSH servers get brute-forced. Keys are both safer and more convenient. On your laptop, create a key and copy it to the server:
ssh-keygen -t ed25519 -C "laptop"
ssh-copy-id you@your-server-ipLog in once with the key to confirm it works. Then, on the server, turn off password and root logins with a drop-in file, which survives package updates better than editing the main config:
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin nosudo sshd -t && sudo systemctl restart sshKeep your current session open and test a new login from a second terminal before you close it. If something is wrong, the open session is how you fix it without walking to the server with a keyboard.
Reach it from outside without opening ports
Forwarding port 22, or the port of any web terminal, from your router to the server puts a login prompt on the public internet, where it will be probed within hours. There are better ways to reach home:
- A mesh VPN such as Tailscale, or plain WireGuard. Your phone and laptop join a private network with the server, and SSH, dashboards, and apps work as if you were at home. Nothing is exposed publicly. Homeio can install and activate Tailscale from its Settings.
- A tunnel with an access policy, such as Cloudflare Tunnel with Cloudflare Access, for browser-based tools you want to reach without a VPN client. Put the identity check in front of the tunnel, not just the app's own login.
Whatever the route, turn on two-factor login for any web interface that can run commands on the server. Homeio supports TOTP codes from any authenticator app, with backup codes, under Settings, Users & Access.
