mirror of
https://github.com/gethomepage/homepage.git
synced 2025-12-31 11:02:12 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6292a0709c | ||
|
|
42af93bef3 | ||
|
|
964991781c | ||
|
|
607a14083e | ||
|
|
133a0a6539 | ||
|
|
0d0f465e16 | ||
|
|
16c1b2da9b | ||
|
|
4761a56b3d | ||
|
|
9d40b67d49 | ||
|
|
97f4bcbdb0 | ||
|
|
ea1375e575 | ||
|
|
733a3140d1 | ||
|
|
b5ac617597 | ||
|
|
9b06212a92 | ||
|
|
6b4182ab96 | ||
|
|
8656b8e2f1 | ||
|
|
dd8e9270f2 | ||
|
|
90dd8e5967 | ||
|
|
6fca9e342d | ||
|
|
66a8b1c21e | ||
|
|
a0dc8c9ccb | ||
|
|
8190260400 | ||
|
|
7ced73b206 | ||
|
|
a2f4dd289b | ||
|
|
0c7cac74ea | ||
|
|
d81fcee31f | ||
|
|
f7889eab27 | ||
|
|
91518d972d | ||
|
|
a090f98fab | ||
|
|
5629440acf | ||
|
|
471800d5bc | ||
|
|
6ab57b7b14 | ||
|
|
f767ff047f |
@@ -56,12 +56,12 @@ COPY --link --chmod=755 docker-entrypoint.sh /usr/local/bin/
|
||||
|
||||
RUN apk add --no-cache su-exec
|
||||
|
||||
ENV HOSTNAME=::
|
||||
ENV HOSTNAME=0.0.0.0
|
||||
ENV PORT=3000
|
||||
EXPOSE $PORT
|
||||
|
||||
HEALTHCHECK --interval=10s --timeout=3s --start-period=20s \
|
||||
CMD wget --no-verbose --tries=1 --spider --no-check-certificate http://localhost:$PORT/api/healthcheck || exit 1
|
||||
CMD wget --no-verbose --tries=1 --spider --no-check-certificate http://127.0.0.1:$PORT/api/healthcheck || exit 1
|
||||
|
||||
ENTRYPOINT ["docker-entrypoint.sh"]
|
||||
CMD ["node", "server.js"]
|
||||
|
||||
@@ -80,6 +80,7 @@ services:
|
||||
image: ghcr.io/gethomepage/homepage:latest
|
||||
container_name: homepage
|
||||
environment:
|
||||
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required, may need port
|
||||
PUID: 1000 # optional, your user id
|
||||
PGID: 1000 # optional, your group id
|
||||
ports:
|
||||
@@ -94,6 +95,7 @@ or docker run:
|
||||
|
||||
```bash
|
||||
docker run --name homepage \
|
||||
-e HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev \
|
||||
-e PUID=1000 \
|
||||
-e PGID=1000 \
|
||||
-p 3000:3000 \
|
||||
|
||||
@@ -16,7 +16,7 @@ services:
|
||||
- /path/to/config:/app/config # Make sure your local config directory exists
|
||||
- /var/run/docker.sock:/var/run/docker.sock # (optional) For docker integrations
|
||||
environment:
|
||||
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required when deploying via public URL
|
||||
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required, may need port
|
||||
```
|
||||
|
||||
### Running as non-root
|
||||
@@ -38,7 +38,7 @@ services:
|
||||
- /path/to/config:/app/config # Make sure your local config directory exists
|
||||
- /var/run/docker.sock:/var/run/docker.sock # (optional) For docker integrations, see alternative methods
|
||||
environment:
|
||||
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required when deploying via public URL
|
||||
HOMEPAGE_ALLOWED_HOSTS: gethomepage.dev # required, may need port
|
||||
PUID: $PUID
|
||||
PGID: $PGID
|
||||
```
|
||||
|
||||
@@ -29,4 +29,8 @@ You have a few options for deploying homepage, depending on your needs. We offer
|
||||
|
||||
### `HOMEPAGE_ALLOWED_HOSTS`
|
||||
|
||||
As of v1.0 there is one required environment variable when deploying via a public URL, <code>HOMEPAGE_ALLOWED_HOSTS</code>. This is a comma separated list of allowed hosts that can access your homepage. See the [docker](docker.md) and [source](source.md) installation pages for examples.
|
||||
As of v1.0 there is one required environment variable when deploying via a public URL, <code>HOMEPAGE_ALLOWED_HOSTS</code>. This is a comma separated (no spaces) list of allowed hosts (sometimes with the port) that can access your homepage. See the [docker](docker.md) and [source](source.md) installation pages for more information.
|
||||
|
||||
`localhost:3000` and `127.0.0.1:3000` are always allowed, but you can add a domain or IP address to this list to allow access from that host such as `HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev,192.168.1.2:1234`, etc.
|
||||
|
||||
This can be disabled by setting `HOMEPAGE_ALLOWED_HOSTS` to `*` but this is not recommended.
|
||||
|
||||
@@ -3,85 +3,6 @@ title: Kubernetes Installation
|
||||
description: Install on Kubernetes
|
||||
---
|
||||
|
||||
## Install with Helm
|
||||
|
||||
There is an [unofficial helm chart](https://github.com/jameswynn/helm-charts/tree/main/charts/homepage) that creates all the necessary manifests, including the service account and RBAC entities necessary for service discovery.
|
||||
|
||||
```sh
|
||||
helm repo add jameswynn https://jameswynn.github.io/helm-charts
|
||||
helm install homepage jameswynn/homepage -f values.yaml
|
||||
```
|
||||
|
||||
The helm chart allows for all the configurations to be inlined directly in your `values.yaml`:
|
||||
|
||||
```yaml
|
||||
config:
|
||||
bookmarks:
|
||||
- Developer:
|
||||
- Github:
|
||||
- abbr: GH
|
||||
href: https://github.com/
|
||||
services:
|
||||
- My First Group:
|
||||
- My First Service:
|
||||
href: http://localhost/
|
||||
description: Homepage is awesome
|
||||
|
||||
- My Second Group:
|
||||
- My Second Service:
|
||||
href: http://localhost/
|
||||
description: Homepage is the best
|
||||
|
||||
- My Third Group:
|
||||
- My Third Service:
|
||||
href: http://localhost/
|
||||
description: Homepage is 😎
|
||||
widgets:
|
||||
# show the kubernetes widget, with the cluster summary and individual nodes
|
||||
- kubernetes:
|
||||
cluster:
|
||||
show: true
|
||||
cpu: true
|
||||
memory: true
|
||||
showLabel: true
|
||||
label: "cluster"
|
||||
nodes:
|
||||
show: true
|
||||
cpu: true
|
||||
memory: true
|
||||
showLabel: true
|
||||
- search:
|
||||
provider: duckduckgo
|
||||
target: _blank
|
||||
kubernetes:
|
||||
mode: cluster
|
||||
settings:
|
||||
|
||||
# The service account is necessary to allow discovery of other services
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: homepage
|
||||
|
||||
# This enables the service account to access the necessary resources
|
||||
enableRbac: true
|
||||
|
||||
ingress:
|
||||
main:
|
||||
enabled: true
|
||||
annotations:
|
||||
# Example annotations to add Homepage to your Homepage!
|
||||
gethomepage.dev/enabled: "true"
|
||||
gethomepage.dev/name: "Homepage"
|
||||
gethomepage.dev/description: "Dynamically Detected Homepage"
|
||||
gethomepage.dev/group: "Dynamic"
|
||||
gethomepage.dev/icon: "homepage.png"
|
||||
hosts:
|
||||
- host: homepage.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
```
|
||||
|
||||
## Install with Kubernetes Manifests
|
||||
|
||||
If you don't want to use the unofficial Helm chart, you can also create your own Kubernetes manifest(s) and apply them with `kubectl apply -f filename.yaml`.
|
||||
@@ -302,6 +223,9 @@ spec:
|
||||
- name: homepage
|
||||
image: "ghcr.io/gethomepage/homepage:latest"
|
||||
imagePullPolicy: Always
|
||||
env:
|
||||
- name: HOMEPAGE_ALLOWED_HOSTS
|
||||
value: gethomepage.dev # required, may need port
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 3000
|
||||
|
||||
@@ -21,7 +21,7 @@ If this is your first time starting, copy the `src/skeleton` directory to `confi
|
||||
Finally, run the server:
|
||||
|
||||
```bash
|
||||
HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev pnpm start
|
||||
HOMEPAGE_ALLOWED_HOSTS=gethomepage.dev:1234 pnpm start
|
||||
```
|
||||
|
||||
When updating homepage versions you will need to re-build the static files i.e. repeat the process above.
|
||||
|
||||
@@ -12,6 +12,7 @@ hide:
|
||||
- Check config/logs/homepage.log, on docker simply e.g. `docker logs homepage`. This may provide some insight into the reason for an error.
|
||||
- Check the browser error console, this can also sometimes provide useful information.
|
||||
- Consider setting the `ENV` variable `LOG_LEVEL` to `debug`.
|
||||
- If certain widgets are failing when connecting to public APIs, consider [disabling IPv6](#disabling-ipv6).
|
||||
|
||||
## Service Widget Errors
|
||||
|
||||
@@ -66,3 +67,24 @@ All service widgets work essentially the same, that is, homepage makes a proxied
|
||||
## Missing custom icons
|
||||
|
||||
If, after correctly adding and mapping your custom icons via the [Icons](../configs/services.md#icons) instructions, you are still unable to see your icons please try recreating your container.
|
||||
|
||||
## Disabling IPv6
|
||||
|
||||
If you are having issues with certain widgets that are unable to reach public APIs (e.g. weather), you may need to disable IPv6 on your host machine. This can be done by adding the following to your `docker-compose.yml` file (or for docker run, the equivalent flag):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
homepage:
|
||||
...
|
||||
sysctls:
|
||||
- net.ipv6.conf.all.disable_ipv6=1
|
||||
```
|
||||
|
||||
or disable IPv6 for the docker network:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
some_network:
|
||||
driver: bridge
|
||||
enable_ipv6: false
|
||||
```
|
||||
|
||||
@@ -20,4 +20,5 @@ widget:
|
||||
url: http://komga.host.or.ip:port
|
||||
username: username
|
||||
password: password
|
||||
key: komgaapikey # optional
|
||||
```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "homepage",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Item({ bookmark, iconOnly = false }) {
|
||||
className={classNames(
|
||||
settings.cardBlur !== undefined && `backdrop-blur${settings.cardBlur.length ? "-" : ""}${settings.cardBlur}`,
|
||||
"text-left cursor-pointer transition-all rounded-md font-medium text-theme-700 dark:text-theme-200 dark:hover:text-theme-300 shadow-md shadow-theme-900/10 dark:shadow-theme-900/20 bg-theme-100/20 hover:bg-theme-300/20 dark:bg-white/5 dark:hover:bg-white/10",
|
||||
iconOnly ? "h-[60px] w-[60px] grid" : "block w-full h-8 mb-3",
|
||||
iconOnly ? "h-[60px] w-[60px] grid" : "block w-full h-full mb-3",
|
||||
)}
|
||||
>
|
||||
{iconOnly ? (
|
||||
|
||||
@@ -4,14 +4,15 @@ export function middleware(req) {
|
||||
// Check the Host header, if HOMEPAGE_ALLOWED_HOSTS is set
|
||||
const host = req.headers.get("host");
|
||||
const port = process.env.PORT || 3000;
|
||||
let allowedHosts = [`localhost:${port}`];
|
||||
let allowedHosts = [`localhost:${port}`, `127.0.0.1:${port}`];
|
||||
const allowAll = process.env.HOMEPAGE_ALLOWED_HOSTS === "*";
|
||||
if (process.env.HOMEPAGE_ALLOWED_HOSTS) {
|
||||
allowedHosts = allowedHosts.concat(process.env.HOMEPAGE_ALLOWED_HOSTS.split(","));
|
||||
}
|
||||
if (!host || !allowedHosts.includes(host)) {
|
||||
if (!allowAll && (!host || !allowedHosts.includes(host))) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Host validation failed for: ${host}. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host.`,
|
||||
`Host validation failed for: ${host}. Hint: Set the HOMEPAGE_ALLOWED_HOSTS environment variable to allow requests from this host / port.`,
|
||||
);
|
||||
return NextResponse.json({ error: "Host validation failed. See logs for more details." }, { status: 400 });
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
@config '../../tailwind.config.js';
|
||||
|
||||
@theme {
|
||||
--breakpoint-3xl: 112rem;
|
||||
}
|
||||
|
||||
/*
|
||||
The default border color has changed to `currentColor` in Tailwind CSS v4,
|
||||
so we've added these compatibility styles to make sure everything still
|
||||
|
||||
@@ -35,8 +35,8 @@ function generateStreamTitle(session, enableUser, showEpisodeNumber) {
|
||||
let streamTitle = "";
|
||||
|
||||
if (Type === "Episode" && showEpisodeNumber) {
|
||||
const seasonStr = `S${ParentIndexNumber.toString().padStart(2, "0")}`;
|
||||
const episodeStr = `E${IndexNumber.toString().padStart(2, "0")}`;
|
||||
const seasonStr = ParentIndexNumber ? `S${ParentIndexNumber.toString().padStart(2, "0")}` : "";
|
||||
const episodeStr = IndexNumber ? `E${IndexNumber.toString().padStart(2, "0")}` : "";
|
||||
streamTitle = `${SeriesName}: ${seasonStr} · ${episodeStr} - ${Name}`;
|
||||
} else {
|
||||
streamTitle = `${Name}${SeriesName ? ` - ${SeriesName}` : ""}`;
|
||||
|
||||
@@ -14,7 +14,11 @@ async function login(widget, service) {
|
||||
const endpoint = "Account/login";
|
||||
const api = widgets?.[widget.type]?.api;
|
||||
const loginUrl = new URL(formatApiCall(api, { endpoint, ...widget }));
|
||||
const loginBody = {};
|
||||
const loginBody = {
|
||||
username: "",
|
||||
password: "",
|
||||
apiKey: "",
|
||||
};
|
||||
if (widget.username && widget.password) {
|
||||
loginBody.username = widget.username;
|
||||
loginBody.password = widget.password;
|
||||
|
||||
@@ -111,7 +111,8 @@ export default async function plexProxyHandler(req, res) {
|
||||
: `/library/sections/${library._attributes.key}/albums`; // music
|
||||
[status, apiData] = await fetchFromPlexAPI(libraryURL, widget);
|
||||
if (apiData && apiData.MediaContainer) {
|
||||
const size = parseInt(apiData.MediaContainer._attributes.size, 10);
|
||||
const sizeProp = apiData.MediaContainer._attributes["totalSize"] ? "totalSize" : "size";
|
||||
const size = parseInt(apiData.MediaContainer._attributes[sizeProp], 10);
|
||||
if (library._attributes.type === "movie") {
|
||||
movies += size;
|
||||
} else if (library._attributes.type === "show") {
|
||||
|
||||
@@ -36,14 +36,14 @@ export default function Component({ service }) {
|
||||
<Block
|
||||
label="speedtest.download"
|
||||
value={t("common.bitrate", {
|
||||
value: speedtestData.data.download * 1000 * 1000,
|
||||
value: widget.version === 2 ? speedtestData.data.download * 8 : speedtestData.data.download * 1000 * 1000,
|
||||
decimals: bitratePrecision,
|
||||
})}
|
||||
/>
|
||||
<Block
|
||||
label="speedtest.upload"
|
||||
value={t("common.bitrate", {
|
||||
value: speedtestData.data.upload * 1000 * 1000,
|
||||
value: widget.version === 2 ? speedtestData.data.upload * 8 : speedtestData.data.upload * 1000 * 1000,
|
||||
decimals: bitratePrecision,
|
||||
})}
|
||||
/>
|
||||
|
||||
@@ -30,10 +30,6 @@ module.exports = {
|
||||
900: "rgb(var(--color-900) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
screens: {
|
||||
"3xl": "1800px",
|
||||
// => @media (min-width: 1800px) { ... }
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [tailwindForms, tailwindScrollbars],
|
||||
|
||||
Reference in New Issue
Block a user