Quickstart: msh

This guide installs msh — the Mezite client CLI — on a developer laptop and walks you through logging in, listing nodes, opening an SSH session, and copying a file with msh scp. By the end you will be SSHing into the node you brought online in the mezd quickstart without ever opening an inbound port on it.

It should take under five minutes once your hub is running and the node is online.

msh is the end-user CLI (think tsh in Teleport). For admin tasks — creating users, roles, tokens, or certificate authorities — use mezctl instead.

Prerequisites

  • A managed hub from the Managed mezhub quickstart (you should have a hub hostname like acme.hub.mezite.com and the initial admin password)
  • At least one node online from the mezd quickstart — confirm it appears as online in mezctl nodes ls before continuing
  • A workstation running Linux (x86_64 or arm64) or macOS (x86_64 or arm64)
  • Outbound TCP/443 from your workstation to your hub host — the laptop dials the hub directly, the hub never dials back

Step 1: Install msh

Grab the latest msh release for your platform. See Installation for the canonical download URLs and checksums; the snippets below assume you have already pulled the tarball for your platform and extracted the msh binary.

Linux

Install msh on Linux bash
# After downloading and extracting the release tarball:
sudo mv msh /usr/local/bin/msh
sudo chmod +x /usr/local/bin/msh

msh --help

macOS

The macOS binary is currently unsigned, so the first time you run it Gatekeeper will quarantine it. Strip the quarantine attribute after you drop it in place, then verify the install:

Install msh on macOS bash
# After downloading and extracting the release tarball:
sudo mv msh /usr/local/bin/msh
sudo chmod +x /usr/local/bin/msh

# Clear the Gatekeeper quarantine attribute (unsigned binary):
sudo xattr -d com.apple.quarantine /usr/local/bin/msh

msh --help

Step 2: Log In

Point msh at your hub on port 443 — the managed hub multiplexes the gRPC auth service and the SSH proxy over a single TLS port via ALPN, so there is only ever one address to remember. Use the same MEZITE_AUTH_SERVER shell variable convention from the Managed mezhub quickstart so your shell carries over:

Log in to the managed hub bash
export MEZITE_AUTH_SERVER=<your-hub-host>:443
export MEZITE_ADMIN_PASSWORD='<initial-admin-password>'

msh login \
  --proxy="$MEZITE_AUTH_SERVER" \
  --user=admin \
  --password="$MEZITE_ADMIN_PASSWORD"

A successful login writes a short-lived SSH certificate and the matching private key to ~/.mezite/; subsequent msh commands pick those up automatically. Confirm the session is healthy:

Check login status bash
msh status

# Output:
# Cluster:     acme.hub.mezite.com
# Proxy:       acme.hub.mezite.com:443
# User:        admin
# Roles:       admin
# Valid until: 2026-05-18 09:00:00 UTC (11h59m59s remaining)

Step 3: List Nodes

msh ls shows every node your certificate can reach. The output is five tab-aligned columns:

List reachable nodes bash
msh ls

# Output:
# HOSTNAME  ROLE  STATUS  LABELS             VERSION
# web-01    node  online  env=prod,role=web  0.1.0

If your node is missing from the list, check that mezd is still running on the host and that mezctl nodes ls reports it as online from the admin shell.


Step 4: SSH to a Node

The form is msh ssh [flags] <hostname> [-- command...]. Use --login to pick the remote Unix user — for the default admin role, root is allowed:

Open an interactive SSH session bash
msh ssh --login=root web-01

Want to run a one-shot command instead of dropping into a shell? Put it after --:

Run a single remote command bash
msh ssh --login=root web-01 -- whoami

# Output:
# root
The login user must be allowed by your Mezite role. The default admin role grants root and a handful of common system users out of the box. If you assign a non-admin user a role that does not include the login you ask for, the SSH handshake will fail with a clear permission error. See the RBAC Guide for adding logins to a role.

Step 5: Copy a File with msh scp

msh scp mirrors scp: msh scp <src> <dst>, with the remote side written as user@host:path. The round trip below uploads a file, downloads it back to a new path, and diffs the two copies to confirm bytes survived:

Upload, download, and diff bash
echo "hello from msh" > /tmp/msh-hello.txt

# Upload
msh scp /tmp/msh-hello.txt root@web-01:/tmp/msh-hello.txt

# Download back to a new path
msh scp root@web-01:/tmp/msh-hello.txt /tmp/msh-hello.roundtrip.txt

# Confirm the round-trip was byte-exact
diff /tmp/msh-hello.txt /tmp/msh-hello.roundtrip.txt && echo "round trip OK"

Use -r to recursively copy a directory. Both upload and download go through the same proxy tunnel msh ssh uses, so no extra ports or firewall rules are needed.


Step 6: Log Out

When you are done, drop your local certificates with msh logout. This removes the profile directory under ~/.mezite/ — you will need to msh login again to use the cluster.

Log out bash
msh logout

# Output:
# Logged out from <cluster-name>

What Just Happened?

  1. msh login authenticated against the hub's gRPC auth service over TLS (multiplexed by ALPN onto port 443), generated an SSH keypair locally, and received a short-lived SSH certificate signed by the hub's User CA. The private key and certificate live in ~/.mezite/ and expire automatically.
  2. msh ls asked the hub for the cluster's node list and printed every node back to you. RBAC is enforced at SSH-connect time — the proxy rejects connections to nodes your role does not allow, even if you can see them in the list.
  3. msh ssh opened a connection to the proxy, which forwarded the session through the reverse tunnel mezd is holding open from the node back to the hub. There is no inbound listener on the node.
  4. msh scp opened the same kind of tunnelled SSH connection and ran SFTP over it, so file transfers traverse the same audited, certificate-authenticated path as interactive sessions.

Next Steps

You now have a working end-to-end SSH path — admin login, node online, laptop logged in, SSH and SCP working. The next step is usually adding a real user with a non-admin role:

Create a non-admin user with SSH access bash
mezctl \
  --auth-server="$MEZITE_AUTH_SERVER" \
  --token="$MEZITE_TOKEN" \
  users create alice --roles=ssh-access
  • RBAC Guide — define which users can reach which nodes, and which Unix logins they are allowed to assume.
  • SSO Guide — replace --user/--password with OIDC, SAML, LDAP, or GitHub OAuth so users log in through your identity provider.
  • Session Recording — capture every interactive SSH session for audit and replay.
  • msh Reference — the full command surface, including hardware-key login, identity-file export, and session invitations.