Skip to content
NEXDIARY

Self-hosting

Your family's diary, on your own server.

nexdiary runs as a single container with one folder for all its data. You need a machine with Docker, such as a small home server or a NAS, and a short compose file. You do not need an account with anyone else, and there is none to have.

Starting in three steps

The image lives in the GitHub Container Registry, for amd64 and arm64. It holds the interface and the server together; nexdiary needs no second database and no web server of its own.

  1. Create the compose file

    Make a folder, for example nexdiary, and put this file in it.

    docker-compose.yml
    services:
      nexdiary:
        image: ghcr.io/derkezorm/nexdiary:latest
        container_name: nexdiary
        restart: unless-stopped
    
        ports:
          # Only this machine reaches nexdiary (127.0.0.1). Put a reverse proxy
          # with https in front and let it forward to http://127.0.0.1:8550.
          # Straight from your home network: write "8550:8000", but only on a
          # network you trust. Without https, passwords cross it in the clear.
          - "127.0.0.1:8550:8000"
    
        # Nothing it does not need: the start only sets the owner of /data,
        # then drops from root to the user nexdiary.
        security_opt:
          - no-new-privileges:true
        cap_drop:
          - ALL
        cap_add:
          - CHOWN
          - DAC_READ_SEARCH
          - SETUID
          - SETGID
    
        volumes:
          # A local disk, never an SMB or NFS share.
          - ./data:/data
    
        environment:
          PUID: 1000
          PGID: 1000
          TZ: Europe/Berlin
          # Behind a proxy: the address people use, and the proxy's.
          # NEXDIARY_PUBLIC_URL: https://diary.example.com
          # NEXDIARY_TRUSTED_PROXIES: 172.16.0.0/12
          # Choose the setup code yourself instead of finding it in the log.
          # NEXDIARY_SETUP_TOKEN: choose-a-long-one
  2. Start it
    Shell
    docker compose up -d
  3. Create the first account

    On that machine, open http://127.0.0.1:8550. The page “Set up nexdiary” asks for a name, a password and the setup code. nexdiary writes the code to its log on every start until it is set up:

    Shell
    docker logs nexdiary

    That way nobody takes over a fresh instance just because they found it first. Whoever creates the first account becomes the operator. The password needs at least twelve characters, and straight afterwards the account sets up its second factor. nexdiary then shows eight recovery codes; keep them somewhere safe.

Why the port listens on 127.0.0.1 only

With 127.0.0.1:8550:8000 only the machine itself reaches nexdiary. A diary should not sit on a network without https, because without encryption passwords and codes travel along the wire for anyone to read. So a reverse proxy with https goes in front and forwards to http://127.0.0.1:8550. If the proxy runs in another container, put both on the same Docker network and forward to http://nexdiary:8000.

A server without a screen

If there is no browser on the server, write "8550:8000" for your home network and open http://address-of-the-server:8550 from another device. That is meant for a network you trust. Reminders by push and passkeys do not work without https anyway, except on the machine itself.

Good to knowRather build from source? Clone the repository. Its docker-compose.yml has build: . instead of image:, explains every option and starts with docker compose up -d --build.

What the machine needs

nexdiary is built for a household, not a data centre. There is no measured minimum for memory; what takes a lot is listed here with figures from the code.

  • Docker with Compose on Linux, amd64 or arm64. That covers a NAS with Intel, AMD or ARM and a computer with 64-bit ARM.
  • A local disk for the data folder. On an SMB or NFS share SQLite does not lock reliably, and the database can break.
  • Memory: a password check takes up to 64 MiB, and at most four run at once. A photo takes about 150 MB while it is unpacked, and by default only one is unpacked at a time (NEXDIARY_DECODE_SLOTS). The server sets one year as a book at a time.
  • Space: nexdiary stores photos redrawn as WebP, at most 2560 pixels on the long side, plus a small preview. By default each person may use 5 GB; you change that under Settings, Accounts, “Storage per person”, where 0 means no limit.
  • https through a reverse proxy as soon as anyone comes in from outside. Push and passkeys need it in the home network too.
  • Phones: nexdiary is a web app and can be added to the home screen from the browser. There is no app in a store. On an iPhone, push only arrives in the app on the home screen, from iOS 16.4.

Behind a proxy, with https

Many people will want to open nexdiary when they are out and about, and it is made for that. Before you open it to the outside, go through this list.

  1. Set up first, then open up

    Create the first account from your own network, with the code from the log. Only after that do you forward a port.

  2. https at the proxy, nexdiary only through it

    Leave the port on 127.0.0.1, or keep the proxy and nexdiary on a Docker network with no published port. HSTS comes from the proxy, not from nexdiary.

  3. Name the address and the proxy

    NEXDIARY_PUBLIC_URL is the address at which the family reaches nexdiary. Invitation links, the return from the sign-in provider, passkeys and the contact for push are built from it; the setting “Public address” in the interface wins when it is set. NEXDIARY_TRUSTED_PROXIES names the address or network of the proxy. Without it every sign-in seems to come from the proxy, and the protection against guessing takes everybody for one person.

  4. Cookies over https only

    NEXDIARY_COOKIE_SECURE is auto by default and also recognises https from the proxy's X-Forwarded-Proto header. on suits a nexdiary that is reached over https only; over plain http nobody can sign in any more.

  5. The second factor stays required

    By default every account with a password sets one up right after signing in, a code from an authenticator app; a passkey can be added afterwards. The operator could switch that off. For a server on the internet, leave it on.

  6. Leave off what you do not need

    The AI, Immich and API tokens are off by default, and so is writing up automatically in the morning. Switch on only what the family really uses.

  7. Keep the operator settings at home

    With NEXDIARY_OPERATOR_NETWORKS: "192.168.0.0/16", nexdiary accepts changes to the operator's settings only from that network, behind a proxy together with NEXDIARY_TRUSTED_PROXIES.

  8. Pin a version

    Use a fixed version such as ghcr.io/derkezorm/nexdiary:0.5.0 instead of latest, update on purpose and back up first.

nexdiary checks itself

Under Settings, Sign-in, the card “Ready for the internet?” sits right at the top. Every time you open the page, nexdiary checks eight points itself and says for each one what to do if it is not met.

  • “Public address with https” and “Sessions and cookies”
  • “Second factor for everybody” and “Your own account”, meaning whether you have one yourself
  • “Protection against guessing”, which nexdiary tries out on a copy, and “Behind the proxy”, whether the visitors' real addresses arrive
  • “Entries encrypted” and “Master key saved”
Settings
Settings, Sign-in, the card “Ready for the internet?” with “All good” and every point ticked
Eight points nexdiary checks itself every time the page opens.

On Unraid

nexdiary is in Unraid's catalogue, Community Apps. Search there for “nexdiary” and install it. The template puts the data folder in /mnt/user/appdata/nexdiary, uses port 8550 and sets PUID 99 and PGID 100, Unraid's usual values. You find the setup code in the log: click the nexdiary icon, then “Logs”.

Unlike the compose file above, the template publishes the port to the whole home network, without https. For the way to the outside, a proxy belongs in front here too. You enter the address, the proxy and a setup code of your own in the template under “Public URL”, “Trusted Proxies” and “Setup Code”.

Good to knowFill in your time zone under “Time Zone”, for example Europe/London. Blank means UTC, and the day of the family question follows the server's time zone, so with UTC it changes at an hour that may not be midnight where you live.

What you need to back up

Two things, kept apart from each other: the data folder with its backups, and the master key. Without the master key no backup can be read, not even by you.

The data folder

Everything lives in /data: the database nexdiary.db, the folder media/ with the photos, the master key keys/master.key, the server's own secret secret.key, plus backups/, logs/ and locales/ for extra languages. What the family writes is encrypted in the database and in the photo folder, each person with a key of their own. Those keys are wrapped with the master key.

The master key

Under Settings, Backup, card “Encryption”, “Save master key” downloads the file nexdiary-master.key. nexdiary asks for your password and your second factor first. Keep it apart from the backups, as carefully as a password. Lose it and every backup is only gibberish; if the file goes missing on the server, the same holds for the live database.

Backups nexdiary makes by itself

By default nexdiary makes a backup every night between three and six and keeps the last seven. Under Settings, Backup you can choose “every week” or “off”, and “Back up now” makes one by hand. A backup is a ZIP file with the database, which nexdiary copies cleanly while it runs, with the photos and with secret.key. The master key is never in it.

The backups lie in /data/backups, so on the same disk. Copy one somewhere else now and then.

Checking, restoring, moving

“Check” opens a backup and tells you whether it is complete and what restoring would add and remove. “Restore” first backs up the current state and then restarts nexdiary. A backup from a newer version, or from a server with a different master key, is turned away with the reason.

To move, download a backup and the master key, put the key on the new server as keys/master.key in the data folder before nexdiary starts there for the first time, set it up, upload the backup with “Upload a backup”, check it and restore it.

Good to knowThe diaries inside a backup are encrypted, the ZIP file itself is not. Readable in it are account names, mail addresses, times, who shared which day with whom, and secret.key, which opens the mail server's password and the AI service's key. Older backups also hold the keys of accounts deleted since. So keep downloaded backups like a password.

Updating

Shell
docker compose pull
docker compose up -d

On start, nexdiary adds whatever the database lacks, step by step. Before its structure changes, it makes a backup by itself, listed as “before a change”. The way back is under Settings, Backup. An older nexdiary cannot open a database from a newer version; the start says so.

nexdiary never updates itself. “About nexdiary” says when a new version is out. For that, nexdiary asks GitHub as soon as someone opens that page and the last answer is more than a day old. It is on by default, and only the operator switches “Check once a day” off there.

After an update with something new, nexdiary shows every account a window “New in nexdiary” once, with what has been added. Pure bug-fix releases get none.

When someone has forgotten their password

Nobody sets a password for somebody else, the operator included. Whoever forgot theirs gets a link and uses it to choose a new one. The link works once and for 24 hours.

For the family

The operator sends the link under Settings, Accounts with “Send a link to reset”. With a mail server set up it goes out by mail if the account has a mail address; otherwise nexdiary shows it once to pass on. Where a mail server, the public address and sign-in with a password are all set up, the sign-in page also offers “Forgot your password?”.

The second factor stays as it was, and so does the diary. It is not encrypted with the password, so a new password loses nothing.

For the operator

The first account has no mail address, and there is nobody to send it a link. So the operator makes the link on the server, with the command below. Without a name it lists the accounts. It prints the link, or a path when no public address is set; open that at the address you use for nexdiary. The link also ends the wait after too many failed attempts.

Shell
docker exec -it -u nexdiary nexdiary python -m app.reset_link your-name

Good to knowOn Unraid, open the container's console instead and run gosu nexdiary python -m app.reset_link your-name. The command refuses to run as root, because files root creates in /data could no longer be opened by nexdiary. Hence the -u nexdiary and the gosu.

All environment variables

Only what has to be fixed before the first start is listed here. The operator sets everything else in the interface.

VariableDefaultWhat it is for
NEXDIARY_DATA_DIR/dataDatabase, log, backups, keys and languages
NEXDIARY_MEDIA_DIR<data>/mediaThe photos
NEXDIARY_LOCALES_DIR<data>/localesExtra languages, one JSON file each
NEXDIARY_MASTER_KEY_FILE<data>/keys/master.keyWhere the master key lies; keep it outside the backups
NEXDIARY_SECRET_KEYmade on first startProtects secrets on the server; when set, it wins over secret.key
NEXDIARY_PUBLIC_URLfrom the requestThe family's address, for invitation links, the sign-in provider, passkeys and push; the setting in the interface wins
NEXDIARY_TRUSTED_PROXIESnoneAddresses or networks of proxies whose X-Forwarded-For is believed, comma separated
NEXDIARY_SETUP_TOKENmade at every start until set upThe code for the first account
NEXDIARY_OPERATOR_NETWORKSnoneNetworks from which the operator's settings may be changed
NEXDIARY_SESSION_DAYS30After this many days without use, a sign-in with “stay signed in” ends
NEXDIARY_COOKIE_SECUREautoon, off or auto (from the request or X-Forwarded-Proto)
NEXDIARY_COOKIE_SUFFIXnoneAn ending for the cookie names when two nexdiary instances run on one machine
NEXDIARY_LOG_LEVELsettingquiet, normal, detailed or trace; overrides the setting
NEXDIARY_API_DOCSfalseServes /api/docs and /api/openapi.json
NEXDIARY_DECODE_SLOTS1How many photos are unpacked at once, 1 to 16, about 150 MB each
NEXDIARY_UPDATE_URLGitHubWhere nexdiary asks for the newest version
NEXDIARY_ARGON2_TIME, NEXDIARY_ARGON2_MEMORY_KIB, NEXDIARY_ARGON2_PARALLELISM3, 65536, 2The effort that goes into storing passwords; only the tests lower it
NEXDIARY_FRONTEND_DIST/app/staticWhere the built interface lies; the image sets it
NEXDIARY_DISABLE_BACKGROUNDfalseSwitches off the work in the background, such as reminders, backups and time capsules; for tests only
NEXDIARY_PORT8000The port inside the container, needed only with host networking
PUID, PGID1000Who owns the files in the data folder; 0 is not allowed, nexdiary never runs as root
TZEurope/Berlin in the exampleThe container's time zone, for the log and the day of the family question; everything else follows each person's own time zone