How ForestVPN works
A VPN moves your trust from your network to a server someone else runs, so you should be able to see how it works. This page follows one tap on Connect, from the ticket to the tunnel, and says plainly what we keep.
Open the film file (MP4, 32 MB). Use it if YouTube is blocked or slow on your connection.
On this page (10)
The short version
- Your traffic is sealed on your device and comes out of a server we run, the exit. Of ForestVPN's parts, the exit is the only one that sees where your traffic goes.
- Before you connect, your device gets a signed ticket. The ticket says which plan you have, and the service that checks it works separately from the one that holds your account.
- The app watches whether data really flows and switches road by itself when it stops. You only see the result.
- One row ties your device, and any linked account, to each session it pays for, for metering. It is deleted an hour after the session settles, or up to 17 days later for a ticket never used. This page shows it next to everything else.
What a VPN changes, and what it does not
A VPN is a transfer of trust. Without one, you trust your network and your internet provider with a view of where your traffic goes. With one, you trust the VPN instead. So the useful questions are the same for any VPN: where does your traffic end, what do the services in front of it know, and what does the app do on your device? This page answers them in that order, with the specifics behind each answer.
Without a VPN, your Wi-Fi and your internet provider can see which servers your device talks to, and every site you reach sees the address your network gave you. With ForestVPN they see encrypted traffic to our servers instead. That server, the exit, is where your traffic comes out onto the internet.
| Without ForestVPN | With ForestVPN | |
|---|---|---|
| Your Wi-Fi network | The servers you talk to | Encrypted traffic to our servers |
| Your internet provider | The servers you talk to | Encrypted traffic to our servers |
| The sites you visit | The address your network gave you | The exit's address |
| The ForestVPN exit | Not involved | The sites you visit and the address you connected from |
That moves trust; it does not remove it. The exit sees the sites you visit and the address you connected from, and the sites you visit see the exit's address instead of yours. A VPN does not make you anonymous: it changes who can see your traffic.
What a VPN does not touch is everything that happens after the exit. The sites you sign in to still know the account you sign in with, and a site that tracks you with cookies still does. The tunnel protects the road, not the destination.
What happens when you tap Connect
You tap Connect. Your device asks for permission to use a server, shows a ticket that carries two facts, (which plan's key signed it and which fortnight that key belongs to), gets pointed to a server, and builds an encrypted tunnel to it. Then it checks that data really flows both ways before it says you are protected.
Sign-in service
Your device
Server list
Session service
Exit
- Your device > Sign-in service: 1. Ask for tickets. Hours earlier, signed by the device key
- Sign-in service > Your device: 2. Blind-signed tickets. The signer never sees the ticket
- Server list > Your device: 3. Signed server list. Checked on your device
- Your device > Session service: 4. Ticket, its session key, place
- Session service > Exit: 5. Install this one-session peer
- Session service > Your device: 6. Exit address and roads
- Your device > Exit: 7. Handshake, then proof round
The ticket is the interesting part. Hours earlier, in a separate request, your device asks our sign-in service for tickets. The service signs each one blind: the signature is made over a value it never sees, so the signature on the ticket you present later does not point back to the request that created it. The one exception is the metering row described below, which ties your device to each session it pays for.
Notice what happens before a single byte of yours moves. Permission comes first: the ticket, checked in a fraction of a second. Placement comes second: a signed server list, which your device verifies itself, and a session service that picks the exit. Proof comes last: the app does not say you are protected when the handshake finishes, but when test packets have gone through the tunnel and come back.
Two details are worth knowing. Tickets are refilled on the underlying network, never through an exit, so the sign-in service is never reached through the tunnel it helps to build. And the app can reach our services by several routes and uses the first that answers, so a poor path to one of them need not stop you from connecting.
Step by step, for engineers
- A machine key from first launch. Your device makes an Ed25519 machine key the first time the app runs, before any account, and keeps it in the system keychain or keystore. An account is optional: a random 128-bit number, shown as 32 characters.
- Tickets, hours earlier. The device asks the issuer for tickets in a request signed by the machine key. The issuer checks suspension, the daily ticket count, the device limit and the entitlement, then blind-signs a value it never sees (RFC 9474: RSA-2048, RSASSA-PSS, SHA-384). Each ticket commits to the hash of a fresh session public key and a 16-byte nonce. There is one signing key per plan and 14-day epoch.
- Off the tunnel. Ticket refills leave on the underlying network, never through an exit, and there is no fallback into the tunnel.
- A signed server list. The device fetches the server list, signed with Ed25519 and checked against a pinned key before it is used. The app can reach the list and our other services by several routes and uses the first that answers.
- The ticket's session key. The device posts the ticket, the X25519 session public key it committed to when the ticket was issued, and the place you want to the session service. The session service checks the ticket against the epoch public key, a check that takes well under a millisecond, picks the exit and its roads, tells the exit to install a peer and answers.
- One peer, one session. The exit installs a peer for that one-session key, with a borrowed address from 100.64.0.0/10 that is reused across sessions, and one plan bit. It is given no account, machine key or durable name.
- The handshake. The device dials the exit with the unmodified Noise_IKpsk2 handshake over UDP. If the first dial gets no answer within a fraction of a second, it also tries other roads inside the same session. A change of road needs no second ticket.
- A proof round. A handshake is not proof. After it, the device sends probes through the tunnel and counts the replies, and only a passed round turns the status to Working. On some networks a handshake passes while the data is dropped. That is why a handshake alone is not proof.
- One set of decisions. The decisions above are written once, in shared Rust code, and reach each app through its native layer. An app keeps only what is its own: the operating-system integration, the screens and the store.
- Same ticket, same session. If the same ticket and session key come back, the session service returns the same session for the ticket's lifetime, so sleep and wake, Wi-Fi to cellular and a retried connect cost one ticket.
Inside the tunnel
Everything you send is sealed on your device with keys that only your device and the exit know. If your network changes, the same tunnel carries on.
- UDP datagram. The first bytes are masked and vary on every connection. Your network sees this ring.
- Sealed frame. Encrypted with keys from the handshake. Only your device and the exit can open it.
- Inner frame. Carries one packet, with a short header of its own.
- Your packet. What your app sent. The exit reads it.
Read the figure from the outside in. Your network sees only the outer datagram: a packet of encrypted bytes going to one of our servers, whose first bytes are masked and whose size varies. Inside it, the sealed frame can be opened only with keys made in the handshake, which only your device and the exit hold. Inside the frame is your own packet, exactly as your app sent it.
The tunnel protocol is called Quantum. Its handshake is Noise_IKpsk2, unmodified, with X25519, ChaCha20-Poly1305 and BLAKE2s. We left it alone on purpose: the published analysis of that handshake still applies to it. What we added sits around it. Packet sizes and header bytes vary on every connection, and the tunnel copes with roaming and with the path changing under it.
The tunnel belongs to the session, not to the network you happen to be on. When you walk from Wi-Fi onto cellular, the session key stays the same and the packets simply start arriving from a new address, so the same tunnel carries on. We do not promise that nothing drops: a switch can take a moment, and the status screen shows what state you are in.
Your traffic ends on servers we run, not on a cloud function. A cloud service cannot carry a tunnel, so the services that hand out tickets and server lists never carry a packet of yours.
More about the tunnel, for engineers
- Your address inside the tunnel is borrowed for the session, from a pool the exit reuses.
- The tunnel is bound to the session key, not to a network path, so moving between Wi-Fi and cellular does not change the session. The app can also move a connection to a new port without dropping it.
- It is built on a Rust, open-licence core, and the same core runs on every platform.
The numbers we measured, with their dates and test setups, are on the protocol page.
One tunnel, many roads
If one path to the server is slow or stops carrying data, ForestVPN tries another by itself and keeps whichever actually carries data. You do not have to pick.
Why more than one road? Networks differ. Some carry UDP well and some handle it poorly, and a network that is fine for hours can change. A fixed choice is wrong somewhere, so the app measures instead. For each network it has connected from, it keeps a small note on your device, filed under a hashed name, saying whether the backup route was needed there. It only reaches for the backup route on a network where connecting directly has failed, now or within the last day. On Free the backup route comes with a monthly allowance, and Premium includes more.
We call a path a road: a way of carrying the same encrypted packets to the same exit. The app always dials the direct road first, over UDP, and on a healthy network nothing else is contacted. If the direct road stops carrying data, the app also tries the other roads it has, inside the same session: TCP, sometimes an extra server of ours chosen automatically, and the backup route, which carries the same packets as ordinary web traffic through a content delivery network. The backup route is a fallback, not a faster road, and it is metered because it costs more.
One session
- Direct, over UDPTried first
- TCPUsed only when needed
- An extra server of oursUsed only when needed
- Backup routeUsed only when needed
Changing road does not change the session: the ticket, the keys and the exit stay the same.
The app decides by data, not by handshakes. A road counts as healthy only while it delivers, and the status screen shows Working only once data is flowing both ways.
On a healthy network
- Dial direct
- Answer
- Proof round
- Data flows both ways
- Working
When the direct road stops carrying data
- No answer, or no data
- After a fraction of a second, or a failed proof round
- Try the other roads
- First to pass the proof round
- Working
More on the connection status and the backup route.
Smart routes
Smart chooses a route that suits your network, keeps measuring it while you use it, and moves to a better one on its own when one appears. A location you choose yourself stays where you put it.
Direct routeStopped carrying data
An extra server of oursCarrying data
The extra server carries the data, so the session moves to it.
The session moves here
Backup routeHeld in reserve
A road is one way to carry your packets to the exit: direct, TCP, through an extra server of ours or the backup route. Smart compares the roads on offer for the place you asked for and moves between them inside the session you already have, with no new ticket and no new handshake.
From cheapest for us to run to dearest
- Direct, UDP
- Costs a little more
- Direct, TCP
- Costs more
- Extra server
- Costs most
- Backup route
Three things Smart does not do. It does not move a location you chose yourself. It does not promise a faster connection: it promises that it keeps checking, and that it moves only when another route is better for your network. And it does not need you: there is nothing to turn on and nothing to pick, although the Network-aware routing setting turns these decisions off if you prefer.
Smart routes is on Windows, Linux, the Mac app from our website, the command line and OpenWrt routers today. iPhone, iPad, Apple TV, Android and the Mac App Store version get it with an app update.
For engineers: how the route engine is built
Our own servers measure the links between each other all the time, at a small fixed rate that does not grow with the number of users. The device and the servers share one scoring function. Today the session service only compares that score with its current choice; the roads it offers are not yet built from it.
Our servers
Session service
Your device
Report service
- Our servers > Session service: Measure the links between them
- Session service > Your device: A signed list of routes
- Your device: Tries them inside the session
- Your device > Report service: Outcome, no identity. Kept only as daily counts
The device races that shortlist inside the open session and keeps the route that carries data. Cheaper roads win, but only inside a quality gate: the content delivery network is a gate, not a weight, and a place is ranked by its own latency, never by the road that carried it.
Two programs, one signed ticket
Why split the work at all? Because the two jobs need different knowledge. Checking that you have a plan needs to know your device. Choosing and opening a session needs to know a place and an address. If one program did both, it would hold both kinds of knowledge together. So they are two programs, deployed apart. The ticket passes between them at connect, and the data a session used passes back when it settles, so it can be charged: that is the metering row described next.
The part that knows your device and plan and the part that knows your server are separate programs. The session service is deployed without any binding to our account database, and the ticket between them is signed blind. One row ties your device, and any linked account, to each session it pays for, to meter data and to cut off a revoked device. It is deleted an hour after the session settles, or up to 17 days later for a ticket that was never used.
The ticket
- Sign-in service Knows your device and plan
- Signs without seeing
- Ticket Signed blind
- Presented at connect
- Session service and exits Know a ticket, a place, a one-session key and the address you connect from
The metering row
- Sign-in service Holds one row per session
- Written when the ticket is issued
- Device and session Ties your device, and any linked account, to the session
- Removed automatically
- Deleted An hour after settlement, or up to 17 days for an unused ticket
The sign-in service holds your account, your devices and your plan, and sees the address each ticket request comes from. It never learns which exit you were given or anywhere you went. The session service sees the address you connect from, the location you chose and a one-time session key. Its session record deletes itself when the session expires, and your source address is never written into it.
| Your device | Your plan | The server you use | Your address | Sites you visit | |
|---|---|---|---|---|---|
| Server list host | Does not receive it | Does not receive it | Does not receive it | Receives it | Does not receive it |
| Sign-in service | Receives it | Receives it | Does not receive it | Receives it | Does not receive it |
| Session service | Does not receive it | Receives it | Receives it | Receives it | Does not receive it |
| Exit | Does not receive it | Receives part of it | Receives it | Receives it | Receives it |
The grid lists what each part is handed at connect time, which is not the same as a promise about what could be worked out by combining records. That is why the metering row is stated in words and drawn in the figure rather than left off.
For engineers: blind signatures and three keys
- Blind signatures. Tickets use RFC 9474 blind RSA signatures. The plan is encoded in which key signed the ticket, not in a field, and at most six keys are live at once.
- Enforced in the build. The session service's deployment configuration has no binding to the account database, and a check in our build fails if one is added.
- Three keys with different lifetimes. The machine key (its public half is known to the sign-in service; the private half never leaves the device), the account number (known to the sign-in service, optional) and the session key (one per ticket; the session service and the exit see it at connect, the sign-in service at a different moment; gone when the session ends).
What we keep, and for how long
There is no column anywhere in our systems for the sites you visit or the names you look up. Which exit a session used is erased when the session ends. Payment is handled by the App Store, Google Play or the processor you choose, and we never see a card number.
The main records and how long each lives, in one picture; the privacy policy lists every one. Route reports, which help us choose better routes for everyone on a network, are aggregates with no device, account, session or exit in them, published only for days with at least 10 devices.
- The metering row, after the session settles1 hour
- The same row, for a ticket never usedUp to about 17 days
- A support report you chose to send72 hours
- Data and connection counts per day31 days
- Country and network of ticket requests, under a pseudonym3 months
- Monthly totals, and device, account and billing recordsIndefinitely
Two more things belong in the same picture. The app contains no analytics SDK, no attribution SDK and no advertising identifier. And if you choose to send a diagnostic report, it shows you its contents first, uploads without your device's identity at a random time in the following hour, never through the connection it describes, and is deleted after 72 hours.
Every record is listed in the privacy policy, and the short version is on the security page.
Your devices, routers and TVs
One account number works on up to ten devices. Devices on your account can reach each other by name, and a computer that stays at home can be an exit for the others. An iPhone can use an exit but cannot be one yet. Routers cover the devices that cannot run an app, and TVs and routers sign in without a keyboard.
Your account number
- PhoneTunnel to our servers
- LaptopTunnel to our servers
- TVTunnel to our servers
- RouterTunnel to our servers
- Home computerDevice to deviceUse as an exit
If the home exit you are using goes offline, the app moves you to another of your own exits and tells you. If every one of your exits fails, traffic stays blocked and the app asks you to tap.
Routers are for the devices that cannot run an app, such as a games console or a smart TV. Put ForestVPN on the router and everything behind it, or only the devices and apps you choose, goes through the tunnel. The router's processor is the speed limit, so the router page says what we measured and on which hardware. A router links to your account with a code it prints for you, and TVs sign in without a keyboard.
What this design does not do
None of this makes the design airtight, and we would rather say where it stops than let a diagram suggest otherwise. These are the main ones; the privacy policy lists every one.
Limits, stated once
- One row ties your device, and any linked account, to each session it pays for, until an hour after the session settles.
- The sign-in service and the exit each see your session key, at different moments. Put together, those two views could rejoin a session; we keep no record that would do it, and neither can do it alone.
- The exit sees the sites you visit and the address you connected from. That is the point where you trust us.
- A VPN does not make you anonymous.
- No kill switch is absolute. What each system allows differs, and on Apple devices some system services may still send traffic outside the tunnel.
- Blinding does not hide that a ticket request and a connect can come from the same network address. That is why tickets are refilled at random times, ahead of when you connect.
- The group a ticket could have come from is everyone holding a ticket signed by the same plan key in the same fortnight, not all our users.
- Route reports are aggregates, not a record of any one device.
Questions
Can ForestVPN see which sites I visit?
The exit server your traffic passes through handles where it goes, as any VPN's exit does. There is no column anywhere in our systems for the sites you visit or the names you look up.
Do I need an account to use ForestVPN?
No. Free needs nothing: connect without an account. When you want a subscription on your other devices, your account is a random 32-character number, with no email, no password and no name.
What does Working mean in the app?
Working appears only once data is flowing both ways. After the handshake, the app sends test packets through the tunnel and waits for the replies.
What happens when the direct route stops carrying data?
The app tries other roads inside the same session: another transport, an extra server of ours or the backup route. It keeps whichever carries data, and the session, the ticket and the exit stay the same.