Receive files from the command line
Last updated: 2026-09-01
Sending is only half the story — sooner or later you're on the receiving end: a colleague wants to hand you a file across the internet, one of your own machines wants to hand off to another, or someone left you a stored link to fetch whenever you get to it. The Relayium CLI covers all three with a different command for each, and none of them need an account on the receiving side.
Pick receive when someone else sends by pairing code, serve when trusted machines push directly to a listener you manage, and down when the sender gave you a stored encrypted link and may already be offline.
Three ways to receive, and when each applies
Which command you run depends on who's starting the transfer and how the two machines know each other:
- relayium receive <code> [destdir] — someone sends to you across networks using a pairing code they minted (with the CLI, a Relayium app or the web page) and passed to you out of band. End-to-end encrypted, relayed whenever the server issues a relay for the code, with a SAS code you can compare.
- relayium serve [--dir D] [--port N] [--once] [--allow-delete] — this machine listens for daemon-direct relayium:// pushes, on port 9031 by default.
- relayium down <link> [destdir] — fetch and decrypt a stored link; no account is needed to download.
receive: someone sends you a file across networks
What you need before step 1
- The CLI on this machine. relayium version prints a version string; a shell that answers command not found means it is not installed here yet.
- A sender who is signed in and at their terminal right now. Only they need an account — you never sign in to receive.
- The six digits, passed to you out of band. They live five minutes from the moment their CLI minted them, so agree on the moment first.
- A way to read six more digits back to them afterwards: the SAS is compared out loud, not on screen.
- The other end can be relayium send or relayium pair, a Relayium app or the web page — any of them mints a code you can receive with.
This is the receiving half of relayium send. The other person runs relayium send <path> on their end (after relayium login); their CLI mints a 6-digit code, good for 5 minutes, and prints it. They tell you what it is over any channel you both trust — a call, a chat message. You run receive with that code:
relayium receive 483920
# or into a specific directory
relayium receive 483920 ./downloads
Agree with the sender on when they will run send. The code starts expiring the moment it is minted, not the moment you get it.
Take the six digits over a channel you both trust — a call, a chat window, the room you are both in.
Run receive from the directory where the files should land, or name one explicitly.
relayium receive 483920relayium receive 483920 ./downloadsWhen both terminals print a verification code, read yours aloud and check it matches theirs. It is not the pairing code, and it is the only thing that rules out a substituted endpoint.
Leave the terminal alone until it returns to the prompt. This is one live session: closing either end stops the transfer.
What a successful receive looks like
The path line says how the bytes travel — relay, or direct / lan for peer to peer — and both ends show the SAME verification code. Different codes are the one result you must not accept — stop and check with the sender which machine they are on.
$ relayium receive 483920
verification code (SAS): 271044 — not the pairing code; compare it on both ends to rule out a substituted endpoint
path: relay (selected pair …)- The connection is end-to-end encrypted; both ends print the same SAS (short authentication string) once connected. Compare it out of band to confirm that the keys the two ends exchanged were not substituted and the rendezvous service did not impersonate either endpoint. The SAS authenticates the endpoints; it does not prove every network hop.
- No destination given: files land in the current directory.
- Same relay rule as send: whenever the server issues a relay for the code, every byte goes through that encrypted relay and counts toward the monthly traffic allowance of the account that minted the code — the sender's, never yours — when the relay reports it as billable usage: the relay nodes Relayium operates do, while Relayium's coturn TURN servers bill nothing today — their legacy usage ingest is disabled, and their optional accounting ingest is off by default and, if configured in shadow mode, records measurements without writing to the billing ledger, usage periods or any allowance. Only when no relay is issued do the two ends connect peer to peer, and then the transfer fails if no direct path exists.
- The code is the same pairing code the apps and the web page use: a sender on relayium.com or in a Relayium app can read you a code and you receive it here, and a code minted by relayium send can be joined from the web page instead of the CLI.
- The receiver never needs an account, on any network. Only the sender signs in, so their CLI can mint the code.
serve: turn this machine into a listening drop box
serve works the other way around: instead of you reaching out, other machines push straight to you over relayium:// — built for machines you already trust, like your own laptop pushing to a NAS, or a build server dropping artifacts on a box you own — over a pinned TLS 1.3 connection, no SSH, no rendezvous.
relayium serve
# a specific directory, port, and allowing delete requests
relayium serve --dir ~/incoming --port 9031 --allow-delete
Start the listener, naming the directory pushes should land in.
relayium serve --dir ~/incomingWhen a new machine pushes for the first time, serve shows its address and fingerprint and asks. Approve it once and later pushes from that fingerprint go through silently.
If this listener will run without a terminal, do not rely on that prompt — nobody is there to answer it, and an unrecognised pusher is rejected outright. Pre-authorize instead, as the next section describes.
- The first time a new machine pushes to you, serve (running in a terminal) shows its address and fingerprint and asks you to approve it once; after that, pushes from the same fingerprint go through silently.
- Without a terminal — a systemd service, a script with no TTY — there's no one to ask, so an unrecognized pusher is rejected outright. Pre-authorize it instead, using the fingerprint the pusher prints with relayium id:
Pre-authorize for unattended serve
For a serve that runs unattended (systemd, a background script), have the pusher run relayium id to print its fingerprint, then approve it ahead of time from the receiving side:
relayium authorize <fingerprint>
- --dir sets where files land (default the current directory); --once accepts a single transfer and exits; --allow-delete lets an incoming --delete (mirror) request actually remove files here, and is off by default.
- --config-dir (default ~/.config/relayium) is where this host's identity and its authorized-fingerprints list live — override it if you're running serve as a dedicated service.
down: fetch a stored encrypted link
down retrieves ciphertext held by Relayium, decrypts it locally and verifies it before installing the output.
relayium down '<complete-link-with-#k-fragment>' ./local-dest
Copy the complete link, including its #k= fragment. That fragment holds the only decryption key and is never sent to Relayium's server.
relayium down '<complete-link-with-#k-fragment>' ./local-destChoose an existing writable destination directory, or create it before downloading.
mkdir -p ./local-destRun down with the complete link. The recipient does not sign in.
relayium down '<complete-link-with-#k-fragment>' ./local-dest
- The server receives the URL before # but never the fragment containing the decryption key.
- down reconnects and continues within the same invocation, up to five attempts. If that invocation ultimately fails, it deletes the partial output; a later run starts over.
- SSH destinations, relayium pull, -i and -p are retired in the current CLI.
When it doesn't work
Five failures cover nearly every unsuccessful receive. Which command you were running decides which of them applies, and each has a line to read or a command to run that settles it.
Symptom, check, fix
- You type the code and the rendezvous refuses it.
relayium receive 483920 # the rendezvous refuses the codeAlmost always the five minutes elapsed — the code expires from the moment the sender's CLI minted it, not from when you were told. Ask them to run send again and read you the fresh digits straight away. A mistyped digit looks identical from here, so re-read it back before assuming it lapsed.
- The transfer completes but you cannot find the files.
relayium receive 483920 ./downloadsWith no destination, receive writes into the directory you ran it from, which is rarely where you were looking. Pass one explicitly, or run pwd first and be sure.
- It prints "relay unavailable: …" and never connects.
relayium receive 483920 # relay unavailable: the pairing code owner's monthly relay allowance is used up; trying a direct connection only (no relay) — across strict NATs that may failThe server issued no relay for this code — the line names why, for example the sender's monthly allowance is used up — so the two ends tried peer to peer and could not reach each other. Ask the sender for a relayium up download link instead, or use daemon-direct between reachable machines you control. If it says "no direct connection to the peer" instead, the other end runs an older relayium whose pairing is direct-only: update it.
- down says the link is invalid or cannot decrypt the file.
relayium down '<link-without-fragment>' ./downloads # invalid link or missing keyCopy the whole link again, including #k=. The fragment is the only decryption key; the server cannot reconstruct it if it was omitted.
- A machine pushes to your serve listener and is rejected without ever prompting you.
relayium serve --dir ~/incomingThe prompt only exists when serve has a terminal. Under systemd, in a script, or behind a pipe there is nobody to ask, so an unknown fingerprint is refused outright. Have the pusher run relayium id and pre-authorize it here with relayium authorize <fingerprint>, using the same --config-dir the listener runs under.
Frequently asked questions
Do I need an account to receive files?
receive and serve need no account on your side, and down needs only the link. The sender signs in to mint a receive pairing code or create a stored link. Hosted storage consumes the sender's plan allowance, which is usage accounting rather than a per-transfer charge.
Does relayium receive interoperate with the browser's pairing code?
Yes. A current relayium and the apps and web page at relayium.com use the same pairing codes, so relayium receive can take a code a browser or app minted, and a browser can join a code relayium send minted. Only an older relayium CLI, or a server that predates pairing hints, falls back to the older CLI-only, direct-only pairing.
What happens if an unknown machine pushes to my serve listener?
In a terminal, you're prompted to approve it by address and fingerprint on its first push, and the approval is remembered. Without a terminal — a systemd service, a cron job — there's no one to ask, so an unrecognized pusher is rejected; pre-authorize it first with relayium authorize <fingerprint>.
Can I pull files from a server I administer?
Not with relayium pull: it and SSH transfers are retired in the current CLI. Run relayium serve on this machine and have the server push to it with relayium push relayium://this-host, or have the server upload with relayium up and fetch the link here with relayium down.
Where does relayium keep my identity and trusted peers?
In ~/.config/relayium by default — override the location with --config-dir on any command that touches identity or trust.
Ready to receive your first transfer? Install the CLI and pick receive, serve, or down.
Get the CLI