Reference
The detail behind every command: the limits, the edge cases and the reasons. How it works is the short version; this is the page to read when something surprises you.
All of it is also in the session. help lists the commands
and help <command> prints the same detail you will
find here, generated from the code that enforces it — so if this
page and your terminal ever disagree, the terminal is right and we want
to hear about it.
The model
Three facts, and the rest follows from them.
- Your SSH key is the account. No password, no session, no API token, and no recovery.
- SSH is the control plane. Every operation is a command over the connection you already have.
- The address is the resource. One public IPv4, yours while you pay for it. It can serve files we hold, or route to a machine of your own, and it can move between the two as often as you like.
The user name is ignored, because the key is what identifies you.
ssh 185.104.32.x versions and
ssh anyone@185.104.32.x versions are the same command.
Two words, used precisely. The address is the resource — one public IPv4, the thing you are paying for. A pod is that address and everything attached to it: your files, releases, domains, keys and settings. So an address is what you own and a pod is what you operate. In the same spirit a pod is terminated and an account is closed, and if you have one pod, terminating it does both.
Connecting
Your key is your account, so the first thing worth checking is who you are handing it to. Every kikopod endpoint presents the same host key:
ED25519 SHA256:OgrPY5flSzqJnOT1iyftrRyJrmchXJFhDZYhds16ntg
That is what you get from get.kikopod.com during signup,
from your own address on port 22 afterwards, and from your pod’s
management port on pods.kikopod.com. Your client shows you
a fingerprint the first time it connects. Compare it with that line and
answer yes only if they match.
One thing that trips people up: port 22 of
pods.kikopod.com is our own machine rather than a customer
endpoint, and answers with a different key. On that host, always use
your pod’s port.
Keys
$ ssh 185.104.32.x keys $ ssh 185.104.32.x keys add "$(cat ~/.ssh/id_ed25519.pub)" $ ssh 185.104.32.x keys agent "ssh-ed25519 AAAA... claude" $ ssh 185.104.32.x keys rm SHA256:abc12345
A unique prefix of the fingerprint is enough to remove one. Up to 20 keys per pod.
There is no account recovery, and that is deliberate. An address that can be recovered by email is an address that can be taken by whoever reaches the inbox — so we do not accept a mailbox as proof of anything. The cost is real and worth stating plainly: if every key on a pod is lost, neither we nor anyone else can restore it. Register a second key from a different machine while you still have the first. That is the whole safety net, and it is the one thing on this page worth doing today rather than later.
health tells you which side of that
line you are on, so it is a thing you can check rather than a thing you
have to remember. We will not make you do it — a platform that
forces a backup key is a platform betting it knows your setup better
than you do — but we will not let it be invisible either.
Give an agent its own key, and make it an agent key. A script or
an AI agent should hold a key that is not yours, so it can be revoked on
its own without locking you out. keys agent registers one
that can do everything on the pod except manage keys and
terminate it, so you can always revoke it.
Four scopes, each a list of what it can do rather than what it cannot, so a command added later stays out of reach until somebody decides otherwise:
| Scope | Can |
|---|---|
keys addowner | Everything, including managing keys and terminating the pod. |
keys agent | Everything except those two, so you can always revoke it. It can still route the address to a machine of its own with wireguard — worth knowing before you hand one out. |
keys deploy | Publish and roll back, and read. Nothing that moves the domains, the reverse DNS or the address. For a CI job. |
keys read | Look, do not touch — not even deploying. For a monitor, or for giving somebody visibility without giving them the pod. |
Only an owner key is your spare. No other scope can add a key, so none
of them can let you back in, and keys does not count them
toward the second key that makes a lost laptop survivable.
Deploying
Three ways in, all of them the client program you already use. None of
these is typed as an ssh command:
$ sftp 185.104.32.x $ rsync -az ./public/ 185.104.32.x: $ git push 185.104.32.x:site HEAD:main
For git it is usually worth naming the remote once:
$ git remote add kikopod ssh://185.104.32.x/site $ git push kikopod HEAD:main
The path in that URL is ignored — there is one repository per pod
and we serve whatever you push to it, so /site is a label
rather than a location. We run nothing: the pushed tree is published as
it is, with no build step to configure or to break.
Every upload becomes a complete release rather than a diff, and it goes live only once all of it has arrived. A half-finished transfer cannot be served, and switching between releases is instant because each one is already whole.
Releases and rollback
$ ssh 185.104.32.x versions $ ssh 185.104.32.x rollback $ ssh 185.104.32.x rollback v2
The last 5 releases are kept and older ones are removed as you deploy, so history you will never roll back to does not quietly eat your disk. Rolling back deletes nothing: the release you rolled away from is still listed, so rolling forward again is just another rollback.
Kept releases count against your disk allowance. If a pod is fuller
than you expect, old releases are usually why —
versions before assuming your site grew.
What we check on upload
One thing, and it is worth knowing about before you meet it: every file you publish is hashed and compared against a list of known malware samples. If one matches, that version is not published — you are told which file and which hash, on the spot and by mail, and the version that was live stays live.
Nothing else about your pod changes, and the rejected upload is not
kept, so you can remove the file and deploy again. If you think we have
it wrong, say reaches a person.
It is a hash comparison, not a judgement about your content. We do not read your files, index them, or look at what your pages say. A match is a match against a public corpus of samples; there is no heuristic that can decide it dislikes your site.
It never refuses a deploy because of a problem at our end. If the corpus is empty, out of date, or unreadable, your upload publishes and we record that it went out unchecked. Refusing your work because a third party was down would be the worse failure. Rolling back is never checked either — that version already passed once, and a recovery path you cannot use when you need it is not a recovery path.
If you have a reason to serve samples — security research is a perfectly good use for an address of your own — ask and we will turn the check off for your pod.
Domains and HTTPS
# after the A record exists $ ssh 185.104.32.x domain add www.example.com $ ssh 185.104.32.x domain rm www.example.com
The A record is the proof. Point the name at your address first; we check that it really resolves there before serving it. On a shared host that would prove nothing, because a thousand sites answer on the same address. Here the address is yours alone, so a name aimed at it could only have been aimed by whoever controls its DNS — which is why there is no token to paste back.
One exception, and we tell you when you meet it. If this address served that same name for somebody else before you had it, their A record may still be pointing here, and a record someone forgot proves nothing about who owns the name today. For that name only, we also ask for a TXT record:
_kikopod.www.example.com. TXT "kikopod-verify=<token>"
The command prints the exact record. Leave the A record where it is — it is what routes the name here — and the TXT record can be deleted once the name is added. Every other name on your pod is the A record alone.
Certificates are issued on the first request to a name and renew themselves. Two things stop us holding one: removing the domain, and serving nothing on it. We will not obtain or renew a certificate for a name that we do not answer for, which means a name added while the web is off, or while the address is routed to your own machine, gets no certificate until we are serving it again.
Watch for a stale AAAA record. We are IPv4 only.
If the name still has an AAAA pointing at a host you used
before, visitors on IPv6 will reach that host and visitors on IPv4 will
reach your pod — which looks exactly like “works on my
phone, not on my laptop” and is miserable to diagnose. Remove it.
Up to 10 names per pod. Wildcards are not supported; add each hostname you want to serve.
Reverse DNS
$ ssh 185.104.32.x ptr $ ssh 185.104.32.x ptr mail.example.com $ ssh 185.104.32.x ptr clear
Reverse DNS is what your address answers when something asks who it is. Most hosting will not let you set it. Here it is yours, and it is forward-confirmed: the name must already have an A record pointing at your address before we will set the PTR, and we check. That is what mail servers and abuse desks actually test — a PTR that disagrees with the forward record is worth less than none.
The check happens when you set it. If you move that A record later the PTR stays as it is and quietly stops being confirmed, so move it back or set a new one.
WireGuard: the address on your own machine
$ ssh 185.104.32.x wireguard > /etc/wireguard/kikopod.conf $ wg-quick up kikopod $ wg-quick down kikopod
One command prints a config that routes your whole address to hardware you own — every port, TCP and UDP, inbound and outbound, through carrier NAT that no port forward can cross.
Only your address moves
The config carries traffic bound to your address and nothing else, so
the rest of that machine’s networking is untouched. You get a
public address, not a VPN that swallows everything. It is also why a
plain curl ifconfig.me will not show it:
$ curl --interface 185.104.32.x ifconfig.me
Configure a firewall first
This is the part to think about before running wg-quick up.
A machine behind carrier NAT is unreachable by accident; the same machine
with your address on it is on the public internet, and every service
listening on it may become reachable. That is the feature — it
is what makes a game server or a home server work — and it is also
how a printer, a database bound to 0.0.0.0 or a
development server ends up exposed. Set up the host’s own firewall
before you bring the tunnel up, not after.
The address follows the tunnel
Bring it up and the address is yours within a second. Take it down and we serve your files again a few minutes later. Neither needs telling us, and a config you generate but never bring up leaves your address exactly where it is.
What we watch is the WireGuard handshake, not your traffic. The config
we issue sets PersistentKeepalive = 25, so a tunnel that is
up handshakes about every two minutes whether or not anybody is using
it. If we see no handshake for three minutes we take the address
back to serving your files. In precise terms:
| Question | Answer |
|---|---|
| What counts | a WireGuard handshake from your peer, and nothing else |
| An idle server | stays up — keepalive handshakes on its own, with no traffic at all |
| Port scans, our own management traffic | do not count either way |
| A short internet outage | under three minutes, nothing happens |
| A longer one | the address comes home and serves your files until your tunnel handshakes again |
| Coming back | automatic and immediate: your peer stays configured, so the next handshake takes the address straight back |
| Open connections | break across the move, in both directions. Nothing can carry a TCP connection between two machines |
| A config never brought up | never moves the address at all |
| With your page turned off | none of the above: a quiet tunnel keeps the address. There is nothing for it to come home to, so we leave it with you until web on or wireguard off |
If you are running something that is not a website — a game
server, a mail server, anything where the address should simply stay on
your machine — turn the page off with web off. The
three-minute rule stops applying to you entirely: we take an address back
because we have your files to serve on it, and once you have said there
are none, there is no reason left. The address stays where you put it
through a reboot, a flaky link, or a machine switched off for a week.
Reaching us while the tunnel is up
While it is up we serve nothing on your address — every port of it
is yours, including 22. So your pod also has a port of its own on a
shared endpoint, which wireguard prints when it issues the
config:
$ ssh -p your-port pods.kikopod.com wireguard status $ ssh -p your-port pods.kikopod.com usage
That works from anywhere, including the machine running the tunnel — which matters, because on that machine your address is a local interface and packets you send to it never leave.
Down is not off
wg-quick down is the pause: the address comes home and
wg-quick up brings it back whenever you like.
wireguard off is the revocation. The config you were issued
stops working permanently and the key is forgotten. It is for a machine
you have lost or no longer trust, and it does not come back — you
would run wireguard again for a new config.
The private key in a config is generated here and never stored, so you see it once. To keep it entirely to yourself, make the pair on your own machine and give us only the public half:
$ wg genkey | tee privkey | wg pubkey | xargs -I{} ssh 185.104.32.x wireguard {}
Turning the page off
$ ssh 185.104.32.x web $ ssh 185.104.32.x web off $ ssh 185.104.32.x web on
Some addresses are bought for a game server, a tunnel, or just to have,
and never need a web page. With it off we answer nothing on 80 and 443
— the connection is closed rather than answered. Nothing is
deleted: your files, releases and domains stay exactly where they are,
and web on brings back the release that was live. While it
is off we hold no certificate for your names, for the same reason as
above: we do not certify what we do not serve.
It also changes what WireGuard does. Normally a
tunnel that goes quiet for a few minutes hands the address back to us,
because we have your files to put on it. With the page off there is
nothing to put there, so we stop taking it back — the address stays
on your machine until web on or wireguard off.
If the address is running something that is not a website, this is the
setting you want.
Terminating, and when your content stops existing
The address is the product, so what happens to it after you leave matters as much as what happens while you are here.
$ ssh 185.104.32.x terminate # what it will do, and how to confirm $ ssh 185.104.32.x terminate 185.104.32.x $ ssh 185.104.32.x reopen # within 7 days, undo all of it
Confirm by repeating the address. A pod is terminated; an account is closed — and if this is the only pod on your account, terminating it does both.
The whole sequence, with the durations the platform actually enforces:
| When | What happens |
|---|---|
| Immediately | The pod stops being served. The address is taken out of use and its reverse DNS is removed, in the same database transaction — so either all of it happened or none of it did. No new certificate is issued and none is renewed. |
| Within a minute | The edge configuration is rebuilt without your pod, and if the address was routed to your own machine over WireGuard, that route is withdrawn. |
| Any time in 7 days | reopen undoes all of it. A terminated pod still answers that one command, with the same key as before, and gives you back the address, your files and your releases. It answers nothing else. |
| 7 days | Your files are deleted from disk, and with them everything that identified the account: the SSH keys, the contact address, the stored WireGuard public key, and the hostnames attached to the pod. Nothing that reached your pod still exists in the live database after this, and reopen stops working. |
| 30 days | The address returns to the pool and can be allocated to somebody else. |
Your keys survive those seven days because they are what
reopen authenticates. Removing them sooner would take the
undo with them, and there is no account recovery to
fall back on.
Two things do not come back with a reopen: a reverse DNS
name you had chosen, and any custom domain you had added. Set them again
with ptr and domain add.
Backups are the honest exception. The platform keeps encrypted off-box backups so it can survive losing a machine, and your content is in them until they age out — up to about twelve months, on a schedule that keeps recent days densely and older months sparsely. Those backups are never served and are not consulted to answer a request; they exist to rebuild the platform. We would rather say this plainly than make a deletion promise that the recovery plan quietly breaks.
What stays after all of it is an account row with no keys, no address and no content — a billing and audit record, kept because deleting it would take the record of the teardown with it.
Limits
Everything below is enforced by the platform rather than by a policy we remember to apply.
| Limit | Value |
|---|---|
| Disk | 2 GB, enforced by the filesystem — a deploy that would exceed it fails rather than half arriving |
| Traffic | 1 TB a month, in and out together. Metered per address and shown by usage and health. We never bill for overage — there is no mechanism to |
| Releases kept | 5, oldest removed as you deploy; they count against the disk allowance |
| Domains | 10 per pod, no wildcards |
| SSH keys | 20 per pod, in four scopes |
say | 8 KB a message, 10 messages a day |
email | 5 confirmation mails and 3 different addresses a day |
Check your disk with ssh 185.104.32.x usage.
What we do not do
- Outbound port 25 is blocked. Your address cannot send mail directly; relay through an SMTP provider on 587 or 465. Receiving on 25 works. See Mail.
- IPv4 only. There is no IPv6 address and no
AAAArecord. See the warning under Domains. - No wildcard certificates or wildcard domains. Add each hostname.
- No build step. We publish the tree you push and run nothing of yours on our machine.
- No account recovery. Ever, by anyone. See Keys.
You can receive on port 25. You cannot send on it. Mail is the one place a dedicated address is deliberately not a general-purpose address, and the reason is the block: one spammer costs every other customer here the clean reputation they are paying for.
Receiving works when the address is routed to your own machine. Port 25 reaches it like any other port, so a pod behind WireGuard can be the MX for a domain and take delivery. Combined with the reverse DNS you set yourself, forward-confirmed, that is a real mail host.
Sending is refused. Outbound connections to port 25 from your address are dropped, so the machine behind your tunnel cannot deliver mail directly. Relay through a provider that will vouch for you — any of the usual SMTP services, on 587 or 465, which are open like every other port. That is how a mail server on a residential or hosting address should be sending anyway.
Ports 587 and 465 are not touched, and neither is anything else: this is one port, in one direction.
Health
$ ssh 185.104.32.x health
network 185.104.32.x — reachable, since this connection got here
web on, serving v7
tls issued on first request to each name, renewed automatically
disk 412 MB of 2.0 GB (20%)
traffic 183 GB of 1.0 TB this month, resets 1 Oct
wireguard off — no config issued
domains 2 serving
Everything this pod knows about itself, one line each, read from the thing being described rather than inferred. It is the answer to “is it me or you” from inside, and the counterpart to the status page, which answers it from outside.
A line that cannot be read says so instead of guessing. That is
the point of the command rather than a detail of it: one reporting
ok because a query failed is worse than no command at all,
because somebody believes it and stops looking. If several lines come
back unreadable at once, that is itself the finding, and it is ours.
Aliased as up and check.
usage is the longer form of the disk and traffic lines,
with the reasons a pod is fuller than you expect.
Is it us or you
status.kikopod.com, hosted somewhere that shares nothing with this platform so it can still be read when this platform cannot. It carries what a person has written about an incident, and links a monitor that probes from outside and updates itself. If the two disagree, believe the monitor about whether something is up and the page about what is being done.
Your own address tells you more than either. If it answers SSH, our daemon is running; if it serves your site, so is the edge. Those are independent of each other and of the page.
How we reach you
$ ssh 185.104.32.x email # what is on file $ ssh 185.104.32.x email you@example.com # set it; a code goes out $ ssh 185.104.32.x email 123456 # confirm it $ ssh 185.104.32.x email clear
Optional, and worth giving us. It is how you hear about the things you would want to hear about without being asked: one of your addresses turning up on a blocklist, your pod being suspended and why, planned maintenance. Without one, those reach you only when you next connect — which, for a pod that has stopped being served, may be a long time.
Confirming it proves the mailbox agreed to hear from us, which is why the code exists: otherwise anyone could point their pod at a stranger’s address and make this platform mail them.
It is never a way in. There is no login and no recovery by mail, and confirming an address does not make it a credential — anyone holding the pod’s key can change it, so it proves the mailbox agreed, not that the sender is you. See Keys for what actually protects an account.
Reaching us
Three routes, and it is worth knowing which is which:
| Route | For |
|---|---|
say | anything about your pod: a bug, a feature you want, a thing that confused you. This is support |
| hello@kikopod.com | questions from people who are not customers yet, and business matters |
| abuse@kikopod.com | reporting something hosted on one of our addresses |
$ ssh 185.104.32.x say "IPv6 would be useful"
Sent. It is message #41 and it reached a person, not a queue.
A message arrives already attached to your account and your address, because the key that sent it says who you are — nothing to prove and no ticket number to quote back at us. Your agent can send one with its own key. We read all of them; we cannot always reply.
← back