# SSH access and terminal

> Give hosting accounts a sandboxed shell over SSH and in the browser, sign in with SSH keys, and run git, rsync, Composer or WP-CLI inside the account's home directory.

Source: https://zopanel.net/docs/ssh-terminal  
Updated: 2026-10-09

Hosting accounts can get a command-line shell for git, rsync, Composer, WP-CLI and similar tools, either over SSH from your computer or in the panel's **Terminal**. Both open the same sandbox: the account sees only its own home directory, the rest of the system is read-only, and the package's CPU, memory and process limits apply. Accounts without shell access keep chrooted SFTP for file transfers.

## Enable shell access

Shell access is a package option.

1. Open **Packages** and edit the account's package (administrators, or resellers for their own packages).
2. Turn on **Terminal** ("Sandboxed shell in the browser and over SSH (git, rsync, composer); home directory only").
3. Save. Every account on the package gets SSH shell access and the **Terminal** menu item.

| Package options | SSH sign-in gives |
| --- | --- |
| **SFTP** on, **Terminal** off | SFTP only, chrooted to the home directory. Shell commands are refused. |
| **Terminal** on | The sandboxed shell, plus SFTP, scp, rsync and git over SSH in the same sandbox. |
| Both off | No SSH access. |

A reseller can only turn on **Terminal** in a package when the reseller's own package includes it. See [Packages and limits](/docs/packages-limits).

## Connection details

| Setting | Value |
| --- | --- |
| Host | The panel domain, or the server's IP address |
| Port | The server's SSH port (usually 22) |
| Username | The hosting account name |
| Password | The account's SFTP password, or an SSH key (below) |

```bash
ssh alice@server.example.com
```

Signing in to the panel with a new password does not change the SSH password: **My account → Change password** only changes the panel password.

## Add an SSH key

Keys are safer than passwords. Add them while signed in to the panel as the hosting account itself:

1. On your computer, create a key if you do not have one:

   ```bash
   ssh-keygen -t ed25519 -C "you@laptop"
   cat ~/.ssh/id_ed25519.pub
   ```

2. In the panel, open **My account** and find **SFTP & SSH keys**.
3. Paste the public key (one per line) and click **Add key**.
4. Connect once with the key. Compare the fingerprint your client shows with **Server fingerprints (check on first connection)** on the card.
5. When the key works, turn on **Keys only** to disable password sign-in for the account.

Administrators can also add or remove an account's keys and switch **Keys only** for it: open **Accounts**, edit the account, and use the **SFTP & SSH keys** card in the dialog.

Accepted keys: Ed25519, ECDSA (P-256, P-384, P-521), RSA of at least 2048 bits and security keys (`sk-ssh-ed25519@openssh.com`, `sk-ecdsa-sha2-nistp256@openssh.com`). An account can have up to 50 keys.

Keys are stored by ZoPanel outside the home directory, so `~/.ssh/authorized_keys` in the account has no effect. This way, a hacked website cannot add its own key. Keys added in the panel are restricted: port, agent and X11 forwarding are off. On an account with **Terminal** on, signing in with a key opens the same interactive shell as the password, and keys also work for commands, SFTP, scp, rsync and git.

## What the shell can do

The shell starts in `/home/<account>` with bash:

| Item | Value |
| --- | --- |
| Working directory | `/home/<account>` (your `domains/`, `backups/`, `logs/` and `tmp/` are here) |
| `$HOME` | `/home/<account>/.home`, a private folder for `.ssh`, `.gitconfig` and tool caches. `~` refers to this folder, so use full paths such as `/home/alice/domains/…`. |
| `PATH` | The newest installed Node.js, then `/usr/local/bin`, `/usr/bin`, `/bin` |

Available tools include:

- `git`, `rsync`, `curl`, `zip`, `unzip` and `tar`;
- `php` and versioned binaries such as `php8.3`;
- `wp` (WP-CLI) and `composer` (when Composer is installed under **Runtimes**);
- `node`, `npm`, `pnpm` and `yarn` (when Node.js is installed under **Runtimes**);
- the `mysql` client for the account's MariaDB databases.

Examples:

```bash
# WordPress: list plugins with the site's PHP version
cd /home/alice/domains/example.com/public_html
php8.3 /usr/local/bin/wp plugin list

# Laravel: install dependencies and migrate
cd /home/alice/domains/example.com/public_html
composer install --no-dev --optimize-autoloader
php8.3 artisan migrate --force

# Import a database dump
mysql -u alice_shop -p alice_shop < /home/alice/backups/db/shop.sql
```

To clone a private repository, create a key in the shell with `ssh-keygen -t ed25519` (it is saved in `~/.ssh`, inside `.home`) and add its public key as a deploy key on GitHub or GitLab.

### Limits of the sandbox

- Only the account's own home directory is visible under `/home`. Other accounts do not exist for the shell.
- Everything outside the home directory is read-only. `/tmp` is private to the session.
- No `sudo`, no setuid programs, no change of user. Packages cannot be installed with `apt`.
- No port or agent forwarding: tunnels to the database or other local services are refused. Use [remote access](/docs/databases#remote-access) for databases.
- CPU, memory and process limits of the package apply. A command that exceeds the memory limit is stopped inside the account.
- Processes end when the session closes. For recurring work use [Cron jobs](/docs/cron-jobs); for a service that keeps running use an app website (see [Node.js and Python apps](/docs/apps-node-python)).
- At most 8 SSH sessions per account at once.

## Transfer files over SSH

With **Terminal** on, SFTP, scp and rsync run in the same sandbox. Paths are the real ones (`/home/alice/domains/…`), not the chrooted ones (`/domains/…`) that SFTP-only accounts see.

```bash
# Upload a folder, deleting files that no longer exist locally
rsync -avz --delete ./site/ alice@server.example.com:/home/alice/domains/example.com/public_html/

# Copy a single file
scp backup.sql.gz alice@server.example.com:/home/alice/backups/
```

For SFTP clients such as FileZilla or WinSCP, see [FTP and SFTP](/docs/ftp-sftp).

## Browser terminal

1. Click **Terminal** in the menu. It appears for customers whose package includes **Terminal**, for resellers whose own package includes it, and for full administrators.
2. Administrators and resellers with several accounts: choose the account in the list.
3. Click **Connect**. The badge shows **Connected**.
4. Click **Disconnect** when you are done.

Before running a command that looks destructive (for example a recursive delete of the home directory, dropping a whole database or killing every process), the terminal asks for confirmation in **Potentially destructive command**. Click **Run anyway** only if you mean it. Pasted text with several lines is checked the same way.

A session closes after 30 minutes without input, after 8 hours in all, when you sign out or change your password, and when the account is suspended. Opening and closing a terminal is recorded in the activity log with the session's duration.

Administrators can open the shell of any hosting account, even when its package does not include **Terminal**.

## The server's root shell

The panel never opens a root shell, not even for full administrators. A root shell from the web process would turn any bug in the panel into full control of the server. Administrators sign in with SSH:

```bash
ssh root@your-server
```

For panel tasks from that shell (reset a password, turn off 2FA, allow an IP), see [Command-line tool](/docs/cli).

## Troubleshooting

| Message or symptom | What to do |
| --- | --- |
| "shell access is not included in this account's package" | The package does not include **Terminal**. Turn it on, or use SFTP. |
| "terminal access is not included in this package" | Same, for the browser terminal. |
| "the server's root shell is not available in the panel; sign in with SSH" | Expected: use `ssh root@your-server`. |
| "account suspended" | The account is suspended. Resume it first. |
| "too many SSH sessions at once" | 8 sessions are already open for the account. Close some. |
| "The shell service is not available right now." | The ZoPanel agent is not running. Administrators: check `systemctl status zopanel-agent` as root. |
| "Permission denied (publickey,password)" | Check the username and password, or that the key is listed under **SFTP & SSH keys**. With **Keys only** on, passwords are refused. After 5 failures in 10 minutes, Fail2ban bans the IP for 1 hour. |
| "Read-only file system" | You are writing outside the home directory. Work in `/home/<account>`. |
| `~/domains` not found | `~` is `/home/<account>/.home` in the shell. Use `/home/<account>/domains`. |
| "unsupported key type" / "RSA keys must have at least 2048 bits" | Create an Ed25519 key: `ssh-keygen -t ed25519`. |
| "add a key before turning password login off" | **Keys only** needs at least one key. |
| The **SFTP & SSH keys** card is missing | Sign in as the hosting account itself (administrators: edit the account under **Accounts**). Website members and accounts without hosting space have no keys. |
| A background process stopped after logout | Sessions end their processes. Use a cron job or an app website. |

## Related

- [FTP and SFTP](/docs/ftp-sftp)
- [File Manager](/docs/file-manager)
- [Cron jobs](/docs/cron-jobs)
- [Packages and limits](/docs/packages-limits)
- [Security](/docs/security)
- [OpenSSH manual](https://man.openbsd.org/ssh) and [WP-CLI commands](https://developer.wordpress.org/cli/commands/)
