Astrolabe Documentation العربية GitHub

Configuration

Every .env key, the Settings panel inside the app, and which of the two wins when both say something.


There are two places to configure Astrolabe, and they mostly cover the same ground.

  1. An .env file. This is a plain text file next to the app, one KEY=value per line. The server reads it once, when it starts. To change something here you edit the file and restart.
  2. The Settings panel. This is inside the app itself. When you change something there, the server writes it to a file called settings.json in its data directory, and the change takes effect immediately. No restart.

Most settings exist in both places. When they disagree, the Settings panel wins: a value saved in the panel overrides the same key in .env. If you clear the field in the panel, the .env value takes over again. A few keys are the exception: the security-sensitive ones (the password, the session secret, the port, and so on) live in .env only, and the panel never shows or changes them.

Updating a server you run yourself

The server reads its version from package.json, and the client carries the version it was built with. After git pull, run npm run build and restart: the pull moves the version, the build moves the files. If an open tab outlives a deploy it says Astrolabe X is now on the server; reload to catch up, once. If a reload brings the same old build back — the files were never rebuilt, or a service worker is still handing out the old shell — the app says so instead, once per version, and stops asking: the server says it is Astrolabe X but serves the Y build. That line means exactly one thing: run npm run build (or reinstall the package) on the machine that runs the server. The desktop app and the Android app ship their own build with their own server, so they never show it.

Environment variables

An environment variable is a named value the server reads when it starts. You can set it in .env or in the shell that starts the server; either way it reaches the same place.

The npm scripts load .env on their own (node --env-file-if-exists=.env), so you never need export or source. The file .env.example in the repository root lists every key with a comment explaining it. The table below is the short version.

KeyWhat
PORTThe port the server listens on (default 6801)
HOSTThe address the server listens on (default 0.0.0.0, which means every network interface). If you listen on anything other than the local machine and have no password, the server prints a loud warning at startup: anyone who can reach the port is an admin
ASTROLABE_VAULTThe vault folder — the folder that holds your notes (default ./vault). A --vault <path> argument on the command line takes precedence over this
ASTROLABE_DATAThe server's data folder (default ./data). It holds settings.json, the comments database (SQLite), your custom.css, designs.json, the git credentials file, the clipper's token (clip-token), fonts/ (your own font files, plus the cached catalog in fonts/catalog/ and uploads in fonts/custom/), versions/ (note history), author-sites.json, and the three ledgers that are yours rather than the machine's: layouts.json, books.json and annotations.json. Six of these files — settings.json, designs.json, custom.css, layouts.json, books.json, annotations.json — and the fonts/ folder are mirrored into <vault>/.astrolabe/, a dot-folder Obsidian never lists, so a second server over the same vault starts from them (see Settings travel with the vault)
ADMIN_PASSWORD_HASHThe admin password, stored as an argon2id hash — a fingerprint the server can check a password against but cannot turn back into the password. npm run hash-password makes one. When it is not set, the app runs in open local mode: no password, everyone is an admin
SESSION_SECRETA long random string used to sign login cookies (the small token your browser keeps to prove you are signed in). When it is not set, the server invents a new one at every startup, so every restart signs you out
PUBLICfalse requires login even to read notes (default: reading is public, editing needs login). The server refuses to start with PUBLIC=false and no ADMIN_PASSWORD_HASH
SECURE_COOKIEStrue or false to force the Secure flag on the login cookie. When it is not set, the server decides from the request: HTTPS gets the flag, plain HTTP does not (a trusted proxy can say HTTPS through X-Forwarded-Proto)
TRUSTED_PROXIESComma-separated IP addresses, or address ranges in CIDR notation, whose X-Forwarded-For and X-Forwarded-Proto headers are believed (for example 127.0.0.1,::1). When it is not set, both headers are ignored and the rate limit counts by the connecting address
HOME_NOTEThe note a first-time visitor lands on, as a path inside the vault, for example index.md
COMMENTSon (also true, 1, yes) lets readers leave comments under published notes (default off)
NOTE_VERSIONSoff (also false, 0, no) stops the app keeping a copy of every note before each save in ASTROLABE_DATA/versions/ (default on) — see Versions, before and beside git
PDF_SEARCHoff (also false, 0, no) stops the sidebar search from reading the text of the PDFs on your shelf (default on; see Searching inside every book)
SPEAK_EXTERNALon (also true, 1, yes) lets the admin set Read aloud's external speaker, a program the server runs as its own user (default off: none can be saved, and one saved earlier is never run). .env only — the operator's decision, not the admin password's. The desktop app is its own operator and turns it on
OLLAMA_HOSTWhere Ask the vault finds Ollama — the same variable Ollama itself reads (default http://127.0.0.1:11434)
SITE_NAMEThe site's name, shown in the sidebar, in page titles and on the login dialog (default Astrolabe)
SITE_TAGLINEA short line under the site name, in blog mode
SITE_FOOTERThe footer line in blog mode. {year} and {siteName} are filled in (default © {year} {siteName})
SITE_URLThe site's public address, for RSS and canonical links, for example https://notes.example.com. When it is not set, it is worked out from each request. .env only — the panel has no field for it
LEGACY_HOSTSOld hostnames the site used to answer on, comma-separated. A request that arrives on one of them is redirected permanently to the same path on SITE_URL, so old links keep working after a rename. Needs SITE_URL; .env only
DEFAULT_THEMEThe theme a visitor sees before choosing one: any of the forty-six built-in themes, custom:<name> for one you built (see Theming), or follow. Unset means follow: visitors get whichever theme you are editing in. Case does not matter; an unknown name is ignored with one line on stderr
EXCLUDE_TAGSComma-separated tags to hide from the public site's topic lists and tag pills — typically workflow tags like draft,seedling. Case does not matter and a leading # is fine. The admin's own views are not affected
PUBLIC_LAYOUTWhat a visitor sees: blog for a classic blog layout (see Blog mode), designed for a home page you compose yourself (see Designer), anything else for app, the read-only app (the default)
SITE_LANGThe site's language: en (default) or ar. With ar every interface string is Arabic and the whole interface is mirrored right-to-left (see Arabic & RTL). The language you edit in is a separate choice, per browser: Settings → Language → Your language
BLOG_LOCALEA language-and-region code (a BCP47 tag like ar-EG or en-GB) that decides the digits in post dates and the RSS feed's language (default: follows SITE_LANG). Month names follow the interface language when the visitor language switch is on
LANGUAGE_FILTERWhich published notes the public site shows, by the language they are written in: off (default, show all) · follow (each reader sees their own language) · ar · en. The old values true and false still work — see Language filter
ATTACHMENTS_DIRThe vault folder that uploads from inside the app are saved into (default Attachments, or مرفقات on an Arabic site; an existing attachments folder is kept). It is created when first needed. The Attachments setting can send uploads elsewhere entirely — see Attachments
BANNER_FALLBACKThe header image for blog posts that have no banner: of their own — generated (default: an abstract gradient made from the note's title, always the same for the same title) or none
ASTROLABE_GIT_SSH_COMMANDThe one GIT_* variable Astrolabe passes on to git, unchanged, as GIT_SSH_COMMAND — see Backup & sync

If you installed this when it was called Vellum. Every key above still answers to its old spelling: VELLUM_VAULT, VELLUM_DATA and the rest are read when the ASTROLABE_* key is not set, so a .env, a systemd unit or a shell alias written before the rename keeps working. When both are set the new spelling wins, and the startup line names the old keys it leaned on, once. /vellum.sty is still served beside /astrolabe.sty, for papers written against the old package name.

Request size limits. Every request to the server is capped in size before anything reads it, and there is no key for this: 10 MB on any /api request, and a much smaller 64 KB on the two things anonymous visitors can send (comments and login attempts). Anything bigger is refused with HTTP 413 ("request too large") instead of being held in memory. Uploads have their own, separate allowance. If you run the app behind a proxy, a matching limit there is a sensible extra layer — in nginx, client_max_body_size 10m;, or 256m if you will drop films into notes, since a video upload's own allowance is 256 MB.

The Settings panel

Most of the site-identity keys above can also be changed at runtime, from the app — no .env edit, no restart. As admin, open Settings (the gear in the top cluster, or the command palette). Its rail has two levels: four groups — You, Your site, Data and App — each a heading over short pages named for what you came to do rather than for where a value is stored. A page answers one question, opens with its name and one sentence saying what it decides, and shows at most ten rows before its Advanced line. A search box above the rail finds any row by its name, its one-line help, the paragraph behind its ⓘ or its environment variable, and takes you to it wherever it lives. On a phone the same four groups are headed lists, and each page is a screen of its own.

One row, one look. Every row is a label, one line of help under it, and one control in a single column at the right (at the left in Arabic): a switch, a set of segments, a list, a row of named chips, a slider whose value sits in the label (Screen warmth · 30%), a path field with Pick… inside it, a text field, or — for the few rows that are tables — the row's full width. A switch has no "On"/"Off" beside it: the label says what on means. A ⓘ beside a label opens a paragraph under the row saying why you would change it, and — where one stands behind it — the environment variable, ready to copy.

Saved, or kept here. A row kept in this browser saves itself the moment you choose. A page made only of such rows (Appearance, This device) says so once under its sentence; elsewhere the few that are wear a small This device mark. Every other row is the site's, and a Save bar rises at the foot as soon as one of them changes (with Discard beside it), and goes when you save.

You

  • Appearance — your theme and the two eye-comfort sliders (see Theming), which edge the notes sidebar sits on, and the writing column's width. All of it is kept on this device.
  • Layout & type — the direction and alignment of note prose, which any note may override from its own frontmatter (see Note direction & alignment), and the four font slots (reading text / interface / code / Arabic face) over a curated, self-hosted catalog or faces you upload yourself, with a live specimen that stays on screen while you choose (see Typography).
  • Language — your language (Follow site / English / العربية — the app's own words for you on this device, never what visitors get) beside the site language (what visitors read it in); Spellcheck in — one row of chips naming the languages whose lines are handed to the spellchecker: in a browser the four the editor recognises, none until you choose; in the desktop app the dictionaries your computer really has (see the editor); and for visitors, the language filter and the optional visitor switch.
  • Dates & calendar — the date calendar (Gregorian / Hijri / both, with a live specimen of today, and with Both which one leads and the mark between them — see Hijri dates); under Advanced, the date locale.
  • Writing — Open on launch (where the app opens — where you left off, the Sigils page, the Orbits shelf, today's note, or a note of your choosing — on top of the restored session, and never over a pasted link), the formatting toolbar, Auto-correct French, the properties card (off hides it in your own views — visitors still see it; see the editor) with the empty-note card under it; where new attachments are written (see Attachments), the tags folder and the tag labels table — display names for canonical tags, for a front end that should read «برمجيات» over a vault that keeps #software (see Localised tag labels); under Advanced, the drawings folder.
  • New notes & templates — the templates folder and the template for new notes, the periodic notes (one table: the folder the four kinds share, and a name and a template each for the day, the week, the month and the year), the unique note's folder and name, and the capture inbox and the clipper.
  • Reading — numbered headings in the reading view, search inside books (PDF search) and feeds with the note that lists them; under Advanced, the hadith corpus folder (the notes that answer > [!hadith] callouts — see Ayah and hadith callouts).
  • Read aloud & voice notes — Read aloud and whether your blog's readers may listen; the voice notes' transcription language, the model and where it runs, and whether recordings are kept (see Capture); under Advanced, your own voices.

Your site

  • Site identity — name, tagline, a logo image (replaces the text wordmark in the sidebar and the blog masthead), a favicon (served at /favicon.ico with its real content type and injected into every page's <link rel="icon">), the default theme visitors arrive on and the ambient masthead; under Advanced, the footer line.
  • Publishing — how much of the site is public, said in numbers at the top; the public layout (app / blog / designed, with the door to the designer under it); the home page — classic note mode with a chosen home note, or the dashboard magazine layout, plus an optional hero banner (read by the blog and designed layouts only, so with Public layout: app the page greys them and says so); share buttons and external video; under Advanced, excluded tags and your other sites.
  • Comments & mentions — comments, webmentions and the fediverse, each off until you turn it on.
  • Collections — whether categories come from tags or from folders, and your own hand-made collections and where they sit. See Blog mode.
  • Library — the public shelf: on or off, its name, where its door is, which folders fill it and the exceptions. See The library.

Data

  • Backup & sync — commit the vault and push it to a private git remote you own, manually or on a timer (off until you turn it on); under Advanced, the branch and pull-first. See Backup & sync.
  • Versions & travel — keep a copy of each note before every save; what the vault's .astrolabe/ folder carries to the next machine; and whether this browser's preferences travel with it.
  • Ask — which models read the notes and answer about them, with the embedding model and the passages per answer under Advanced. See Ask the vault.

App

  • This device — the offline copy of what you open, Vim keys (with relative line numbers), the what's-new deck after an update, and in the desktop app only its name, its icon, a launcher entry and Software updates (see the desktop app). All of it is kept on this device.
  • About — the version, the Node version, the vault's counts, and the absolute paths of the vault, the data directory, settings.json and the uploaded-fonts folder.

A pocket vault (a GitHub repository opened on the Android app) shows fourteen: Publishing, Comments & mentions, Collections, Library and Ask need a server, and the rows it cannot keep are drawn greyed, with one line saying why.

Image fields reuse the banner machinery: pick from the vault's attachments or upload right there (drag & drop; bytes are sniffed; lands wherever the Attachments setting points).

Attachments

An attachment is any file you put into the vault that is not a note — a picture, a PDF, an audio clip. Where new attachments go is a setting, named the same way Obsidian names it (Default location for new attachments), so a vault that moved from Obsidian behaves the way its owner already expects. It lives in Settings → Writing → New attachments, beside the templates folder and the tags folder.

ModeAn upload lands in
Vault rootthe top of the vault
Same folder as the notebeside the note being edited
Subfolder of the note's folder<note's folder>/<name> — e.g. an assets next to each note
Specified folder (default)one fixed vault-relative folder — ATTACHMENTS_DIR, else Attachments (مرفقات on an Arabic instance); a vault that already has an attachments folder keeps it

The setting only decides for uploads that did not name a place themselves: a picture pasted into a note, or a file dropped into the editor. A file dropped onto a folder in the sidebar tree already names a place, and lands in that folder.

The folder you type is checked like every vault path: it must stay inside the vault, it cannot be a dot-folder (a folder whose name starts with . — the tree, the indexer and the file watcher all ignore those), and it is created when first needed. Attachments you already have are never moved. The setting decides where the next upload goes; existing embeds keep working because a note finds its images by file name, whatever folder they are in.

Every way of uploading obeys the setting: paste or drop in the editor, drop onto the sidebar tree, and the upload button in any picker. A note's banner and a Media entry's cover count as uploads into that note, so under Same folder and Subfolder the picture lands beside the note (or the tracker note) it belongs to. The site-wide pickers — home banner, logo, favicon — belong to no note and are measured from the vault root. Fonts (ASTROLABE_DATA/fonts) and custom.css have their own homes and are not affected.

Any file the vault can hold, not just images. POST /api/upload accepts images (png, jpeg, webp, gif, svg, avif, heic, bmp), PDF, audio (mp3, m4a, wav, ogg, oga, opus, flac) and video (mp4, m4v, mov, webm, mkv, ogv). A film may be up to 256 MB and is written to disk as it arrives; every other file is capped at 10 MB. The contents of the file are inspected, so a program renamed to .png is refused whatever its extension says. Anything not on that list is refused in the browser, before the upload starts, with a message naming what was refused and what would have been accepted.

Drop files anywhere on the tree. Drag files from your file manager onto a folder in the sidebar (or onto a note — they land beside it) and they are added to the vault. The row lights up and says how many files are coming. Afterwards a toast names the folder they actually landed in and offers Undo, which moves them to .trash/. If a name is already taken, the new file gets the first free name-2.ext and the toast says so.

Deleting tells you what it is really taking. The sidebar tree shows notes only. So a folder that still held four images after its note moved away used to describe itself as "0 notes" — and deleting it silently broke a published essay. Now every delete confirmation asks the server what is actually inside:

Move "Media" to .trash? 0 notes, 60 attachments — 53 of them referenced by 48 notes. All of it moves to the vault's .trash folder — recoverable from disk.

When only a few notes reference the files, they are named. Only notes that survive the delete count as breakage; a note that goes in the same act is not a broken link. Both kinds of link count — wikilink embeds (![[fig.png]]) and Markdown links (![](assets/fig.png)) — and so does a note's banner:. The confirmation for a permanent delete repeats the same inventory, and deleting a single attachment (the × on a row in the banner picker's list) asks the same question.

Every control in the panel is drawn by Astrolabe, not by your operating system. A dropdown list is a themed popover attached to its button and kept inside the panel: it grows no taller than the room available, flips upward when there is no room below, and takes arrow keys and type-ahead, Enter to confirm and Esc to put the old value back. Switches are switches; three-way rows (inherit / on / off) show all three states at once; numbers carry their unit inside the field. The reason: a native <select> opens a window drawn by the operating system, which no theme can style and no panel can keep inside its bounds — exactly what a font list of twenty-seven faces must not do.

On a phone (the phone layout) the panel is a list of the same nine sections, in the same order and under the same names — More → Settings — with the same search above it, and each section is a screen of its own showing the same rows. As soon as a section holds a change, a bar rises from the bottom with Discard and Save; leaving the section any other way with changes unsaved asks first. A row marked This device saves itself as you choose and never raises the bar.

Settings keys

These are the keys ASTROLABE_DATA/settings.json can hold. The panel writes them, and so does PATCH /api/settings. Any key that is absent falls back to its .env default from the table above.

KeyValuesDefault
siteNamestring, ≤ 80 charsSITE_NAME, else Astrolabe
taglinestring, ≤ 160SITE_TAGLINE, else none
footerstring, ≤ 200SITE_FOOTER, else © {year} {siteName}
defaultThemeone of the forty-six ids, custom:<name> for a theme that exists, or follow (visitors track your editor theme)DEFAULT_THEME, else follow
adminThemeone theme id — written by the app, not by hand: your own editor theme, mirrored from your browser so follow has something to servenone until you pick a theme
publicLayoutapp · blog · designedPUBLIC_LAYOUT, else app
blogLocalelanguage-and-region code (BCP47), ≤ 35 chars, tidied into its standard form on saveBLOG_LOCALE, else ar when the language is Arabic, else en
languageen · arSITE_LANG, else en
languageFilteroff · follow · ar · enLANGUAGE_FILTER, else off
languageToggleboolean — the public EN/ع switch. No env counterpartfalse
topicstags · folders — where the public site's categories come from (Settings → Collections)tags
excludeTagsarray of strings, ≤ 200 entries, ≤ 50 chars eachEXCLUDE_TAGS, else empty
commentsEnabledbooleanCOMMENTS, else false
noteVersionsboolean — keep a version of every note before each save (Settings → Backup & sync)NOTE_VERSIONS, else true
shareButtonsboolean — the share row under blog articlestrue
authorSitesarray of { url } (https); each site's title and preview image are fetched once (from its OpenGraph tags) and cached in ASTROLABE_DATA/author-sites.json; rendered on the blog as More from the author cards. No env counterpartempty
ambientboolean — a slow decorative atmosphere behind the public masthead, drawn per theme (see Theming)false
pdfSearchboolean — the sidebar search reads the pages of every PDF on the shelf (see Searching inside every book)PDF_SEARCH, else true
externalVideoboolean — a YouTube, Vimeo or PeerTube link on a line of its own plays in place, in the app and on the blog (Settings → Publishing → Embed external video; see Embeds). No env counterpartfalse
feeds{ fetch, note } — feeds: whether the server may fetch the feeds you follow (Settings → Reading → Feeds), and the note that lists themfetch: false, note: Feeds.md
voice{ model, backend, language, keepAudio } — voice notes: the transcription model (base-q5_1 · small-q5_1 · large-v3-turbo-q5_0 · large-v3-turbo · off), where it runs (auto · cpu, the processor only), the language (auto · ar · en), and whether the recording is keptsmall-q5_1, auto, auto, true
speak{ engine, rate, voices, public } — Read aloud: the engine (light · natural), the pace (0.8 · 1 · 1.2), a chosen voice per language, and whether the blog's readers may listen. Two more sub-keys, voicesDir (your own voices folder) and external ({ command, langs }, the external speaker), are accepted here but written to ASTROLABE_DATA/speak-local.json, never to settings.json: they name this machine's paths and programs, and do not travellight, 1, each engine's first voice, false
webmentions{ accept, send } — webmentions: receive them into moderation, and tell the sites a post links to when it is published (Settings → Comments & mentions → Webmentions). No env counterpartboth false
fediverse{ enabled, handle } — the blog as one fediverse account, and the name before the @ (1–30 letters, digits or underscores). No env counterpartenabled: false; the handle is the site's name folded to that alphabet, else blog
ask{ provider, chatModel, anthropicModel, embedModel, topK } — Ask the vault: who answers (ollama · anthropic), the model names, and how many passages an answer reads (2–12). The Anthropic key is not here: it is write-only and lives in ASTROLABE_DATA/ask-credentials.json, which never travelsollama, qwen3.5:9b, claude-sonnet-5, embeddinggemma, 6
faviconvault-relative image (.ico .png .svg .jpg .jpeg .gif .webp .avif)none
logohttps URL or vault-relative imagenone
home.modenote · dashboardnote
home.notevault-relative note (.md / .tex / .latex)HOME_NOTE
home.bannerhttps URL or vault imagenone — a generated gradient seeded from the site name
publicFolders{ enabled, nav, home, folders[] } — the hand-made collections: whether they are on, a door in the navigation, a band on the home page, and up to 12 folders, each with a slug (≤ 60), a title (≤ 60), a description (≤ 200), a mark and an optional hidden flagoff; home: true
library{ enabled, nav, home, title, paths[] } — the library: on or off, a door in the navigation (on by default once the library is), a shelf on the home page, a name (≤ 40) and up to 24 paths, each a vault folder with a title (≤ 80), a blurb (≤ 300) and a kindoff
attachments.modevault-root · same-folder · subfolder · specifiedspecified
attachments.foldervault-relative folder, ≤ 180 chars; read by subfolder and specified only. No traversal, no absolute path, no dot-folderATTACHMENTS_DIR, else an existing attachments/Attachments/مرفقات, else Attachments (مرفقات on an Arabic instance)
templatesFoldervault-relative folderauto-detected (Templates, _templates, قوالب), else none
hadithFoldervault-relative folder whose notes (with collection: and number: in their frontmatter) answer > [!hadith] calloutsauto-detected (hadith, Corpus/hadith, أحاديث), else none
drawingsFoldervault-relative folder the sidebar's pencil starts a drawing innone — the vault root
defaultTemplatevault-relative note applied to every new notenone
dailyFoldervault-relative folder the periodic notes live in; "" for the vault rootdaily
dailyFormata period format naming the year, month and day (YYYY, MM, DD, [literals], /)YYYY-MM-DD
weeklyFormata period format naming the year and the ISO week (ww); "" turns weekly notes offYYYY-[W]ww
monthlyFormata period format naming the year and the month and nothing finer; "" turns monthly notes offYYYY-MM
yearlyFormata period format naming the year and nothing finer; "" turns yearly notes offYYYY
dailyTemplate / weeklyTemplate / monthlyTemplate / yearlyTemplatevault-relative note applied when that period's note is creatednone (the day falls back to defaultTemplate)
launchresume · sigils · orbits · today · a vault-relative note — what the admin's shell opens on top of the restored session (see Periodic notes). No env counterpartresume
uniqueFoldervault-relative folder the palette's New unique note files into (see Unique notes)none — the vault root
uniqueFormatthe unique note's name: the daily tokens plus HH, mm, ss; must name the year and something finer than a dayYYYYMMDDHHmm
captureInboxvault-relative note the quick-capture sheet can drop lines into instead of today's notenone — today's note only
dateCalendargregorian · hijri · bothgregorian
dateOrderauto · hijri-first · gregorian-first — which calendar leads in bothauto (by the site language)
dateSeparatorbar · dot · parens — what stands between the two in bothbar
textDirectionauto · ltr · rtlauto
emptyPropsCardtrue · false — the one-line properties card on notes that have no frontmattertrue
propsCardtrue · false — the properties card at all, in the owner's editor and reading view (visitors always see it)true
textAlignstart · left · right · center · justifystart
tagsFoldervault-relative folder holding tag pagesauto-detected, else tags
tagLabels{ tag: { en, ar } }, ≤ 200 tags — replaced whole, not mergedempty
folderIcons{ \"folder/path\": \"mark\" }, ≤ 200 folders — the folder marks the tree draws; a mark not in the catalog is droppedempty
fonts.prose / .ui / .mono / .arabica catalog id, custom:<file> for an upload, or systemsystem
fonts.arabicSizeAdjustinteger percent, 50–300the catalog face's own measured value, or none
gitSync.enabledbooleanfalse
gitSync.remotehttps://…, ssh://… or git@host:path, no embedded credentialsnone
gitSync.branchstringmain
gitSync.intervalMinutesinteger 0–1440; 0 is manual only0
gitSync.pullFirstboolean — pull the remote before each sync, and only if it merely adds on top of what you have (a fast-forward)true
gitSync.authModessh · tokenssh

Two more keys are write-only: gitToken and gitUser. PATCH /api/settings accepts them and stores them in ASTROLABE_DATA/git-credentials.json, readable only by the system user the server runs as (mode 0600). They never go into settings.json and can never be read back: a read answers gitSync.tokenSet: true and the username, nothing more.

settings.json is written atomically, meaning the file is either fully old or fully new — a crash in the middle cannot leave it half-written. Changes apply live: the site name, the layout, the default theme, the excluded tags, the comment routes and the favicon all update without a restart. If the file is ever corrupted, the server logs one warning and runs on the .env defaults.

The security-sensitive keys are deliberately .env only, forever. The panel and /api/settings can neither read nor write them: ADMIN_PASSWORD_HASH, SESSION_SECRET, TRUSTED_PROXIES, PORT, HOST, ASTROLABE_VAULT, ASTROLABE_DATA, PUBLIC. SITE_URL is .env only too, for a duller reason: nothing has ever needed to change it while the server runs.

The settings API

For scripts. Admin only; a visitor gets a 404.

  • GET /api/settings returns the stored keys, plus effective (the merged values actually in use), the font catalog, and an about block (version, Node version, absolute paths, counts).
  • PATCH /api/settings takes a partial object. Only the keys you name change; null clears a key so it falls back to .env. Validation is strict — an unknown key is a 400 — and the answer has the same shape as GET. The git credential keys additionally require that the instance has a real password.

Edit this page on GitHub

Astrolabe is free software. These pages are built from the Markdown in the repo's docs folder.