Privacy Policy
dkuvpn holds a Duke address, a netid, a payment record and a byte counter. This page lists every piece of it: where it sits, who else sees it, and when it goes.
Last updated 23 August 2026
What this covers
dkuvpn is run by students at Duke Kunshan, for students at Duke Kunshan. It is not a University service. There is no company, no registered office and no data protection officer to name here — there is a mailbox, and the people reading it are the same people who hold the data this page describes.
This policy covers three things: this website, the sign-in that creates your account, and the account itself on the proxy panel behind it. It does not cover what you do once you are connected. The sites you open have their own policies and this service is not a party to them.
Where a clause below quotes a number — ten minutes, five attempts, thirty days — it is the number in the code, not a rounded one.
What we collect, and why each piece exists
This is the whole list for this website and the sign-in. The account on the proxy panel holds a short list of its own, and it is set out in full in the next section — between the two, nothing about you is held that is not written down on this page.
- Your Duke email address. You type it to sign in, and it is used for one thing: sending you a six-digit code. It is handed to Resend for delivery and is not written to our own database.
- Your netid — the part of the address before the @. It is your username on the panel and the identity everything else keys on. On an allowed domain that is not the primary one it is qualified with the domain's first label, so ab999@duke.edu and ab999@dukekunshan.edu.cn stay two different people rather than one shared account.
- The sign-in code, as a hash. What is stored is scrypt of the code and a fresh 16-byte random salt, never the six digits. Nobody reading the database — us included — can read a code out of it.
- The IP address a code request came from, taken from the X-Real-IP header our reverse proxy sets. It is written down for one purpose: this endpoint sends mail to whatever address the caller typed, so without a count per address it is an email bomb pointed at anyone with a Duke account.
- One cookie in your browser, dkuvpn_session. It carries your netid and an expiry, signed with HMAC-SHA256, and it is the only thing that tells a page whose dashboard to draw. The Cookie Policy is the long version.
- The email address on a Gumroad receipt, but only when a payment arrives with no netid attached to it. It is read back from Gumroad, turned into a netid so the time can be granted, and written to the server log so a person can grant it by hand if it cannot be.
- One row per payment: the Gumroad sale id, the netid it paid for, how many days it granted, and when. That is the entire row — no amount, no card, no name.
There is no password, no security question and no profile to fill in. The service asks for an address because that is all it needs to know.
What the proxy panel holds
Your account lives on a Marzban panel; this site is a front end for it. Against your username, the panel holds:
- The status of the account — active, disabled, limited, expired or on hold.
- One running total, in bytes, of everything the account has carried.
- A data limit in bytes and an expiry date. On the free week both come from the trial template.
- Your subscription link and the token inside it, along with the proxy settings your client needs to connect.
- Which administrator owns the account — the service account this app signs in as. Your dashboard is never sent that field, or the raw proxy settings.
- A note reading dkuvpn self-service, which is how an account this site created is told apart from one an administrator made by hand.
- The time your account was last seen carrying traffic. It is one timestamp, overwritten each time — not a history of your sessions. It does mean the panel can say roughly when you were last connected.
- The client software that last fetched your subscription link, as the User-Agent string that software sent — typically the name and version of the VPN app on your device. One value, overwritten on each fetch.
That total is a counter, not a history. dkuvpn keeps no record of the sites you opened, the addresses you connected to, or the names your device looked up — there is nowhere in this application such a record could be written. The counter can tell someone that your account moved 4.2 GB. It cannot tell them where any of it went.
The honest limit on that: a proxy server necessarily handles the traffic it is forwarding, in the moment it forwards it. That is what a proxy is, and no policy can write it away. The claim here is about what is written down and kept afterwards, which is the list above and nothing else.
Why we may hold it
Wherever a law asks a service to state its reason, ours is short: each item exists because the service does not work without it, and no two of them are there for the same reason.
- The address, the code hash and the netid — you asked to be signed in, and there is no way to sign you in without them.
- The IP address — keeping the sign-in endpoint from being used to send mail nobody asked for. For that purpose it is counted, at ten requests an hour, and nothing else: the rate-limit row holds the address and a timestamp, is never joined to your browsing, and is never shown to anyone. Separately from it, the web server keeps an ordinary access log that does record which address asked for which page; it is described under Where each piece is kept.
- The cookie — strictly necessary. Without it the site cannot tell your account from anyone else's, which is why it is set without asking and why there is no consent banner.
- The payment row — the record of a sale, and the thing that stops one payment being granted twice.
Nothing here is collected for marketing, and nothing collected for one of the reasons above is later used for another.
What we do not collect
Every line here was checked against the code rather than assumed:
- Your name, student number, photograph, phone number, date of birth or postal address. None of it is asked for and none of it has anywhere to be stored.
- Card numbers, bank details, or anything else about how you paid. Checkout happens on gumroad.com in a separate tab and this site never sees it.
- A password. There is not one — the code in your inbox is the whole of the sign-in.
- Advertising, a tag manager, a tracking pixel, or any third-party script — and no analytics of any kind running in your browser. No page on this site loads anything from another host, the font included. Visitor numbers are counted afterwards, by reading the web server's own log on the same machine; nothing runs on the page to produce them and no other company is involved. That log is described under Where each piece is kept.
- Your location, beyond whatever an IP address implies about the network you asked for a code from.
- Anything off your device: no contacts, no files, no device identifier. The site is HTML and the client app is not ours.
Where each piece is kept
Six places, and no others:
- One SQLite file on the server this site runs on, owned by this application. It has exactly three tables: the code hashes, the rate-limit rows, and the payment ledger. There is nothing else in it about anybody.
- The panel's own database, holding the account described above.
- Your browser, holding the session cookie. Nothing about your session is stored on the server — the cookie carries it, which is why there is no session table anywhere.
- The server's log, on that same machine: which sale added how many days to which netid, and errors when something fails.
- The web server's access log, on that same machine again. This is the ordinary log a web server writes for every request it answers, and it is where visitor numbers come from: the address the request came from, the page asked for, the time, the response code, and the description the browser gives of itself. It is kept for fourteen days and rotation then deletes it. Subscription links are the one thing excluded from it, because the link is itself a credential and a log is the wrong place for one.
- Resend and Gumroad, each holding what the next section describes.
One line in that log can carry an email address. When a payment arrives with nothing identifying the buyer, the plan and the address on the receipt are logged so a person can grant the time by hand, rather than a student losing money they have already paid. Logs are read when something is broken. They are not used for anything else, and nothing is built out of them.
Who else sees it
Three parties receive anything at all, and each receives one thing:
- Resend delivers the sign-in email. It receives the address you typed — which contains your netid — and the code inside the message. It receives nothing else: not your account, not your usage, not what you paid.
- Gumroad takes the payment, as merchant of record. It receives your card details and your billing information; neither reaches this site. One thing comes back the other way: when a payment arrives with no netid attached, the app reads the sale back from Gumroad and takes the address on the receipt, because that address is the only remaining way to find whose account the time belongs to. The checkout link built for you also carries your netid, because that tag is the entire mechanism by which a payment finds your account.
- The exit servers carry your traffic. That is the service, and it is described in the Terms.
Resend and Gumroad hold what they hold under their own privacy policies, not this one. What leaves here for them is the two lines above, and nothing more.
Nobody else receives anything. In particular: nothing is sold, rented or traded — there is no advertiser to sell it to and nothing collected an advertiser would want. Your account is not reported to Duke Kunshan University or to Duke; dkuvpn is not a University service and has no reporting line into one. There is no data broker, no analytics vendor and no mailing list.
One more, and for some people it matters more than everything above it. Your sign-in code is delivered to your university address, so it passes through — and is stored by — whoever runs that mailbox. Duke's mail system records the sender, the recipient and the subject line of every message it accepts, and an administrator there can read what sits in that mailbox. dkuvpn does not report your account to the University and has no way to; but the University's own mail logs can still show that you received a dkuvpn sign-in code. No setting on this site changes that. It is what receiving mail at an address someone else administers means, and it is equally true of every other service that emails you there.
If a demand ever arrives that a law requires an answer to, what exists to hand over is what is listed on this page — a netid, a payment ledger, a byte total, a last-seen timestamp and the name of a client app — because nothing beyond the two lists on this page is written down. We will not manufacture a record to satisfy one, and where we are allowed to tell you, we will.
Data that crosses a border
The point of this service is that your traffic leaves mainland China. The exits are Durham, Iowa, Seoul, Tokyo, Bangkok and Singapore, and picking one is picking where your connection surfaces.
Two other things cross a border. The sign-in email goes through Resend and payments go through Gumroad; both are outside mainland China, so the address you type and the record of what you bought are handled outside it too. Signing in and paying are the moments you agree to that — a service that never receives your address cannot send you a code.
Your Duke mailbox is a University system and not ours. The code lands wherever Duke runs your mail.
This page does not name the country each server sits in, because that changes when the service moves hosts and a policy that named one would go stale silently. Ask and we will tell you where a given one is today.
Using an unauthorised VPN in mainland China is restricted under PRC law, and this document cannot change that. The Terms say what it means for you. This page is only about data.
How long things are kept
These are the intervals the code uses:
- A sign-in code: ten minutes of usable life, and then it is deleted by the next thing that touches it — a verify attempt burns an expired row on sight, and every new code request sweeps every expired row in the table. What can outlast the ten minutes is the scrypt hash of a code that is already worthless, waiting for the next request to sweep it.
- A rate-limit row — netid, IP address, timestamp: one hour. The sweep runs on every code request and deletes everything older than an hour, so a row lives at most until the first request after its hour is up. If nobody asks for a code all day, the last rows wait there until somebody does.
- The payment ledger: kept indefinitely, on purpose. Your rights below explains why, and what that means for deletion.
- The web server's access log: fourteen days. It is rotated once a day and the oldest is deleted on the way, so a request drops off fourteen rotations after the day it was made. Nothing is kept from it after that — the visitor counts read out of it are totals, and hold no address.
- The session cookie: 30 days from the sign-in that wrote it, and it is not renewed as you browse. Signing out deletes it there and then.
- Your account on the panel: as long as you have one. Deleting it clears the username, the byte total, the expiry, the data limit and the subscription token from the panel's own database.
- Resend and Gumroad keep their own records to their own schedules — a delivered message at one, a sale at the other. Neither schedule is ours to set.
What protects it
Concrete measures, not adjectives. In roughly the order they matter:
- Sign-in codes are never stored. What is stored is scrypt of the code and a 16-byte random salt, compared in constant time — so neither a copy of the database nor the timing of a wrong guess gives a code away.
- Guessing is capped at five attempts per code, and the fifth wrong one destroys the code rather than leaving it to be tried again later. Six digits, five attempts and ten minutes is not a space anyone brute-forces.
- Asking is capped too: three codes per netid per 15 minutes, ten per IP address per hour. That is what keeps the endpoint from being turned on somebody's inbox.
- The session cookie is httpOnly, so no script on the page can read it; SameSite=Lax, so another site cannot make your browser present it; Secure in production, so on the live site it only travels over HTTPS; and signed, so its contents cannot be edited into another student's netid.
- The token that can read and write every account on the panel lives in one server-side module, behind a runtime guard that throws if it is ever loaded in a browser. It has never been part of a page.
- That token belongs to a deliberately non-sudo administrator. A sudo one could restart the proxy core and rewrite node configuration, so the app is built such that compromising it cannot reach either.
- A verified Duke address becomes a user on the panel, never an administrator. No student ever holds a credential that could read another student's account.
- Every response carries X-Content-Type-Options: nosniff, X-Frame-Options: DENY and Referrer-Policy: same-origin, so this site cannot be framed by another and does not leak the page you were on when you follow a link off it.
Two things are yours to protect. Your subscription link is a credential: anyone holding it can use your account, so do not post it or pass it round. And the session cookie signs in whoever holds it — sign out on a machine that is not yours.
None of this makes the service unbreakable, and it is run by students alongside their own coursework. If you find something wrong with it, write to support@dkuvpn.com — we would far rather hear it from you than not.
And if it is broken into, you get told rather than left to find out. A dated notice goes on this page, and every account we have reason to think was reached gets a mail written by hand — the way a suspension warning is written, because the service itself only ever sends sign-in codes. It says what was reached, when, and what is worth doing about it. What an intruder would hold is what this page already lists: netids, the payment ledger, byte totals, and any session still signed in. What they could not take is where you have been, because no such record exists to take, or a usable sign-in code, because what is stored is a scrypt hash of one that stops working within ten minutes.
Your rights, and what deletion reaches
The account is yours. What you can ask for:
- Access — most of it is already on your dashboard: netid, status, bytes used, any data limit, expiry, subscription link. Ask and we will tell you the rest, which is the payment rows standing against your netid.
- Correction — a netid is derived from the address you signed in with, so it can only be wrong if the address was. Write and we will fix or remove the account it created.
- Deletion — say so and your account on the panel goes: username, byte counter, expiry, data limit, subscription token. A code row stopped being usable within ten minutes of being made, and a rate-limit row stopped counting after an hour; both are deleted by the next code request that sweeps them, as the retention clause above sets out.
- A complaint, or an objection to any of this — one mailbox, read by a person rather than a queue.
Deletion cannot reach the payment ledger. A row is a sale id, a netid, a day count and a date, and it is kept because it is the record that a payment paid out once: a refunded sale has its day count set to zero rather than the row removed, and without the row a redelivered payment notice would grant the same days a second time. It is also the answer to the question 'I paid, where did it go?'. The netid stays in it, because the netid is the only thing tying a payment to an account.
Gumroad keeps its own record of a sale as merchant of record. An invoice is not ours to delete, and asking us will not remove it — that request goes to Gumroad. The Refund Policy covers the money side of the same event.
Two honest consequences of deleting an account: it does not refund unused time, and it does not stop a payment already in flight. The code that applies a sale provisions an account when it finds none, so a payment that lands afterwards will create yours again.
Changes, and how to reach us
This page is dated. If it changes, the date at the top changes with it, and a change to what is collected, who receives it, or how long it is kept is written into the clause it affects rather than folded into a summary. That date is the announcement — there is no mailing list, and we will not email you about a policy.
Questions about anything here, and any request under your rights, go to support@dkuvpn.com. It is read by the students who run dkuvpn between their own classes, and answered within one business day.
If something on this page does not match what the service actually does — a record we say we do not keep, or one we keep and did not list — that is a bug, in the code or in this document. Tell us and it gets fixed.