mirror of
https://github.com/ajnart/homarr.git
synced 2026-02-04 05:39:17 +01:00
🐳 Fix issues with dockerfile (#1611)
* Add `wait $PID` to be able to send SIG_ABORT * Move to docker `entrypoint` * Change default NEXTAUTH_URL * Add `VOLUME` instruction * corrected a typo * 🐳 Fix docker TCP not working Fixes Lost docker connection via TCP with 0.14.0 update #1577 * 🚧 Improve dockerfile and start script and fix permission issue by adding new user with permission to read / write to /data folder * 🐛 Cleanup changes, Local db:migrate script not working, CI failed * ✨ Image properties customization (#1590) * 🌐 New Crowdin updates (#1572) * ✨ Add notice page for readonly db * Misc docker changes * 🐳 Add `homarr` as `USER` * 🐛 Unable to use user homarr because db.sqlite file is already owned by root --------- Co-authored-by: Lumilias <10852161+Lumilias@users.noreply.github.com> Co-authored-by: Meier Lukas <meierschlumpf@gmail.com> Co-authored-by: Manuel <30572287+manuel-rw@users.noreply.github.com> Co-authored-by: Manuel <manuel.ruwe@bluewin.ch>
This commit is contained in:
42
src/components/Onboarding/database-not-writeable.tsx
Normal file
42
src/components/Onboarding/database-not-writeable.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import { Center, Code, List, Stack, Text, Title } from '@mantine/core';
|
||||
import Head from 'next/head';
|
||||
|
||||
export const DatabaseNotWriteable = ({ error, errorMessage }: { error: any | unknown, errorMessage: string | undefined }) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Onboard - Error • Homarr</title>
|
||||
</Head>
|
||||
|
||||
<Center h="100%">
|
||||
<Stack align="center" p="lg">
|
||||
<Title order={1} weight={800} size="3rem" opacity={0.8}>
|
||||
Critical error while starting Homarr
|
||||
</Title>
|
||||
<Text size="lg" mb={40}>
|
||||
We detected that Homarr is unable to write to the database. Please troubleshoot using
|
||||
the following steps:
|
||||
</Text>
|
||||
<List>
|
||||
<List.Item>
|
||||
Ensure that you mounted the path <code>/data</code> to a writeable location with
|
||||
enough disk space. For this, you must add the following mounting point to your docker
|
||||
compose: <Code block>{' - <your-path>/data:/data'}</Code>
|
||||
</List.Item>
|
||||
<List.Item>
|
||||
Ensure that you followed the installation instructions at{' '}
|
||||
<a href="https://homarr.dev/docs/introduction/installation">
|
||||
https://homarr.dev/docs/introduction/installation
|
||||
</a>
|
||||
</List.Item>
|
||||
</List>
|
||||
<Code block>{error && JSON.stringify(error)}</Code>
|
||||
|
||||
{errorMessage && (
|
||||
<Code block>{errorMessage}</Code>
|
||||
)}
|
||||
</Stack>
|
||||
</Center>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -47,11 +47,5 @@ const shouldRedirectToOnboard = async (): Promise<boolean> => {
|
||||
return cachedUserCount === 0;
|
||||
};
|
||||
|
||||
if (!process.env.DATABASE_URL?.startsWith('file:')) {
|
||||
return await cacheAndGetUserCount();
|
||||
}
|
||||
|
||||
const fileUri = process.env.DATABASE_URL.substring(4);
|
||||
return await cacheAndGetUserCount();
|
||||
// TODO: Show an error page if the database file is read-only
|
||||
};
|
||||
|
||||
@@ -1,19 +1,28 @@
|
||||
import { Box, Button, Center, Image, Stack, Text, Title, useMantineTheme } from '@mantine/core';
|
||||
import { Button, Center, Image, Stack, Text, Title, useMantineTheme } from '@mantine/core';
|
||||
import { useDisclosure } from '@mantine/hooks';
|
||||
import { IconArrowRight } from '@tabler/icons-react';
|
||||
import Consola from 'consola';
|
||||
import fs from 'fs';
|
||||
import fsPromises from 'fs/promises';
|
||||
import { GetServerSideProps, InferGetServerSidePropsType } from 'next';
|
||||
import Head from 'next/head';
|
||||
import { DatabaseNotWriteable } from '~/components/Onboarding/database-not-writeable';
|
||||
import { OnboardingSteps } from '~/components/Onboarding/onboarding-steps';
|
||||
import { ThemeSchemeToggle } from '~/components/ThemeSchemeToggle/ThemeSchemeToggle';
|
||||
import { FloatingBackground } from '~/components/layout/Background/FloatingBackground';
|
||||
import { db } from '~/server/db';
|
||||
import { env } from '~/env';
|
||||
import { getTotalUserCountAsync } from '~/server/db/queries/user';
|
||||
import { getConfig } from '~/tools/config/getConfig';
|
||||
import { getServerSideTranslations } from '~/tools/server/getServerSideTranslations';
|
||||
|
||||
const util = require('util');
|
||||
const exec = util.promisify(require('child_process').exec);
|
||||
|
||||
export default function OnboardPage({
|
||||
configSchemaVersions,
|
||||
databaseNotWriteable,
|
||||
error,
|
||||
errorMessage
|
||||
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||
const { fn, colors, colorScheme } = useMantineTheme();
|
||||
const background = colorScheme === 'dark' ? 'dark.6' : 'gray.1';
|
||||
@@ -39,29 +48,35 @@ export default function OnboardPage({
|
||||
</Center>
|
||||
</Center>
|
||||
|
||||
{onboardingSteps ? (
|
||||
<OnboardingSteps isUpdate={isUpgradeFromSchemaOne} />
|
||||
{databaseNotWriteable == true ? (
|
||||
<DatabaseNotWriteable error={error} errorMessage={errorMessage} />
|
||||
) : (
|
||||
<Center h="100%">
|
||||
<Stack align="center" p="lg">
|
||||
<Title order={1} weight={800} size="3rem" opacity={0.8}>
|
||||
Welcome to Homarr!
|
||||
</Title>
|
||||
<Text size="lg" mb={40}>
|
||||
Your favorite dashboard has received a big upgrade.
|
||||
<br />
|
||||
We'll help you update within the next few steps
|
||||
</Text>
|
||||
<>
|
||||
{onboardingSteps ? (
|
||||
<OnboardingSteps isUpdate={isUpgradeFromSchemaOne} />
|
||||
) : (
|
||||
<Center h="100%">
|
||||
<Stack align="center" p="lg">
|
||||
<Title order={1} weight={800} size="3rem" opacity={0.8}>
|
||||
Welcome to Homarr!
|
||||
</Title>
|
||||
<Text size="lg" mb={40}>
|
||||
Your favorite dashboard has received a big upgrade.
|
||||
<br />
|
||||
We'll help you update within the next few steps
|
||||
</Text>
|
||||
|
||||
<Button
|
||||
onClick={showOnboardingSteps}
|
||||
rightIcon={<IconArrowRight size="1rem" />}
|
||||
variant="default"
|
||||
>
|
||||
Start update process
|
||||
</Button>
|
||||
</Stack>
|
||||
</Center>
|
||||
<Button
|
||||
onClick={showOnboardingSteps}
|
||||
rightIcon={<IconArrowRight size="1rem" />}
|
||||
variant="default"
|
||||
>
|
||||
Start update process
|
||||
</Button>
|
||||
</Stack>
|
||||
</Center>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</>
|
||||
@@ -87,10 +102,65 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||
ctx.res
|
||||
);
|
||||
|
||||
if (env.DATABASE_URL.startsWith('file:')) {
|
||||
const rawDatabaseUrl = env.DATABASE_URL.substring('file:'.length);
|
||||
Consola.info(
|
||||
`Instance is using a database on the file system. Checking if file '${rawDatabaseUrl}' is writable...`
|
||||
);
|
||||
try {
|
||||
await fsPromises.access(rawDatabaseUrl, fs.constants.W_OK);
|
||||
} catch (error) {
|
||||
// this usually occurs when the database path is not mounted in Docker
|
||||
Consola.error(`Database '${rawDatabaseUrl}' is not writable.`, error);
|
||||
return {
|
||||
props: {
|
||||
...translations,
|
||||
configSchemaVersions: configSchemaVersions,
|
||||
databaseNotWriteable: true,
|
||||
error: error,
|
||||
},
|
||||
};
|
||||
}
|
||||
Consola.info('Database is writeable');
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
try {
|
||||
const { stdout, stderr } = await exec("mount | grep '/data'");
|
||||
|
||||
if (stderr.split('\n').length > 1 || stdout.split('\n').length <= 1) {
|
||||
Consola.error(`Database at '${rawDatabaseUrl}' has not been mounted: ${stdout.replace('\n', '\\n')} ${stderr.replace('\n', '\\n')}`);
|
||||
return {
|
||||
props: {
|
||||
...translations,
|
||||
configSchemaVersions: configSchemaVersions,
|
||||
databaseNotWriteable: true,
|
||||
error: `Database at '${rawDatabaseUrl}' is not mounted:\n${stdout}`,
|
||||
},
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
const errorMessage = `Database at '${rawDatabaseUrl}' has not been mounted: ${error}`;
|
||||
Consola.error(errorMessage);
|
||||
return {
|
||||
props: {
|
||||
...translations,
|
||||
configSchemaVersions: configSchemaVersions,
|
||||
databaseNotWriteable: true,
|
||||
error: error,
|
||||
errorMessage: errorMessage
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Consola.info(`Database at '${rawDatabaseUrl}' is writeable and mounted`);
|
||||
}
|
||||
|
||||
return {
|
||||
props: {
|
||||
...translations,
|
||||
configSchemaVersions: configSchemaVersions,
|
||||
databaseNotWriteable: false
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ConfigType } from '~/types/config';
|
||||
|
||||
import defaultConfig from '../../../data/configs/default.json';
|
||||
import defaultConfig from '../../../data/default.json';
|
||||
|
||||
export const getFallbackConfig = (name?: string) => ({
|
||||
...defaultConfig,
|
||||
|
||||
Reference in New Issue
Block a user