Skip to content
NEXDIARY

Security

A diary needs protecting, and honest words about it

People write things in a diary that nobody else is meant to know. So in nexdiary everything is encrypted, each person with a key of their own, a second factor is required by default, and the server checks for itself whether it is ready for the internet. Here is what that protects, and just as plainly, where it stops.

Encrypted, each person with a key of their own

Everything somebody writes in nexdiary is encrypted in the database. That is so from the start and cannot be switched off.

What is encrypted

Pages with their title, text, tags, values and choice of cover, notes and their questions, drafts, a person's own values and questions, templates, answers to the family question, time capsules, photos with their previews, the access to Immich, the devices for notifications and the names of API tokens.

How

Every person has a data key of their own, wrapped with the installation's master key. Each field is sealed on its own with AES-256-GCM and bound to its person, table, column and row. A text that somebody copies into another row cannot be opened there. When an account is deleted, its key goes with it, and everything of that person is unreadable from then on.

What that protects

Whoever opens the database or a backup sees only gibberish. A copied file, a lost backup drive, a curious look into the data folder gets nobody anywhere.

What it does not protect

The master key lies on the same server so that nexdiary itself can read, for the search, the statistics, the AI and the book. Whoever holds the whole server therefore gets in, and nexdiary says so itself in its interface. It is not end-to-end encryption. For a family sharing its own server that is enough; whoever does not trust the people running the server should not keep a diary there.

Good to knowThe keys do not depend on the password. Whoever resets their password therefore loses nothing of their diary.

What the server needs for keeping order stays unencrypted: account name, display name, mail address, role, profile picture and settings such as colour and time zone, along with each day's date and timestamps, each note's date and time, each photo's date and size, who shared which day with whom, the sender, recipients and days of time capsules, and for each session the address and browser for the device list. The content itself is nowhere in the clear.

Keep the master key somewhere else

The master key lies on the server as keys/master.key, readable only by its owner. It is deliberately left out of every backup. Without it a backup cannot be read, not even by the operator.

  • Saving it: under “Settings”, “Backup”, card “Encryption”, the operator downloads it with “Save master key”. nexdiary asks for the operator's password and second factor first. Without a second factor of their own, nexdiary does not hand the key out.
  • Keeping it: apart from the backups, in a password manager, say, or on a USB stick in a drawer. When it was last saved shows on the card and in “Ready for the internet?”.
  • At start-up: if the key is missing, does not match or lies in the wrong place, nexdiary does not start and overwrites nothing.

Good to knowThe backup itself is a ZIP file that is not encrypted. The diaries inside it are, but account names, mail addresses, timestamps and the server's secret, which opens the mail password, the AI key and the sign-in provider's secret, lie in it openly. So treat a backup as something confidential. Older backups also hold the keys of accounts deleted since. How backups and moving work is in the guide under Backups.

Signing in with a second factor, required by default

A guessed or stolen password should not be enough to read a diary. So by default nexdiary asks every account that signs in with a password for a second factor.

Password and code

A password has at least 12 characters and is stored with Argon2id. Right after the first sign-in each person sets up a code from an authenticator app, and only then do they get any further. nexdiary then shows eight recovery codes once, which belong on paper. Each gets you in once if the phone is gone.

Passkeys

With a passkey you sign in with your fingerprint, your face or the device's PIN, without password and without code. A passkey counts as two factors by itself and cannot be phished. You add up to ten per account under “My account”, “Security”. Passkeys need https and the server's public address.

The operator can switch the requirement off under “Settings”, “Sign-in” with “Require a second factor”. That has to be confirmed with the operator's password, and “Ready for the internet?” then shows it as open. Whoever comes in through a sign-in provider such as authentik also sets up a second factor here by default, unless the operator declares that the provider checks one itself.

My account
My account, Security tab, with the second factor, a passkey called Laptop and two signed-in devices
Second factor, passkeys and devices in one place.

With “Stay signed in on this device”, which is ticked to begin with, a sign-in ends only after 30 days without use. Without it, it ends with the browser, after 12 hours at the latest. The message on a failed sign-in never gives away whether the name or the password was wrong.

You can see where you are signed in

Signed-in devices

Under “My account”, “Security” you find every device your account is signed in on, with browser, network and last use. Each can be signed out on its own, and “Sign out everywhere else” ends all the others at once. Changing your password signs out every other device as well.

Told about a new sign-in

When your account signs in on a browser it has never been signed in on before, you are told, by push to your devices and by mail if a mail server is set up and your account has an address. The message says which device, which browser, roughly from where and when. Tapping it leads to “My account”, “Security”, where one more tap signs the device out.

“Roughly from where” means the network, cut down to its first part, with no location lookup at any outside service. The switch “Tell me about a new sign-in” is on from the start.

Guessing does not pay

After five wrong tries the account waits 15 minutes, and so does the address the tries came from. Every try is in the log. This cannot be adjusted; it is always on.

  • You are not locked out when a stranger blocks your account by guessing. A browser you have signed in on before still gets in with the right password.
  • A link to reset the password lifts the wait.
  • Behind a proxy nexdiary has to see the visitors' real addresses, or it takes them all for one. How that works is further down.

Good to knowThe counters for accounts live in the database, those for addresses only in memory. A restart therefore forgets the addresses, not the accounts. “Ready for the internet?” tries the brake out on a copy every time it is opened.

nexdiary checks for itself whether it is ready for the internet

Many people will want to reach nexdiary when they are out and about. So under “Settings”, “Sign-in” the card “Ready for the internet?” sits right at the top. It checks eight points afresh every time the operator opens the page, marks each “fine”, “check” or “open” and says what to do.

PointWhat nexdiary checks
Public address with httpswhether the public address starts with https and the request really came over https. Without https, passwords travel the network in the clear, and Web Push and passkeys do not work at all.
Second factor for everybodywhether every account with a password needs a code or a passkey as well
Your own accountwhether the operator's account, which may change everything, has a second factor itself
Protection against guessingwhether the brake passes its own test and no public networks are entered as a proxy
Entries encryptedwhether the master key is there and readable by its owner only
Sessions and cookieswhether the sign-in cookies go over https only and cannot be read by scripts
Behind the proxywhether the visitors' real address arrives, or an unknown proxy sits in between
Master key savedwhether, and when, the master key was last downloaded

What the card cannot see

The card checks what nexdiary can know about itself. Whether your router, your proxy and your server are up to date, it cannot tell. It covers the things that are easiest to overlook when setting up.

On top of that, the operator can keep the settings to the home network altogether. With NEXDIARY_OPERATOR_NETWORKS, 192.168.0.0/16 for instance, nexdiary refuses any change to the settings from elsewhere.

Settings
Settings, Sign-in tab, with the card Ready for the internet? showing All good and a green tick on every point
All good. The eighth point is further down the card.

Behind a proxy, with https

In the self-hosting example nexdiary can only be reached on the machine itself, at 127.0.0.1:8550. In front of it belongs a reverse proxy that speaks https. Whoever puts nexdiary on the home network without https sends passwords and codes across it in the clear.

Naming the proxy

NEXDIARY_TRUSTED_PROXIES names the address or network of the proxy. nexdiary believes only that proxy about the visitors' real address. Without it, every sign-in seems to come from the proxy, and the protection against guessing cannot tell people apart. “Ready for the internet?” marks public networks in this list as open.

Naming the address

NEXDIARY_PUBLIC_URL or the setting “Public address” names the address nexdiary is reached under. Invitation links, the return from the sign-in provider, passkeys and the contact for push are built from it. nexdiary protects the cookies over https by itself; the HSTS header is sent by the proxy.

Strict headers

The page loads files from its own server only, cannot be embedded in other sites and has camera, microphone and location switched off.

Rights on the server

Every request is checked on the server. Somebody else's day, note or photo answers as if it did not exist.

No root

The container runs with no-new-privileges and hardly any capabilities, and nexdiary itself never runs as root.

Other sites stay out

Every request that changes something carries a header that another website cannot send along. Cookies cannot be read by scripts.

A log without content

The log never holds a word from pages or notes, never a password, key or token. Tokens in addresses are masked.

Photos redrawn

An uploaded photo is redrawn from its pixels, without location, device and time taken, and lies encrypted on the disk like everything else.

What goes out

The browser talks only to your own server. nexdiary brings its fonts, icons and scripts along; there are no statistics, no error reports, no maps and no pictures from outside services. The server itself makes only these connections, and most of them only once somebody switches them on.

ConnectionWhenBy defaultWhat goes out
Asking for a new versionwhen somebody opens “About nexdiary” and the last answer is older than a dayononly the question to GitHub, without names, entries or any identifier. The operator switches it off with “Check once a day”.
Web Pushreminders, time capsules, notice of a new sign-in or a reset second factor, a waiting draftonly once a device is signed upan encrypted message to the browser's push service that only the device can read. It never holds an entry, but it can name the question of the day, a sender's name or the network of a new sign-in.
AI serviceat the press of a button, or in the morning if the operator and the person have both switched it onno AIthe notes of one day, without name, date, photos and values; for a summary the pages of a week or a month. Details on the AI page.
Immichwhen a person has connected their Immich and picks photosclosedtheir Immich key and a date or search term, nothing from the diary, only to addresses the operator allows
Mail serverinvitation, link to reset, notice of a new sign-in or a reset second factor, test mailnone enteredaccount name, link, device and time, never an entry
Sign-in providerwhen a provider such as authentik is set up and somebody uses itnot set upthe usual requests of OpenID Connect, no entry
Setting up authentikonly when the operator presses “Set up”offcalls to authentik with a token that nexdiary neither stores nor writes to the log

Good to knowWeb Push, the AI and Immich check their target addresses, follow no redirects, and addresses where cloud providers offer their internal metadata are always blocked there. These three and the question about a new version also ignore any proxy from HTTP_PROXY or HTTPS_PROXY. That is worth knowing if your server only reaches the internet through such a proxy.

Reporting a security flaw

If you find a flaw, please do not report it in public but privately through GitHub: in the repository under “Security”, “Report a vulnerability”. What helps most is what you found, how to reproduce it and which version was running.

You get an answer within a week. The fix comes out as a new release, and the release notes name the problem once the fix is available.

Security fixes go into the newest release only. Updating means docker compose pull and docker compose up -d; before any change to the database, nexdiary makes a backup by itself. nexdiary never updates on its own.

Security on GitHub