Server Base URL Resolution#
serverURL is a per-request computed property on the ThinkJS context that provides an absolute base URL for the Waline server. It is the single source of truth for constructing all outbound URLs — OAuth redirects, email verification links, RSS feeds, and the admin dashboard's API endpoint.
Resolution Logic#
The serverURL getter in packages/server/src/config/extend.js applies this priority chain:
SERVER_URLenv var — if set, it is returned verbatim. Use this whenever the server is behind a reverse proxy, load balancer, or any configuration where the observedhostheader differs from the public URL.- Netlify environment — detected via
think.env === 'netlify'. The base URL becomes${protocol}://${host}${netlifyFunctionPrefix}, wherenetlifyFunctionPrefixis derived from the_HANDLERenvironment variable . This prefix accounts for Netlify Functions' path structure (e.g./.netlify/functions/server). - Request protocol + host fallback —
${protocol}://${host}, derived directly from the incoming HTTP request. This is the default for self-hosted or Vercel/Railway deployments that surface the correct host header.
Important: If your deployment sits behind a reverse proxy and the host header is an internal name, you must set
SERVER_URLexplicitly or all server-generated links will be broken.
Consumers of ctx.serverURL#
| Feature | File | Usage |
|---|---|---|
| Admin dashboard bootstrap | middleware/dashboard.js:19 | Sets window.serverURL = '${ctx.serverURL}/api/' so the SPA knows the API root |
| OAuth redirect URLs | controller/oauth.js:14-15, 33-37 | Builds the redirect callback passed to the OAuth provider |
| User registration email | controller/user.js:94-97 | Constructs the /verification?token=…&email=… link |
| Password reset email | controller/user/password.js:25 | Constructs the /ui/profile?token=… link |
| RSS feed channel link | controller/comment/rss.js:61 | Falls back to ctx.serverURL when SITE_URL env var is absent |
| Akismet spam check | controller/comment.js | Passes the server URL to the Akismet API |
RSS Feed: SITE_URL vs SERVER_URL#
The RSS controller resolves its channel link as process.env.SITE_URL || this.ctx.serverURL . SITE_URL is the public-facing blog/site URL, while SERVER_URL is the Waline API server URL — they are often different. The buildAbsoluteUrl helper then prepends the resolved base URL to relative comment paths, short-circuiting if the path is already an absolute URL.
Demo Page: Client-Side serverURL#
The root indexAction in controller/index.js derives serverURL client-side using location.protocol + '//' + location.host + location.pathname.replace(/\/+$/, ''). This is only used for the built-in example/demo page and does not interact with the server-side ctx.serverURL getter.
Key Files#
- Resolution logic:
packages/server/src/config/extend.js— theserverURLgetter - Netlify detection:
packages/server/src/config/netlify.js—isNetlify+netlifyFunctionPrefix - Dashboard injection:
packages/server/src/middleware/dashboard.js - OAuth redirect construction:
packages/server/src/controller/oauth.js - RSS feed construction:
packages/server/src/controller/comment/rss.js