Compare commits

..
Author SHA1 Message Date
ajnart f7b594c8ca fix(backup): prompt re-login after restore 2026-09-06 10:21:28 +02:00
7 changed files with 49 additions and 34 deletions

No files matched your search

+7 -9
View File
@@ -1,24 +1,22 @@
# Since .env is gitignored, you can use .env.example to build a new `.env` file when you clone the repo.
# Keep this file up-to-date when you add new variables to `.env`.
# Keep this file up-to-date when you add new variables to \`.env\`.
# This file will be committed to version control, so make sure not to have any secrets in it.
# If you are cloning this repo, create a copy of this file named `.env` and populate it with your secrets.
# Generate two different 64-character hex values with `openssl rand -hex 32` before starting Homarr.
# Never reuse these values or commit the populated `.env` file.
AUTH_SECRET=
# The below secret is not used anywhere but required for Auth.js (Would encrypt JWTs and Mail hashes, both not used)
AUTH_SECRET="supersecret"
# The below secret is used to encrypt integration secrets in the database.
# Homarr will reject an empty or invalid value and print a randomly generated candidate.
SECRET_ENCRYPTION_KEY=
# It should be a 32-byte string, generated by running `openssl rand -hex 32` on Unix
# or starting the project without any (which will show a randomly generated one).
SECRET_ENCRYPTION_KEY=0000000000000000000000000000000000000000000000000000000000000000
LOG_LEVEL='info'
# This is how you can use the sqlite driver:
DB_DRIVER='better-sqlite3'
# Safe local source-development path. SQLite files are ignored by Git.
# Container images use /appdata/db/db.sqlite by default instead.
DB_URL='./db.sqlite'
DB_URL='FULL_PATH_TO_YOUR_SQLITE_DB_FILE'
# Those are the two ways to use the mysql2 driver:
# 1. Using the URL format:
@@ -244,21 +244,18 @@ Homarr supports multiple authentication options, from internal userbase (credent
- Create a group (e.g., `homarr-admins`) and assign users who require admin access.
**2. Example .env file:**
Generate `SECRET_ENCRYPTION_KEY` with `openssl rand -hex 32`; do not copy an example key between installs.
```env
OIDC_CLIENT_ID=<REPLACE_WITH_OIDC_CLIENT_ID>
OIDC_CLIENT_SECRET=<REPLACE_WITH_OIDC_CLIENT_SECRET>
OIDC_CLIENT_ID=identificationid #OIDC client ID
OIDC_CLIENT_SECRET=secretsecretsecret #OIDC client secret
OIDC_SLUG=homarr #Application slug in Authentik
AUTH_DOMAIN=auth.example.com #Authentik FQDN
ADMIN_GROUP=homarr-admins #Authentik group for Homarr admins
HOMARR_FQDN=homarr.example.com #Homarr FQDN
SECRET_ENCRYPTION_KEY=<REPLACE_WITH_64_HEX_CHARACTERS>
SECRET_ENCRYPTION_KEY=encryptencryptencrypt #Homarr encryption key
```
**3. Example Docker Compose configuration:**
```yaml {14-24}
```yaml {14-26}
services:
homarr:
image: ghcr.io/homarr-labs/homarr:latest
@@ -272,6 +269,8 @@ Homarr supports multiple authentication options, from internal userbase (credent
environment:
- TZ=America/Los_Angeles
- SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
- BASE_URL=https://${HOMARR_FQDN}
- NEXTAUTH_URL=https://${HOMARR_FQDN}
- AUTH_PROVIDERS=oidc #(optional: include ',credentials' to keep local accounts as fallback)
- AUTH_OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
- AUTH_OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
@@ -323,18 +322,15 @@ Homarr supports multiple authentication options, from internal userbase (credent
- Record the `Client-ID` and `Client Key` (secret).
**2. Example .env file (Homarr):**
Generate `SECRET_ENCRYPTION_KEY` with `openssl rand -hex 32`; do not copy an example key between installs.
```env
OIDC_CLIENT_ID=<REPLACE_WITH_GOOGLE_CLIENT_ID>
OIDC_CLIENT_SECRET=<REPLACE_WITH_GOOGLE_CLIENT_SECRET>
OIDC_CLIENT_ID=identificationid #Google Client-ID
OIDC_CLIENT_SECRET=secretsecretsecret #Google Client Key (secret)
HOMARR_FQDN=homarr.example.com #Homarr FQDN
SECRET_ENCRYPTION_KEY=<REPLACE_WITH_64_HEX_CHARACTERS>
SECRET_ENCRYPTION_KEY=encryptencryptencrypt #Homarr encryption key
```
**3. Example Docker Compose configuration (Homarr):**
```yaml {14-20}
```yaml {16-22}
services:
homarr:
image: ghcr.io/homarr-labs/homarr:latest
@@ -348,6 +344,8 @@ Homarr supports multiple authentication options, from internal userbase (credent
environment:
- TZ=Europe/Berlin
- SECRET_ENCRYPTION_KEY=${SECRET_ENCRYPTION_KEY}
- BASE_URL=https://${HOMARR_FQDN}
- NEXTAUTH_URL=https://${HOMARR_FQDN}
- AUTH_PROVIDERS=oidc #(optional: include ',credentials' to keep local accounts as fallback)
- AUTH_OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
- AUTH_OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
@@ -38,14 +38,13 @@ This method is only useful, when you want to develop on Homarr or extend it with
Install all dependencies using <code>pnpm install</code>
</li>
<li>
Copy the `.env.example` file to `.env`. Its `DB_URL='./db.sqlite'` value is ready for local use and stores the
database in the cloned repository. Replace it with an absolute writable path such as
`DB_URL='/home/username/homarr/db.sqlite'` if you want to store the database elsewhere.
Copy the `.env.example` file to `.env` and replace `DB_URL` with the full path you want to use for the sqlite
database file. For example `DB_URL='/home/username/homarr/db.sqlite`
</li>
<li>
Run `openssl rand -hex 32` twice and set `AUTH_SECRET` and `SECRET_ENCRYPTION_KEY` to the two different generated
values. Keep both values secret and preserve `SECRET_ENCRYPTION_KEY` with your backups.
Replace `AUTH_SECRET` and `SECRET_ENCRYPTION_KEY` both with a secure random string by using `openssl rand -hex 32`
</li>
<li>Replace `CRON_JOB_API_KEY` with a secure random string by using `openssl rand -base64 32`</li>
<li>Run `pnpm run db:migration:sqlite:run` and wait that it completes</li>
<li>Build the source using `pnpm build`</li>
<li>
+3 -2
View File
@@ -30,8 +30,9 @@ needed to restore encrypted integration credentials.
Select a Homarr backup ZIP. The browser previews entity counts, board names, and required database migrations before
the archive is uploaded.
Restoring replaces the current SQLite database and cannot be undone. After a successful restore, the Next.js process
restarts and the page reloads when Homarr is ready.
Restoring replaces the current SQLite database and cannot be undone. It also invalidates the current database session.
After a successful management restore, Homarr waits for the restarted server and sends the administrator to sign in
again. The first-run onboarding restore keeps its existing board destination.
A backup can be restored on another Homarr instance. When its `SECRET_ENCRYPTION_KEY` differs, Homarr re-encrypts stored
integration secrets for the target instance. Version metadata is used to apply compatible migrations.
@@ -204,8 +204,12 @@ export const DatabaseRestoreFlow = ({ variant = "card", onRestoreComplete }: Dat
}
onRestoreComplete?.();
const destination =
variant === "standalone" && homeBoardName ? `/boards/${encodeURIComponent(homeBoardName)}` : null;
let destination: string | null = null;
if (variant === "standalone" && homeBoardName) {
destination = `/boards/${encodeURIComponent(homeBoardName)}`;
} else if (variant === "card") {
destination = "/auth/login";
}
startReadinessCheck(restartAfterMs, destination);
}, [file, onRestoreComplete, startReadinessCheck, t, variant]);
@@ -317,6 +321,7 @@ export const DatabaseRestoreFlow = ({ variant = "card", onRestoreComplete }: Dat
<RestoreProgressPanel
active
status={restoreStatus}
reloginRequired={variant === "card"}
onRetry={() => startReadinessCheck(0)}
onReload={() => window.location.reload()}
/>
@@ -11,11 +11,18 @@ export type RestoreProgressStatus = "restoring" | "restarting" | "timedOut";
interface RestoreProgressPanelProps {
active: boolean;
status: RestoreProgressStatus;
reloginRequired?: boolean;
onRetry: () => void;
onReload: () => void;
}
export const RestoreProgressPanel = ({ active, status, onRetry, onReload }: RestoreProgressPanelProps) => {
export const RestoreProgressPanel = ({
active,
status,
reloginRequired = false,
onRetry,
onReload,
}: RestoreProgressPanelProps) => {
const t = useI18n("management.page.tool.backup.restore");
const tCommon = useI18n("common");
const reduceMotion = useReducedMotion();
@@ -63,6 +70,12 @@ export const RestoreProgressPanel = ({ active, status, onRetry, onReload }: Rest
</div>
</Group>
{reloginRequired && !isRestoring ? (
<Text size="sm" c="dimmed">
{t("progress.relogin")}
</Text>
) : null}
{isTimedOut ? (
<Group>
<Button variant="light" onClick={onRetry} leftSection={<IconRefresh size={16} />}>
+2 -1
View File
@@ -6456,7 +6456,8 @@
},
"progress": {
"title": "Restoring database...",
"restarting": "Restarting server"
"restarting": "Restarting server",
"relogin": "Restoring the database invalidated your current session. Homarr will send you to sign in when the server is ready."
},
"timeout": {
"title": "Server did not come back online",