Compare commits

...

1 commit

Author SHA1 Message Date
Nicolas Meienberger
12520a0598 feat: base-url env variable
Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
2026-01-28 00:39:41 +01:00
3 changed files with 57 additions and 12 deletions

View file

@ -51,6 +51,7 @@ services:
- /dev/fuse:/dev/fuse - /dev/fuse:/dev/fuse
environment: environment:
- TZ=Europe/Paris # Set your timezone here - TZ=Europe/Paris # Set your timezone here
- BASE_URL=http://localhost:4096 # URL you will use to access Zerobyte
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /var/lib/zerobyte:/var/lib/zerobyte - /var/lib/zerobyte:/var/lib/zerobyte
@ -77,7 +78,8 @@ Zerobyte can be customized using environment variables. Below are the available
### Environment Variables ### Environment Variables
| Variable | Description | Default | | Variable | Description | Default |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------- | :--------- | | :-------------------- | :-------------------------------------------------------------------------------------------------------------------------- | :--------- |
| `BASE_URL` | The base URL of your Zerobyte instance (e.g., `https://zerobyte.example.com`). See [Authentication](#authentication) below. | (none) |
| `PORT` | The port the web interface and API will listen on. | `4096` | | `PORT` | The port the web interface and API will listen on. | `4096` |
| `RESTIC_HOSTNAME` | The hostname used by Restic when creating snapshots. Automatically detected if a custom hostname is set in Docker. | `zerobyte` | | `RESTIC_HOSTNAME` | The hostname used by Restic when creating snapshots. Automatically detected if a custom hostname is set in Docker. | `zerobyte` |
| `TZ` | Timezone for the container (e.g., `Europe/Paris`). **Crucial for accurate backup scheduling.** | `UTC` | | `TZ` | Timezone for the container (e.g., `Europe/Paris`). **Crucial for accurate backup scheduling.** | `UTC` |
@ -109,6 +111,7 @@ services:
- "4096:4096" - "4096:4096"
environment: environment:
- TZ=Europe/Paris # Set your timezone here - TZ=Europe/Paris # Set your timezone here
- BASE_URL=http://localhost:4096 # Change this to your actual URL (use https:// for secure cookies)
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /var/lib/zerobyte:/var/lib/zerobyte - /var/lib/zerobyte:/var/lib/zerobyte
@ -150,6 +153,7 @@ services:
- /dev/fuse:/dev/fuse - /dev/fuse:/dev/fuse
environment: environment:
- TZ=Europe/Paris - TZ=Europe/Paris
- BASE_URL=http://localhost:4096 # URL you will use to access Zerobyte
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /var/lib/zerobyte:/var/lib/zerobyte - /var/lib/zerobyte:/var/lib/zerobyte
@ -223,6 +227,7 @@ Zerobyte can use [rclone](https://rclone.org/) to support 40+ cloud storage prov
- /dev/fuse:/dev/fuse - /dev/fuse:/dev/fuse
environment: environment:
- TZ=Europe/Paris - TZ=Europe/Paris
- BASE_URL=http://localhost:4096 # URL you will use to access Zerobyte
volumes: volumes:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
- /var/lib/zerobyte:/var/lib/zerobyte - /var/lib/zerobyte:/var/lib/zerobyte
@ -264,6 +269,30 @@ Zerobyte allows you to easily restore your data from backups. To restore data, n
![Preview](https://github.com/nicotsx/zerobyte/blob/main/screenshots/restoring.png?raw=true) ![Preview](https://github.com/nicotsx/zerobyte/blob/main/screenshots/restoring.png?raw=true)
## Authentication
Zerobyte uses [better-auth](https://github.com/better-auth/better-auth) for authentication and session management. The authentication system automatically adapts to your deployment scenario:
### Cookie Security
- **IP Address / HTTP access**: Set `BASE_URL=http://192.168.1.50:4096` (or your IP). Cookies will use `Secure: false`, allowing immediate login without SSL.
- **Domain / HTTPS access**: Set `BASE_URL=https://zerobyte.example.com`. Cookies will automatically use `Secure: true` for protected sessions.
### Reverse Proxy Setup
If you're running Zerobyte behind a reverse proxy (Nginx, Traefik, Caddy, etc.):
1. **Set `BASE_URL`** to your HTTPS domain (e.g., `https://zerobyte.example.com`)
2. The app will automatically enable secure cookies based on the `https://` prefix
3. Ensure your proxy passes the `X-Forwarded-Proto` header
### Important Notes
- The `BASE_URL` must start with `https://` for secure cookies to be enabled
- Local IP addresses (e.g., `http://192.168.x.x`) are **not** treated as secure contexts by browsers, so secure cookies are disabled automatically
- `localhost` is treated as a secure context by browsers even over HTTP, but we still recommend using `BASE_URL` for consistency
- If you don't set `BASE_URL`, the app will work but may have issues with callback URLs in certain authentication flows. All cookies will be set with `Secure: false`.
## Troubleshooting ## Troubleshooting
For troubleshooting common issues, please refer to the [TROUBLESHOOTING.md](TROUBLESHOOTING.md) file. For troubleshooting common issues, please refer to the [TROUBLESHOOTING.md](TROUBLESHOOTING.md) file.
@ -305,6 +334,7 @@ RESTIC_PASS_FILE=./data/restic.pass
RESTIC_CACHE_DIR=./data/restic/cache RESTIC_CACHE_DIR=./data/restic/cache
ZEROBYTE_REPOSITORIES_DIR=./data/repositories ZEROBYTE_REPOSITORIES_DIR=./data/repositories
ZEROBYTE_VOLUMES_DIR=./data/volumes ZEROBYTE_VOLUMES_DIR=./data/volumes
BASE_URL=http://localhost:4096
``` ```
Notes: Notes:

View file

@ -19,13 +19,24 @@ import { authService } from "../server/modules/auth/auth.service";
export type AuthMiddlewareContext = MiddlewareContext<MiddlewareOptions, AuthContext<BetterAuthOptions>>; export type AuthMiddlewareContext = MiddlewareContext<MiddlewareOptions, AuthContext<BetterAuthOptions>>;
const createBetterAuth = (secret: string) => const createBetterAuth = (secret: string) => {
betterAuth({ const origins = new Set([config.baseUrl]);
if (config.trustedOrigins) {
for (const origin of config.trustedOrigins) {
origins.add(origin);
}
}
const trustedOrigins = Array.from(origins).filter((o) => o !== undefined);
return betterAuth({
secret, secret,
trustedOrigins: config.trustedOrigins ?? ["*"], baseURL: config.baseUrl,
trustedOrigins: trustedOrigins,
advanced: { advanced: {
cookiePrefix: "zerobyte", cookiePrefix: "zerobyte",
useSecureCookies: false, useSecureCookies: config.isSecure,
}, },
onAPIError: { onAPIError: {
throw: true, throw: true,
@ -150,6 +161,7 @@ const createBetterAuth = (secret: string) =>
}), }),
], ],
}); });
};
type Auth = ReturnType<typeof createBetterAuth>; type Auth = ReturnType<typeof createBetterAuth>;

View file

@ -35,6 +35,7 @@ const envSchema = type({
TRUSTED_ORIGINS: "string?", TRUSTED_ORIGINS: "string?",
DISABLE_RATE_LIMITING: 'string = "false"', DISABLE_RATE_LIMITING: 'string = "false"',
APP_SECRET: "32 <= string <= 256", APP_SECRET: "32 <= string <= 256",
BASE_URL: "string",
}).pipe((s) => ({ }).pipe((s) => ({
__prod__: s.NODE_ENV === "production", __prod__: s.NODE_ENV === "production",
environment: s.NODE_ENV, environment: s.NODE_ENV,
@ -47,6 +48,8 @@ const envSchema = type({
trustedOrigins: s.TRUSTED_ORIGINS?.split(",").map((origin) => origin.trim()), trustedOrigins: s.TRUSTED_ORIGINS?.split(",").map((origin) => origin.trim()),
disableRateLimiting: s.DISABLE_RATE_LIMITING === "true", disableRateLimiting: s.DISABLE_RATE_LIMITING === "true",
appSecret: s.APP_SECRET, appSecret: s.APP_SECRET,
baseUrl: s.BASE_URL,
isSecure: s.BASE_URL?.startsWith("https://") ?? false,
})); }));
const parseConfig = (env: unknown) => { const parseConfig = (env: unknown) => {