diff --git a/docs/alternate-views.md b/docs/alternate-views.md
index f9fa6996..5bde691c 100644
--- a/docs/alternate-views.md
+++ b/docs/alternate-views.md
@@ -1,10 +1,16 @@
# Alternate Views & Opening Methods
## Views
-As well as the default start view, Dashy has several other start pages, for different tasks. You can switch views with the view-switcher button in the top-right, or set a default starting view using the `appConfig.startingView` attribute (can be `default`, `minimal` or `workspace`).
+
+Dashy has three different views:
+- Default View - This is the main homepage with sections in a grid layout
+- Workspace View - Items displayed on the side, and are launched within Dashy
+- Minimal View - A clean + simple tabbed view
+
+You can switch between views using the dropdown in the top-right corner. Set your chosen Starting View with `appConfig.startingView`. Click the page title at any time to go back to your selected starting view.
### Default
-This is the main page that you will land on when you first launch the application. Here all of your sections and items will be visible, you can modify settings and search + launch your applications.
+This is the main page that you will land on when you first launch the application. Here all of your sections (with items + widgets) are visible in a grid layout.
+
-
-
-
-
+
+
+
+
@@ -15,28 +15,46 @@
+
+
+
-
+
+
+
+
-
+
-
+
-
+
-
+
+
+
+
+
+
+
-
+
-
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/assets/repo-visualization.svg b/docs/assets/repo-visualization.svg
index a6b05a90..236615b7 100644
--- a/docs/assets/repo-visualization.svg
+++ b/docs/assets/repo-visualization.svg
@@ -1 +1 @@
-views views utils utils styles styles components components assets assets Workspace Workspace Settings Settings PageStrcture PageStrcture MinimalView MinimalView LinkItems LinkItems InteractiveEditor InteractiveEditor FormElements FormElements Configuration Configuration locales locales interface-icons interface-icons Home.vue Home.vue Home.vue Login.vue Login.vue Login.vue emojis.json emojis.json emojis.json ConfigSch... ConfigSch... ConfigSch... color-the... color-the... color-the... CustomThe... CustomThe... CustomThe... Item.vue Item.vue Item.vue Section.vue Section.vue Section.vue EditItem... EditItem... EditItem... JsonEdito... JsonEdito... JsonEdito... ConfigCo... ConfigCo... ConfigCo... hi.json hi.json hi.json fr.json fr.json fr.json ru.json ru.json ru.json en.json en.json en.json ar.json ar.json ar.json .js .json .scss .svg .vue each dot sized by file size
\ No newline at end of file
+views views utils utils styles styles mixins mixins components components assets assets Workspace Workspace Widgets Widgets Settings Settings PageStrcture PageStrcture MinimalView MinimalView LinkItems LinkItems InteractiveEditor InteractiveEditor FormElements FormElements Configuration Configuration locales locales interface-icons interface-icons emojis.json emojis.json emojis.json ConfigSc... ConfigSc... ConfigSc... color-th... color-th... color-th... WidgetBa... WidgetBa... WidgetBa... Item.vue Item.vue Item.vue hi.json hi.json hi.json fr.json fr.json fr.json .js .json .scss .svg .vue each dot sized by file size
\ No newline at end of file
diff --git a/docs/authentication.md b/docs/authentication.md
index 23ac36a4..7f8b6b6c 100644
--- a/docs/authentication.md
+++ b/docs/authentication.md
@@ -143,9 +143,25 @@ appConfig:
realm: 'alicia-homelab'
clientId: 'dashy'
```
+
+### 4. Add groups and roles (Optional)
+Keycloak allows you to assign users roles and groups. You can use these values to configure who can access various sections in Dashy.
+Keycloak server administration and configuration is a deep topic; please refer to the [server admin guide](https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-and-access-using-roles-and-groups) to see details about creating and assigning roles and groups.
+Once you have groups or roles assigned to users you can configure access under each sections `displayData.showForKeycloakUser` and `displayData.hideForKeycloakUser`.
+Both show and hide configurations accept a list of `groups` and `roles` that limit access. If a users data matches one or more items in these lists they will be allowed or excluded as defined.
+```yaml
+sections:
+ - name: DeveloperResources
+ displayData:
+ showForKeycloakUsers:
+ roles: ['canViewDevResources']
+ hideForKeycloakUsers:
+ groups: ['ProductTeam']
+```
+
Your app is now secured :) When you load Dashy, it will redirect to your Keycloak login page, and any user without valid credentials will be prevented from accessing your dashboard.
-From within the Keycloak console, you can then configure things like user permissions, time outs, password policies, access, etc. You can also backup your full Keycloak config, and it is recommended to do this, along with your Dashy config. You can spin up both Dashy and Keycloak simultaneously and restore both applications configs using a `docker-compose.yml` file, and this is recommended.
+From within the Keycloak console, you can then configure things like time-outs, password policies, etc. You can also backup your full Keycloak config, and it is recommended to do this, along with your Dashy config. You can spin up both Dashy and Keycloak simultaneously and restore both applications configs using a `docker-compose.yml` file, and this is recommended.
---
diff --git a/docs/configuring.md b/docs/configuring.md
index e04b6c15..a5db7780 100644
--- a/docs/configuring.md
+++ b/docs/configuring.md
@@ -1,298 +1,323 @@
-# Configuring
-
-All app configuration is specified in [`/public/conf.yml`](https://github.com/Lissy93/dashy/blob/master/public/conf.yml) which is in [YAML Format](https://yaml.org/) format. Changes can also be made [directly through the UI](#editing-config-through-the-ui) and previewed live, from here you can also export, backup, reset, validate and download your configuration file.
-
-The following file provides a reference of all supported configuration options.
-
----
-
-#### Contents
-
-- [**`pageInfo`**](#pageinfo) - Header text, footer, title, navigation, etc
- - [`navLinks`](#pageinfonavlinks-optional) - Navigation bar items and links
-- [**`appConfig`**](#appconfig-optional) - Main application settings
- - [`webSearch`](#appconfigwebsearch-optional) - Configure web search engine options
- - [`hideComponents`](#appconfighidecomponents-optional) - Show/ hide page components
- - [`auth`](#appconfigauth-optional) - Built-in authentication setup
- - [`users`](#appconfigauthusers-optional) - Setup for simple auth
- - [`keycloak`](#appconfigauthkeycloak-optional) - Auth using Keycloak
-- [**`sections`**](#section) - List of sections
- - [`displayData`](#sectiondisplaydata-optional) - Section display settings
- - [`icon`](#sectionicon-and-sectionitemicon) - Icon for a section
- - [`items`](#sectionitem) - List of items
- - [`icon`](#sectionicon-and-sectionitemicon) - Icon for an item
-- [**Notes**](#notes)
- - [Editing Config through the UI](#editing-config-through-the-ui)
- - [About YAML](#about-yaml)
- - [Config Saving Methods](#config-saving-methods)
- - [Preventing Changes](#preventing-changes-being-written-to-disk)
- - [Example](#example)
-
----
-
-Tips:
-- You may find it helpful to look at some sample config files to get you started, a collection of which can be found [here](https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10)
-- You can check that your config file fits the schema, by running `yarn validate-config`
-- After modifying your config, the app needs to be recompiled, by running `yarn build` - this happens automatically whilst the app is running if you're using Docker
-- It is recommended to make and keep a backup of your config file. You can download your current config through the UI either from the Config menu, or using the `/download` endpoint. Alternatively, you can use the [Cloud Backup](/docs/backup-restore) feature.
-- The config can also be modified directly through the UI, validated and written to the conf.yml file.
-- All fields are optional, unless otherwise stated.
-
----
-
-### Top-Level Fields
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`pageInfo`** | `object` | Required | Basic meta data like title, description, nav bar links, footer text. See [`pageInfo`](#pageinfo)
-**`appConfig`** | `object` | _Optional_ | Settings related to how the app functions, including API keys and global styles. See [`appConfig`](#appconfig-optional)
-**`sections`** | `array` | Required | An array of sections, each containing an array of items, which will be displayed as links. See [`section`](#section)
-
-**[âŦī¸ Back to Top](#)**
-
-### `PageInfo`
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`title`** | `string` | Required | Your dashboard title, displayed in the header and browser tab
-**`description`** | `string` | _Optional_ | Description of your dashboard, also displayed as a subtitle
-**`navLinks`** | `array` | _Optional_ | Optional list of a maximum of 6 links, which will be displayed in the navigation bar. See [`navLinks`](#pageinfonavlinks-optional)
-**`footerText`** | `string` | _Optional_ | Text to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS
-**`logo`** | `string` | _Optional_ | The path to an image to display in the header (to the right of the title). This can be either local, where `/` is the root of `./public`, or any remote image, such as `https://i.ibb.co/yhbt6CY/dashy.png`. It's recommended to scale your image down, so that it doesn't impact load times
-
-**[âŦī¸ Back to Top](#)**
-
-### `pageInfo.navLinks` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`title`** | `string` | Required | The text to display on the link button
-**`path`** | `string` | Required | The URL to navigate to when clicked. Can be relative (e.g. `/about`) or absolute (e.g. `https://example.com` or `http://192.168.1.1`)
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`language`** | `string` | _Optional_ | The 2 (or 4-digit) [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for your language, e.g. `en` or `en-GB`. This must be a language that the app has already been [translated](https://github.com/Lissy93/dashy/tree/master/src/assets/locales) into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.
-**`startingView`** | `enum` | _Optional_ | Which page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either `default`, `minimal` or `workspace`. Defaults to `default`
-**`defaultOpeningMethod`** | `enum` | _Optional_ | The default opening method for items, if no `target` is specified for a given item. Can be either `newtab`, `sametab`, `top`, `parent`, `modal` or `workspace`. Defaults to `newtab`
-**`statusCheck`** | `boolean` | _Optional_ | When set to `true`, Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting `statusCheck` under each item. Defaults to `false`
-**`statusCheckInterval`** | `boolean` | _Optional_ | The number of seconds between checks. If set to `0` then service will only be checked on initial page load, which is usually the desired functionality. If value is less than `10` you may experience a hit in performance. Defaults to `0`
-**`webSearch`** | `object` | _Optional_ | Configuration options for the web search feature, set your default search engine, opening method or disable web search. See [`webSearch`](#appconfigwebsearch-optional)
-**`backgroundImg`** | `string` | _Optional_ | Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load
-**`enableFontAwesome`** | `boolean` | _Optional_ | Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons
-**`fontAwesomeKey`** | `string` | _Optional_ | If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`)
-**`faviconApi`** | `enum` | _Optional_ | Only applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to `local` to do this locally, without using an API. Services running locally will use this option always. Available options are: `local`, `faviconkit`, `google`, `clearbit`, `webmasterapi` and `allesedv`. Defaults to `faviconkit`. See [Icons](/docs/icons#favicons) for more info
-**`auth`** | `object` | _Optional_ | All settings relating to user authentication. See [`auth`](#appconfigauth-optional)
-**`layout`** | `enum` | _Optional_ | Layout for homepage, either `horizontal`, `vertical` or `auto`. Defaults to `auto`. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.
-**`iconSize`** | `enum` | _Optional_ | The size of link items / icons. Can be either `small`, `medium,` or `large`. Defaults to `medium`. This can also be set directly from the UI.
-**`colCount`** | `number` | _Optional_ | The number of columns of sections displayed on the homepage, using the default view. Should be in integer between `1` and `8`. Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.
-**`theme`** | `string` | _Optional_ | The default theme for first load (you can change this later from the UI)
-**`cssThemes`** | `string[]` | _Optional_ | An array of custom theme names which can be used in the theme switcher dropdown
-**`customColors`** | `object`| _Optional_ | Enables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See [Theming](/docs/theming#modifying-theme-colors) for more info
-**`externalStyleSheet`** | `string` or `string[]` | _Optional_ | Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
-**`customCss`** | `string` | _Optional_ | Raw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.
-**`hideComponents`** | `object` | _Optional_ | A list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See [`appConfig.hideComponents`](#appconfighideComponents-optional)
-**`routingMode`** | `string` | _Optional_ | Can be either `hash` or `history`. Determines the URL format for sub-pages, hash mode will look like `/#/home` whereas with history mode available you have nice clean URLs, like `/home`. For more info, see the [Vue docs](https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations). If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use `hash` mode.Defaults to `history`.
-**`enableMultiTasking`** | `boolean` | _Optional_ | If set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.
-**`workspaceLandingUrl`** | `string` | _Optional_ | The URL or an app, service or website to launch when the workspace view is opened, before another service has been launched
-**`allowConfigEdit`** | `boolean` | _Optional_ | Should prevent / allow the user to write configuration changes to the conf.yml from the UI. When set to `false`, the user can only apply changes locally using the config editor within the app, whereas if set to `true` then changes can be written to disk directly through the UI. Defaults to `true`. Note that if authentication is enabled, the user must be of type `admin` in order to apply changes globally.
-**`enableErrorReporting`** | `boolean` | _Optional_ | Enable reporting of unexpected errors and crashes. This is off by default, and **no data will ever be captured unless you explicitly enable it**. Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses [Sentry](https://github.com/getsentry/sentry) for error reporting. Defaults to `false`.
-**`sentryDsn`** | `boolean` | _Optional_ | If you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the [Sentry DSN Docs](https://docs.sentry.io/product/sentry-basics/dsn-explainer/). Note that this will only ever be used if `enableErrorReporting` is explicitly enabled.
-**`disableSmartSort`** | `boolean` | _Optional_ | For the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to `false`.
-**`disableUpdateChecks`** | `boolean` | _Optional_ | If set to true, Dashy will not check for updates. Defaults to `false`.
-**`enableServiceWorker`** | `boolean` | _Optional_ | Service workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to `true` to disable all service workers.
-**`disableContextMenu`** | `boolean` | _Optional_ | If set to `true`, the custom right-click context menu will be disabled. Defaults to `false`.
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig.auth` _(optional)_
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`users`** | `array` | _Optional_ | An array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See [`appConfig.auth.users`](#appconfigauthusers-optional). **Note** this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an [alternate authentication method](/docs/authentication#alternative-authentication-methods).
-**`enableKeycloak`** | `boolean` | _Optional_ | If set to `true`, then authentication using Keycloak will be anabled. Note that you need to have an instance running, and have also configured `auth.keycloak`. Defaults to `false`
-**`keycloak`** | `object` | _Optional_ | Config options to point Dashy to your Keycloak server. Requires `enableKeycloak: true`. See [`auth.keycloak`](#appconfigauthkeycloak-optional) for more info
-**`enableGuestAccess`** | `boolean` | _Optional_ | When set to `true`, an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires `auth.users` to be configured. Defaults to `false`.
-
-For more info, see the **[Authentication Docs](/docs/authentication)**
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig.auth.users` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`user`** | `string` | Required | Username to log in with
-**`hash`** | `string` | Required | A SHA-256 hashed password
-**`type`** | `string` | _Optional_ | The user type, either admin or normal
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig.auth.keycloak` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`serverUrl`** | `string` | Required | The URL (or URL/ IP + Port) where your keycloak server is running
-**`realm`** | `string` | Required | The name of the realm (must already be created) that you want to use
-**`clientId`** | `string` | Required | The Client ID of the client you created for use with Dashy
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig.webSearch` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`disableWebSearch`** | `string` | _Optional_ | Web search is enabled by default, but can be disabled by setting this property to `true`
-**`searchEngine`** | `string` | _Optional_ | Set the key name for your search engine. Can also use a custom engine by setting this property to `custom`. Currently supported: `duckduckgo`, `google`, `whoogle`, `qwant`, `startpage`, `searx-bar` and `searx-info`. Defaults to `duckduckgo`
-**`customSearchEngine`** | `string` | _Optional_ | You can also use a custom search engine, or your own self-hosted instance. This requires `searchEngine: custom` to be set. Then add the URL of your service, with GET query string included here
-**`openingMethod`** | `string` | _Optional_ | Set your preferred opening method for search results: `newtab`, `sametab`, `workspace`. Defaults to `newtab`
-**`searchBangs`** | `object` | _Optional_ | A key-value-pair set of custom search _bangs_ for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with `/`, `!` or `:`), and value is the destination, either as a search engine key (e.g. `reddit`) or a URL with search parameters (e.g. `https://en.wikipedia.org/w/?search=`)
-
-
-**[âŦī¸ Back to Top](#)**
-
-### `appConfig.hideComponents` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`hideHeading`** | `boolean` | _Optional_ | If set to `true`, the page title & sub-title will not be visible. Defaults to `false`
-**`hideNav`** | `boolean` | _Optional_ | If set to `true`, the navigation menu will not be visible. Defaults to `false`
-**`hideSearch`** | `boolean` | _Optional_ | If set to `true`, the search bar will not be visible. Defaults to `false`
-**`hideSettings`** | `boolean` | _Optional_ | If set to `true`, the settings menu will not be visible. Defaults to `false`
-**`hideFooter`** | `boolean` | _Optional_ | If set to `true`, the footer will not be visible. Defaults to `false`
-**`hideSplashScreen`** | `boolean` | _Optional_ | If set to `true`, splash screen will not be visible while the app loads. Defaults to `true` (except on first load, when the loading screen is always shown)
-
-**[âŦī¸ Back to Top](#)**
-
-### `section`
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`name`** | `string` | Required | The title for the section
-**`icon`** | `string` | _Optional_ | An single icon to be displayed next to the title. See [`section.icon`](#sectionicon-and-sectionitemicon)
-**`items`** | `array` | Required | An array of items to be displayed within the section. See [`item`](#sectionitem)
-**`displayData`** | `object` | _Optional_ | Meta-data to optionally overide display settings for a given section. See [`displayData`](#sectiondisplaydata-optional)
-
-**[âŦī¸ Back to Top](#)**
-
-### `section.item`
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`title`** | `string` | Required | The text to display/ title of a given item. Max length `18`
-**`description`** | `string` | _Optional_ | Additional info about an item, which is shown in the tooltip on hover, or visible on large tiles
-**`url`** | `string` | Required | The URL / location of web address for when the item is clicked
-**`icon`** | `string` | _Optional_ | The icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See [`item.icon`](#sectionicon-and-sectionitemicon)
-**`target`** | `string` | _Optional_ | The opening method for when the item is clicked, either `newtab`, `sametab`, `top`, `parent`, `modal` or `workspace`. Where `newtab` will open the link in a new tab, `sametab` will open it in the current tab, and `modal` will open a pop-up modal and `workspace` will open in the Workspace view. Defaults to `newtab`
-**`hotkey`** | `number` | _Optional_ | Give frequently opened applications a numeric hotkey, between `0 - 9`. You can then just press that key to launch that application.
-**`tags`** | `string[]` | _Optional_ | A list of tags, which can be used for improved search
-**`statusCheck`** | `boolean` | _Optional_ | When set to `true`, Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override `appConfig.statusCheck` so you can turn off or on checks for a given service. Defaults to `appConfig.statusCheck`, falls back to `false`
-**`statusCheckUrl`** | `string` | _Optional_ | If you've enabled `statusCheck`, and want to use a different URL to what is defined under the item, then specify it here
-**`statusCheckHeaders`** | `object` | _Optional_ | If you're endpoint requires any specific headers for the status checking, then define them here
-**`statusCheckAllowInsecure`** | `boolean` | _Optional_ | By default, any request to insecure content will be blocked. Setting this option to `true` will disable the `rejectUnauthorized` option, enabling you to ping non-HTTPS services for the current item. Defaults to `false`
-**`color`** | `string` | _Optional_ | An optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well
-**`backgroundColor`** | `string` | _Optional_ | An optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background
-**`provider`** | `string` | _Optional_ | The name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name
-
-**[âŦī¸ Back to Top](#)**
-
-### `section.displayData` _(optional)_
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`sortBy`** | `string` | _Optional_ | The sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: `most-used` (most opened apps first), `last-used` (the most recently used apps), `alphabetical`, `reverse-alphabetical`, `random` and `default`
-**`collapsed`** | `boolean` | _Optional_ | If true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to `false`
-**`rows`** | `number` | _Optional_ | Height of the section, specified as the number of rows it should span vertically, e.g. `2`. Defaults to `1`. Max is `5`.
-**`cols`** | `number` | _Optional_ | Width of the section, specified as the number of columns the section should span horizontally, e.g. `2`. Defaults to `1`. Max is `5`.
-**`itemSize`** | `string` | _Optional_ | Specify the size for items within this group, either `small`, `medium` or `large`. Note that this will overide any settings specified through the UI
-**`color`** | `string` | _Optional_ | A custom accent color for the section, as a hex code or HTML color (e.g. `#fff`)
-**`customStyles`** | `string` | _Optional_ | Custom CSS properties that should be applied to that section, e.g. `border: 2px dashed #ff0000;`
-**`sectionLayout`** | `string` | _Optional_ | Specify which CSS layout will be used to responsivley place items. Can be either `auto` (which uses flex layout), or `grid`. If `grid` is selected, then `itemCountX` and `itemCountY` may also be set. Defaults to `auto`
-**`itemCountX`** | `number` | _Optional_ | The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
-**`itemCountY`** | `number` | _Optional_ | The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If `itemCountX` is set, then `itemCountY` can be calculated automatically. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
-**`hideForUsers`** | `string[]` | _Optional_ | Current section will be visible to all users, except for those specified in this list
-**`showForUsers`** | `string[]` | _Optional_ | Current section will be hidden from all users, except for those specified in this list
-**`hideForGuests`** | `boolean` | _Optional_ | Current section will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false`
-
-**[âŦī¸ Back to Top](#)**
-
-### `section.icon` and `section.item.icon`
-
-**Field** | **Type** | **Required**| **Description**
---- | --- | --- | ---
-**`icon`** | `string` | _Optional_ | The icon for a given item or section. See [Icon Docs](/docs/icons) for all available supported icon types. To auto-fetch icon from a services URL, aet to `favicon`. To use font-awesome, specify the category, followed by the icon name, e.g. `fas fa-rocket`, `fab fa-monero` or `fal fa-duck`. Similarly, for branded icons, you can use [simple-icons](https://simpleicons.org/) by setting icon to `si-[icon-name]` or [material-design-icons](https://dev.materialdesignicons.com/icons) by setting icon to `mdi-[icon-name]`. If set to `generative`, then a unique icon is generated from the apps URL or IP. You can also use hosted any by specifying it's URL, e.g. `https://i.ibb.co/710B3Yc/space-invader-x256.png`. To use a local image, first store it in `./public/item-icons/` (or `-v /app/public/item-icons/` in Docker) , and reference it by name and extension - e.g. set `image.png` to use `./public/item-icon/image.png`, you can also use sub-folders if you have a lot of icons, to keep them organised.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Notes
-
-### Editing Config through the UI
-
-Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / [#3](https://github.com/Lissy93/dashy/pull/3)), or the interactive editor (introduced in V 1.8.9 / [#298](https://github.com/Lissy93/dashy/pull/298)).
-
-
-
- Interactive Editor
-
-
-
-
- Raw Editor
-
-
-
-
-### About YAML
-If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This [quick guide](https://linuxhandbook.com/yaml-basics/) should get you up to speed in a few minutes, for more advanced topics take a look at this [Wikipedia article](https://en.wikipedia.org/wiki/YAML).
-
-### Config Saving Methods
-When updating the config through the JSON editor in the UI, you have two save options: **Local** or **Write to Disk**.
-- Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file.
-- On the other-hand, if you choose to write changes to disk, then your main `conf.yml` file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.
-
-### Preventing Changes being Written to Disk
-To disallow any changes from being written to disk via the UI config editor, set `appConfig.allowConfigEdit: false`. If you are using users, and have setup `auth` within Dashy, then only users with `type: admin` will be able to write config changes to disk.
-
-### Example
-
-```yaml
----
-pageInfo:
- title: Home Lab
-sections: # An array of sections
-- name: Section 1 - Getting Started
- items: # An array of items
- - title: GitHub
- description: Source code and documentation on GitHub
- icon: fab fa-github
- url: https://github.com/Lissy93/dashy
- - title: Issues
- description: View currently open issues, or raise a new one
- icon: fas fa-bug
- url: https://github.com/Lissy93/dashy/issues
- - title: Demo
- description: A live demo
- icon: far fa-rocket
- url: https://dashy-demo-1.netlify.app
-- name: Section 2 - Local Services
- items:
- - title: Firewall
- icon: favicon
- url: http://192.168.1.1/
- - title: Game Server
- icon: https://i.ibb.co/710B3Yc/space-invader-x256.png
- url: http://192.168.130.1/
-```
-
-For more example config files, see: [this gist](https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10)
-
-If you need any help, feel free to [Raise an Issue](https://github.com/Lissy93/dashy/issues/new?assignees=Lissy93&labels=%F0%9F%A4%B7%E2%80%8D%E2%99%82%EF%B8%8F+Question&template=question&title=%5BQUESTION%5D) or [Start a Discussion](https://github.com/Lissy93/dashy/discussions)
-
-Happy Configuring đ¤đ§
-
-**[âŦī¸ Back to Top](#)**
-
+# Configuring
+
+All app configuration is specified in [`/public/conf.yml`](https://github.com/Lissy93/dashy/blob/master/public/conf.yml) which is in [YAML Format](https://yaml.org/) format. Changes can also be made [directly through the UI](#editing-config-through-the-ui) and previewed live, from here you can also export, backup, reset, validate and download your configuration file.
+
+The following file provides a reference of all supported configuration options.
+
+---
+
+#### Contents
+
+- [**`pageInfo`**](#pageinfo) - Header text, footer, title, navigation, etc
+ - [`navLinks`](#pageinfonavlinks-optional) - Navigation bar items and links
+- [**`appConfig`**](#appconfig-optional) - Main application settings
+ - [`webSearch`](#appconfigwebsearch-optional) - Configure web search engine options
+ - [`hideComponents`](#appconfighidecomponents-optional) - Show/ hide page components
+ - [`auth`](#appconfigauth-optional) - Built-in authentication setup
+ - [`users`](#appconfigauthusers-optional) - Setup for simple auth
+ - [`keycloak`](#appconfigauthkeycloak-optional) - Auth using Keycloak
+- [**`sections`**](#section) - List of sections
+ - [`displayData`](#sectiondisplaydata-optional) - Section display settings
+ - [`icon`](#sectionicon-and-sectionitemicon) - Icon for a section
+ - [`items`](#sectionitem) - List of items
+ - [`icon`](#sectionicon-and-sectionitemicon) - Icon for an item
+- [**Notes**](#notes)
+ - [Editing Config through the UI](#editing-config-through-the-ui)
+ - [About YAML](#about-yaml)
+ - [Config Saving Methods](#config-saving-methods)
+ - [Preventing Changes](#preventing-changes-being-written-to-disk)
+ - [Example](#example)
+
+---
+
+Tips:
+- You may find it helpful to look at some sample config files to get you started, a collection of which can be found [here](https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10)
+- You can check that your config file fits the schema, by running `yarn validate-config`
+- After modifying your config, the app needs to be recompiled, by running `yarn build` - this happens automatically whilst the app is running if you're using Docker
+- It is recommended to make and keep a backup of your config file. You can download your current config through the UI either from the Config menu, or using the `/download` endpoint. Alternatively, you can use the [Cloud Backup](/docs/backup-restore) feature.
+- The config can also be modified directly through the UI, validated and written to the conf.yml file.
+- All fields are optional, unless otherwise stated.
+
+---
+
+### Top-Level Fields
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`pageInfo`** | `object` | Required | Basic meta data like title, description, nav bar links, footer text. See [`pageInfo`](#pageinfo)
+**`appConfig`** | `object` | _Optional_ | Settings related to how the app functions, including API keys and global styles. See [`appConfig`](#appconfig-optional)
+**`sections`** | `array` | Required | An array of sections, each containing an array of items, which will be displayed as links. See [`section`](#section)
+
+**[âŦī¸ Back to Top](#)**
+
+### `PageInfo`
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`title`** | `string` | Required | Your dashboard title, displayed in the header and browser tab
+**`description`** | `string` | _Optional_ | Description of your dashboard, also displayed as a subtitle
+**`navLinks`** | `array` | _Optional_ | Optional list of a maximum of 6 links, which will be displayed in the navigation bar. See [`navLinks`](#pageinfonavlinks-optional)
+**`footerText`** | `string` | _Optional_ | Text to display in the footer (note that this will override the default footer content). This can also include HTML and inline CSS
+**`logo`** | `string` | _Optional_ | The path to an image to display in the header (to the right of the title). This can be either local, where `/` is the root of `./public`, or any remote image, such as `https://i.ibb.co/yhbt6CY/dashy.png`. It's recommended to scale your image down, so that it doesn't impact load times
+
+**[âŦī¸ Back to Top](#)**
+
+### `pageInfo.navLinks` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`title`** | `string` | Required | The text to display on the link button
+**`path`** | `string` | Required | The URL to navigate to when clicked. Can be relative (e.g. `/about`) or absolute (e.g. `https://example.com` or `http://192.168.1.1`)
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`language`** | `string` | _Optional_ | The 2 (or 4-digit) [ISO 639-1 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for your language, e.g. `en` or `en-GB`. This must be a language that the app has already been [translated](https://github.com/Lissy93/dashy/tree/master/src/assets/locales) into. If your language is unavailable, Dashy will fallback to English. By default Dashy will attempt to auto-detect your language, although this may not work on some privacy browsers.
+**`startingView`** | `enum` | _Optional_ | Which page to load by default, and on the base page or domain root. You can still switch to different views from within the UI. Can be either `default`, `minimal` or `workspace`. Defaults to `default`
+**`defaultOpeningMethod`** | `enum` | _Optional_ | The default opening method for items, if no `target` is specified for a given item. Can be either `newtab`, `sametab`, `modal`, `workspace`, `clipboard`, `top` or `parent`. Defaults to `newtab`
+**`statusCheck`** | `boolean` | _Optional_ | When set to `true`, Dashy will ping each of your services and display their status as a dot next to each item. This can be overridden by setting `statusCheck` under each item. Defaults to `false`
+**`statusCheckInterval`** | `boolean` | _Optional_ | The number of seconds between checks. If set to `0` then service will only be checked on initial page load, which is usually the desired functionality. If value is less than `10` you may experience a hit in performance. Defaults to `0`
+**`webSearch`** | `object` | _Optional_ | Configuration options for the web search feature, set your default search engine, opening method or disable web search. See [`webSearch`](#appconfigwebsearch-optional)
+**`backgroundImg`** | `string` | _Optional_ | Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load
+**`enableFontAwesome`** | `boolean` | _Optional_ | Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons
+**`fontAwesomeKey`** | `string` | _Optional_ | If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`)
+**`faviconApi`** | `enum` | _Optional_ | Only applicable if you are using favicons for item icons. Specifies which service to use to resolve favicons. Set to `local` to do this locally, without using an API. Services running locally will use this option always. Available options are: `local`, `faviconkit`, `iconhorse`, `google`, `clearbit`, `webmasterapi` and `allesedv`. Defaults to `faviconkit`. See [Icons](/docs/icons#favicons) for more info
+**`auth`** | `object` | _Optional_ | All settings relating to user authentication. See [`auth`](#appconfigauth-optional)
+**`layout`** | `enum` | _Optional_ | Layout for homepage, either `horizontal`, `vertical` or `auto`. Defaults to `auto`. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified and overridden from the UI.
+**`iconSize`** | `enum` | _Optional_ | The size of link items / icons. Can be either `small`, `medium,` or `large`. Defaults to `medium`. This can also be set directly from the UI.
+**`colCount`** | `number` | _Optional_ | The number of columns of sections displayed on the homepage, using the default view. Should be in integer between `1` and `8`. Note that by default this is applied responsively, based on current screen size, and specifying a value here will override this behavior, which may not be desirable.
+**`theme`** | `string` | _Optional_ | The default theme for first load (you can change this later from the UI)
+**`cssThemes`** | `string[]` | _Optional_ | An array of custom theme names which can be used in the theme switcher dropdown
+**`customColors`** | `object`| _Optional_ | Enables you to apply a custom color palette to any given theme. Use the theme name (lowercase) as the key, for an object including key-value-pairs, with the color variable name as keys, and 6-digit hex code as value. See [Theming](/docs/theming#modifying-theme-colors) for more info
+**`externalStyleSheet`** | `string` or `string[]` | _Optional_ | Either a URL to an external stylesheet or an array or URLs, which can be applied as themes within the UI
+**`customCss`** | `string` | _Optional_ | Raw CSS that will be applied to the page. This can also be set from the UI. Please minify it first.
+**`hideComponents`** | `object` | _Optional_ | A list of key page components (header, footer, search, settings, etc) that are present by default, but can be removed using this option. See [`appConfig.hideComponents`](#appconfighideComponents-optional)
+**`routingMode`** | `string` | _Optional_ | Can be either `hash` or `history`. Determines the URL format for sub-pages, hash mode will look like `/#/home` whereas with history mode available you have nice clean URLs, like `/home`. For more info, see the [Vue docs](https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations). If you're hosting Dashy with a custom BASE_URL, you will find that a bit of extra server config is necessary to get history mode working, so here you may want to instead use `hash` mode.Defaults to `history`.
+**`enableMultiTasking`** | `boolean` | _Optional_ | If set to true, will keep apps open in the background when in the workspace view. Useful for quickly switching between multiple sites, and preserving their state, but comes at the cost of performance.
+**`workspaceLandingUrl`** | `string` | _Optional_ | The URL or an app, service or website to launch when the workspace view is opened, before another service has been launched
+**`allowConfigEdit`** | `boolean` | _Optional_ | Should prevent / allow the user to write configuration changes to the conf.yml from the UI. When set to `false`, the user can only apply changes locally using the config editor within the app, whereas if set to `true` then changes can be written to disk directly through the UI. Defaults to `true`. Note that if authentication is enabled, the user must be of type `admin` in order to apply changes globally.
+**`showSplashScreen`** | `boolean` | _Optional_ | If set to `true`, a loading screen will be shown. Defaults to `false`.
+**`enableErrorReporting`** | `boolean` | _Optional_ | Enable reporting of unexpected errors and crashes. This is off by default, and **no data will ever be captured unless you explicitly enable it**. Turning on error reporting helps previously unknown bugs get discovered and fixed. Dashy uses [Sentry](https://github.com/getsentry/sentry) for error reporting. Defaults to `false`.
+**`sentryDsn`** | `boolean` | _Optional_ | If you need to monitor errors in your instance, then you can use Sentry to collect and process bug reports. Sentry can be self-hosted, or used as SaaS, once your instance is setup, then all you need to do is pass in the DSN here, and enable error reporting. You can learn more on the [Sentry DSN Docs](https://docs.sentry.io/product/sentry-basics/dsn-explainer/). Note that this will only ever be used if `enableErrorReporting` is explicitly enabled.
+**`disableSmartSort`** | `boolean` | _Optional_ | For the most-used and last-used app sort functions to work, a basic open-count is stored in local storage. If you do not want this to happen, then disable smart sort here, but you wil no longer be able to use these sort options. Defaults to `false`.
+**`disableUpdateChecks`** | `boolean` | _Optional_ | If set to true, Dashy will not check for updates. Defaults to `false`.
+**`enableServiceWorker`** | `boolean` | _Optional_ | Service workers cache web applications to improve load times and offer basic offline functionality, and are enabled by default in Dashy. The service worker can sometimes cause older content to be cached, requiring the app to be hard-refreshed. If you do not want SW functionality, or are having issues with caching, set this property to `true` to disable all service workers.
+**`disableContextMenu`** | `boolean` | _Optional_ | If set to `true`, the custom right-click context menu will be disabled. Defaults to `false`.
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig.auth` _(optional)_
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`users`** | `array` | _Optional_ | An array of objects containing usernames and hashed passwords. If this is not provided, then authentication will be off by default, and you will not need any credentials to access the app. See [`appConfig.auth.users`](#appconfigauthusers-optional). **Note** this method of authentication is handled on the client side, so for security critical situations, it is recommended to use an [alternate authentication method](/docs/authentication#alternative-authentication-methods).
+**`enableKeycloak`** | `boolean` | _Optional_ | If set to `true`, then authentication using Keycloak will be anabled. Note that you need to have an instance running, and have also configured `auth.keycloak`. Defaults to `false`
+**`keycloak`** | `object` | _Optional_ | Config options to point Dashy to your Keycloak server. Requires `enableKeycloak: true`. See [`auth.keycloak`](#appconfigauthkeycloak-optional) for more info
+**`enableGuestAccess`** | `boolean` | _Optional_ | When set to `true`, an unauthenticated user will be able to access the dashboard, with read-only access, without having to login. Requires `auth.users` to be configured. Defaults to `false`.
+
+For more info, see the **[Authentication Docs](/docs/authentication)**
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig.auth.users` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`user`** | `string` | Required | Username to log in with
+**`hash`** | `string` | Required | A SHA-256 hashed password
+**`type`** | `string` | _Optional_ | The user type, either admin or normal
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig.auth.keycloak` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`serverUrl`** | `string` | Required | The URL (or URL/ IP + Port) where your keycloak server is running
+**`realm`** | `string` | Required | The name of the realm (must already be created) that you want to use
+**`clientId`** | `string` | Required | The Client ID of the client you created for use with Dashy
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig.webSearch` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`disableWebSearch`** | `string` | _Optional_ | Web search is enabled by default, but can be disabled by setting this property to `true`
+**`searchEngine`** | `string` | _Optional_ | Set the key name for your search engine. Can also use a custom engine by setting this property to `custom`. Currently supported: `duckduckgo`, `google`, `whoogle`, `qwant`, `startpage`, `searx-bar` and `searx-info`. Defaults to `duckduckgo`
+**`customSearchEngine`** | `string` | _Optional_ | You can also use a custom search engine, or your own self-hosted instance. This requires `searchEngine: custom` to be set. Then add the URL of your service, with GET query string included here
+**`openingMethod`** | `string` | _Optional_ | Set your preferred opening method for search results: `newtab`, `sametab`, `workspace`. Defaults to `newtab`
+**`searchBangs`** | `object` | _Optional_ | A key-value-pair set of custom search _bangs_ for redirecting query to a specific app or search engine. The key of each should be the bang you will type (typically starting with `/`, `!` or `:`), and value is the destination, either as a search engine key (e.g. `reddit`) or a URL with search parameters (e.g. `https://en.wikipedia.org/w/?search=`)
+
+
+**[âŦī¸ Back to Top](#)**
+
+### `appConfig.hideComponents` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`hideHeading`** | `boolean` | _Optional_ | If set to `true`, the page title & sub-title will not be visible. Defaults to `false`
+**`hideNav`** | `boolean` | _Optional_ | If set to `true`, the navigation menu will not be visible. Defaults to `false`
+**`hideSearch`** | `boolean` | _Optional_ | If set to `true`, the search bar will not be visible. Defaults to `false`
+**`hideSettings`** | `boolean` | _Optional_ | If set to `true`, the settings menu will be initially collapsed. Defaults to `false`
+**`hideFooter`** | `boolean` | _Optional_ | If set to `true`, the footer will not be visible. Defaults to `false`
+
+**[âŦī¸ Back to Top](#)**
+
+### `section`
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`name`** | `string` | Required | The title for the section
+**`icon`** | `string` | _Optional_ | An single icon to be displayed next to the title. See [`section.icon`](#sectionicon-and-sectionitemicon)
+**`items`** | `array` | _Optional_ | An array of items to be displayed within the section. See [`item`](#sectionitem). Sections must include either 1 or more items, or 1 or more widgets.
+**`widgets`** | `array` | _Optional_ | An array of widgets to be displayed within the section. See [`widget`](#sectionwidget-optional)
+**`displayData`** | `object` | _Optional_ | Meta-data to optionally overide display settings for a given section. See [`displayData`](#sectiondisplaydata-optional)
+
+**[âŦī¸ Back to Top](#)**
+
+### `section.item`
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`title`** | `string` | Required | The text to display/ title of a given item. Max length `18`
+**`description`** | `string` | _Optional_ | Additional info about an item, which is shown in the tooltip on hover, or visible on large tiles
+**`url`** | `string` | Required | The URL / location of web address for when the item is clicked
+**`icon`** | `string` | _Optional_ | The icon for a given item. Can be a font-awesome icon, favicon, remote URL or local URL. See [`item.icon`](#sectionicon-and-sectionitemicon)
+**`target`** | `string` | _Optional_ | The opening method for when the item is clicked, either `newtab`, `sametab`, `modal`, `workspace`, `clipboard`, `top` or `parent`. Where `newtab` will open the link in a new tab, `sametab` will open it in the current tab, and `modal` will open a pop-up modal, `workspace` will open in the Workspace view and `clipboard` will copy the URL to system clipboard (but not launch app). Defaults to `newtab`
+**`hotkey`** | `number` | _Optional_ | Give frequently opened applications a numeric hotkey, between `0 - 9`. You can then just press that key to launch that application.
+**`tags`** | `string[]` | _Optional_ | A list of tags, which can be used for improved search
+**`statusCheck`** | `boolean` | _Optional_ | When set to `true`, Dashy will ping the URL associated with the current service, and display its status as a dot next to the item. The value here will override `appConfig.statusCheck` so you can turn off or on checks for a given service. Defaults to `appConfig.statusCheck`, falls back to `false`
+**`statusCheckUrl`** | `string` | _Optional_ | If you've enabled `statusCheck`, and want to use a different URL to what is defined under the item, then specify it here
+**`statusCheckHeaders`** | `object` | _Optional_ | If you're endpoint requires any specific headers for the status checking, then define them here
+**`statusCheckAllowInsecure`** | `boolean` | _Optional_ | By default, any request to insecure content will be blocked. Setting this option to `true` will disable the `rejectUnauthorized` option, enabling you to ping non-HTTPS services for the current item. Defaults to `false`
+**`color`** | `string` | _Optional_ | An optional color for the text and font-awesome icon to be displayed in. Note that this will override the current theme and so may not display well
+**`backgroundColor`** | `string` | _Optional_ | An optional background fill color for the that given item. Again, this will override the current theme and so might not display well against the background
+**`provider`** | `string` | _Optional_ | The name of the provider for a given service, useful for when including hosted apps. In some themes, this is visible under the item name
+
+**[âŦī¸ Back to Top](#)**
+
+### `section.widget` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`type`** | `string` | Required | The widget type. See [Widget Docs](/docs/widgets) for full list of supported widgets
+**`options`** | `object` | _Optional_ | Some widgets accept either optional or required additional options. Again, see the [Widget Docs](/docs/widgets) for full list of options
+**`updateInterval`** | `number` | _Optional_ | You can keep a widget constantly updated by specifying an update interval, in seconds. See [Continuous Updates Docs](/docs/widgets#continuous-updates) for more info
+**`useProxy`** | `boolean` | _Optional_ | Some widgets make API requests to services that are not CORS-enabled. For these instances, you will need to route requests through a proxy, Dashy has a built in CORS-proxy, which you can use by setting this option to `true`. Defaults to `false`. See the [Proxying Requests Docs](/docs/widgets#proxying-requests) for more info
+
+**[âŦī¸ Back to Top](#)**
+
+
+### `section.displayData` _(optional)_
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`sortBy`** | `string` | _Optional_ | The sort order for items within the current section. By default items are displayed in the order in which they are listed in within the config. The following sort options are supported: `most-used` (most opened apps first), `last-used` (the most recently used apps), `alphabetical`, `reverse-alphabetical`, `random` and `default`
+**`collapsed`** | `boolean` | _Optional_ | If true, the section will be collapsed initially, and will need to be clicked to open. Useful for less regularly used, or very long sections. Defaults to `false`
+**`cutToHeight`** | `boolean` | _Optional_ | By default, sections will fill available space. Set this option to true to match section height with content height
+**`rows`** | `number` | _Optional_ | Height of the section, specified as the number of rows it should span vertically, e.g. `2`. Defaults to `1`. Max is `5`.
+**`cols`** | `number` | _Optional_ | Width of the section, specified as the number of columns the section should span horizontally, e.g. `2`. Defaults to `1`. Max is `5`.
+**`itemSize`** | `string` | _Optional_ | Specify the size for items within this group, either `small`, `medium` or `large`. Note that this will overide any settings specified through the UI
+**`color`** | `string` | _Optional_ | A custom accent color for the section, as a hex code or HTML color (e.g. `#fff`)
+**`customStyles`** | `string` | _Optional_ | Custom CSS properties that should be applied to that section, e.g. `border: 2px dashed #ff0000;`
+**`sectionLayout`** | `string` | _Optional_ | Specify which CSS layout will be used to responsivley place items. Can be either `auto` (which uses flex layout), or `grid`. If `grid` is selected, then `itemCountX` and `itemCountY` may also be set. Defaults to `auto`
+**`itemCountX`** | `number` | _Optional_ | The number of items to display per row / horizontally. If not set, it will be calculated automatically based on available space. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
+**`itemCountY`** | `number` | _Optional_ | The number of items to display per column / vertically. If not set, it will be calculated automatically based on available space. If `itemCountX` is set, then `itemCountY` can be calculated automatically. Can only be set if `sectionLayout` is set to `grid`. Must be a whole number between `1` and `12`
+**`hideForUsers`** | `string[]` | _Optional_ | Current section will be visible to all users, except for those specified in this list
+**`showForUsers`** | `string[]` | _Optional_ | Current section will be hidden from all users, except for those specified in this list
+**`hideForGuests`** | `boolean` | _Optional_ | Current section will be visible for logged in users, but not for guests (see `appConfig.enableGuestAccess`). Defaults to `false`
+**`hideForKeycloakUsers`** | `object` | _Optional_ | Current section will be visible to all keycloak users, except for those configured via these groups and roles. See `hideForKeycloakUsers`
+**`showForKeycloakUsers`** | `object` | _Optional_ | Current section will be hidden from all keyclaok users, except for those configured via these groups and roles. See `showForKeycloakUsers`
+
+**[âŦī¸ Back to Top](#)**
+
+### `section.icon` and `section.item.icon`
+
+**Field** | **Type** | **Required**| **Description**
+--- | --- | --- | ---
+**`icon`** | `string` | _Optional_ | The icon for a given item or section. See [Icon Docs](/docs/icons) for all available supported icon types, including: auto-fetched favicons, generative icons, emoji icons, home-lab service logos, font-awesome, simple-icons, material icons, and icons specified by URL
+
+**[âŦī¸ Back to Top](#)**
+
+### `section.displayData.hideForKeycloakUsers` and `section.displayData.showForKeycloakUsers`
+
+**Field** | **Type** | **Required**| **Description**
+--- |------------| --- | ---
+**`groups`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the groups in this list
+**`roles`** | `string[]` | _Optional_ | Current Section will be hidden or shown based on the user having any of the roles in this list
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Notes
+
+### Editing Config through the UI
+
+Config can be modified directly through the UI, and then written to disk, or applied locally. This can be done wither with the raw config editor (introduced in V 0.6.5 / [#3](https://github.com/Lissy93/dashy/pull/3)), or the interactive editor (introduced in V 1.8.9 / [#298](https://github.com/Lissy93/dashy/pull/298)).
+
+
+
+ Interactive Editor
+
+
+
+
+ JSON Editor
+
+
+
+
+### About YAML
+If you're new to YAML, it's pretty straight-forward. The format is exactly the same as that of JSON, but instead of using curly braces, structure is denoted using whitespace. This [quick guide](https://linuxhandbook.com/yaml-basics/) should get you up to speed in a few minutes, for more advanced topics take a look at this [Wikipedia article](https://en.wikipedia.org/wiki/YAML).
+
+### Config Saving Methods
+When updating the config through the JSON editor in the UI, you have two save options: **Local** or **Write to Disk**.
+- Changes saved locally will only be applied to the current user through the browser, and will not apply to other instances - you either need to use the cloud sync feature, or manually update the conf.yml file.
+- On the other-hand, if you choose to write changes to disk, then your main `conf.yml` file will be updated, and changes will be applied to all users, and visible across all devices. For this functionality to work, you must be running Dashy with using the Docker container, or the Node server. A backup of your current configuration will also be saved in the same directory.
+
+### Preventing Changes being Written to Disk
+To disallow any changes from being written to disk via the UI config editor, set `appConfig.allowConfigEdit: false`. If you are using users, and have setup `auth` within Dashy, then only users with `type: admin` will be able to write config changes to disk.
+
+### Example
+
+```yaml
+---
+pageInfo:
+ title: Home Lab
+sections: # An array of sections
+- name: Section 1 - Getting Started
+ items: # An array of items
+ - title: GitHub
+ description: Source code and documentation on GitHub
+ icon: fab fa-github
+ url: https://github.com/Lissy93/dashy
+ - title: Issues
+ description: View currently open issues, or raise a new one
+ icon: fas fa-bug
+ url: https://github.com/Lissy93/dashy/issues
+ - title: Demo
+ description: A live demo
+ icon: far fa-rocket
+ url: https://dashy-demo-1.netlify.app
+- name: Section 2 - Local Services
+ items:
+ - title: Firewall
+ icon: favicon
+ url: http://192.168.1.1/
+ - title: Game Server
+ icon: https://i.ibb.co/710B3Yc/space-invader-x256.png
+ url: http://192.168.130.1/
+```
+
+For more example config files, see: [this gist](https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10)
+
+If you need any help, feel free to [Raise an Issue](https://github.com/Lissy93/dashy/issues/new?assignees=Lissy93&labels=%F0%9F%A4%B7%E2%80%8D%E2%99%82%EF%B8%8F+Question&template=question.md&title=%5BQUESTION%5D) or [Start a Discussion](https://github.com/Lissy93/dashy/discussions)
+
+Happy Configuring đ¤đ§
+
+**[âŦī¸ Back to Top](#)**
+
diff --git a/docs/contributing.md b/docs/contributing.md
index 243f71c7..9cb2be0e 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -1,14 +1,8 @@
# Contributing
First off, thank you for considering contributing towards Dashy! đ
-There are several ways that you can help out (but don't feel you have to).
-Any contributions, however small will always be very much appreciated, and you will be appropriately credited in the readme - huge thank you to [everyone who has helped](/docs/credits) so far đ
-
-## Submit a PR
-Contributing to the code or documentation is super helpful. You can fix a bug, add a new feature or improve an existing one. I've written [several guides](https://github.com/Lissy93/dashy/blob/master/docs/development-guides) to help you get started. For setting up the development environment, outline of the standards, and understanding the PR flow, see the [Development Docs](https://github.com/Lissy93/dashy/blob/master/docs/development). I've tried to keep the code neat and documentation thorough, so understanding what everything does should be fairly straight forward, but feel free to ask if you have any questions.
-
-## Add Translations
-If you speak another language, then adding translations would be really helpful, and you will be credited in the readme for your work. Multi-language support makes Dashy accessible for non-English speakers, which I feel is important. This is a very quick and easy task, as all application text is located in [`locales/en.json`](https://github.com/Lissy93/dashy/blob/master/src/assets/locales/en.json), so adding a new language is as simple as copying this file and translating the values. You don't have to translate it all, as any missing attributes will just fallback to English. For a full tutorial, see the [Multi-Language Support Docs](https://github.com/Lissy93/dashy/blob/master/docs/multi-language-support).
+There are several ways that you can help out, and any contributions, however small will always be very much appreciated.
+You will be appropriately credited in the readme - huge thank you to [everyone who has helped](/docs/credits) so far đ
## Take a 2-minute survey
Help improve Dashy by taking a very short, 6-question survey. This will give me a better understanding of what is important to you, so that I can make Dashy better in the future :)
@@ -16,10 +10,40 @@ Help improve Dashy by taking a very short, 6-question survey. This will give me
[![Take the Survey](https://img.shields.io/badge/Take_the-Survey-%231a86fd?style=for-the-badge&logo=buddy)](https://survey.typeform.com/to/gl0L68ou)
## Share your dashboard
-Dashy now has a [Showcase](https://github.com/Lissy93/dashy/blob/master/docs/showcase#dashy-showcase-) where you can show off a screenshot of your dashboard, and get inspiration from other users. I also really enjoy seeing how people are using Dashy. To [submit your dashboard](https://github.com/Lissy93/dashy/blob/master/docs/showcase#submitting-your-dashboard), please either open a PR or raise an issue.
+Dashy now has a [Showcase](https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#dashy-showcase-) where you can show off a screenshot of your dashboard, and get inspiration from other users (and I really love seeing how people are using Dashy). To [submit your dashboard](https://github.com/Lissy93/dashy/blob/master/docs/showcase.md#submitting-your-dashboard), either open a PR or raise an issue.
+
+[![Add your Dashboard to the Showcase](https://img.shields.io/badge/Add_your_Dashboard-Showcase-%238616ee?style=for-the-badge&logo=feathub&logoColor=8616ee)](https://github.com/Lissy93/dashy/issues/new?assignees=&labels=%F0%9F%92%AF+Showcase&template=showcase-addition.yml&title=%5BSHOWCASE%5D+%3Ctitle%3E)
+
+## Make a small donation
+
+Donations help to cover server costs, development time and caffeine ;)
+Don't feel any pressure to donate anything, as Dashy and my other projects will always be 100% free, for everyone, for ever.
+
+[![Sponsor Lissy93 on GitHub](https://img.shields.io/badge/Sponsor_on_GitHub-Lissy93-%23ff4dda?style=for-the-badge&logo=githubsponsors&logoColor=ff4dda)](https://github.com/sponsors/Lissy93)
+
+Sponsoring will give you several perks - for $1 / ÂŖ0.75 per month, you'll get a sponsor badge on your profile, be credited on the Dashy's readme, with a link to your website/ profile/ socials, get priority support, have your feature ideas implemented, plus lots more. For more info, see [@Lissy93's Sponsor Page](https://github.com/sponsors/Lissy93).
+
+## Enable Anonymous Bug Reports
+
+Bug reports helps me to discover bugs I was unaware of, and then fix them, in order to make Dashy more reliable long term. This is a simple, yet really helpful step you can take to help improve Dashy. [Sentry](https://github.com/getsentry/sentry) is an open source error tracking and performance monitoring tool, which enables the identification any errors which occur in the production app (only if you enable it).
+
+To enable error reporting:
+```yaml
+appConfig:
+ enableErrorReporting: true
+```
+
+All reporting is **disabled** by default, and no data will ever be sent to any external endpoint without your explicit consent. All statistics are anonomized and stored securely. For more about privacy and security, see the [Sentry Security Docs](https://sentry.io/security/).
+
+## Add Translations
+If you speak another language, then adding translations will help make Dashy available to non-native English speakers. This is a very quick and easy task, as all application text is located in [`locales/en.json`](https://github.com/Lissy93/dashy/blob/master/src/assets/locales/en.json), so adding a new language is as simple as copying this file and translating the values. You don't have to translate it all, as any missing attributes will just fallback to English. For a full tutorial, see the [Multi-Language Support Docs](https://github.com/Lissy93/dashy/blob/master/docs/multi-language-support).
+
+## Submit a PR
+Contributing to the code or docs is super helpful. You can fix a bug, add a new feature or improve an existing one. If you've built your own custom widget, theme or view, consider sharing it in a PR. I've written [several guides](/docs/development-guides) to help you get started, and the steps for setting up the development environment are outlined in the [Development Docs](/docs/development). Feel free to ask if you have any questions.
## Improve the Docs
Found a typo, or something that isn't as clear as it could be? Maybe I've missed something off altogether, or you hit a roadblock that took you a while to figure out. Submitting a pull request to add to or improve the documentation will help future users get Dashy up and running more easily.
+All content is located either in the [`./README.md`](/README) or [`/docs/`](/docs) directory, and synced to the Wiki and website using a GH [action](/actions/workflows/wiki-sync.yml).
## Raise a bug
If you've found a bug, then please do raise it as an issue. This will help me know if there's something that needs fixing. Try and include as much detail as possible, such as your environment, steps to reproduce, any console output and maybe an example screenshot or recording if necessary.
@@ -31,51 +55,33 @@ I've enabled the discussion feature on GitHub, here you can share tips and trick
[![Join the Discussion on GitHub](https://img.shields.io/badge/Join_the-Discussion-%23ffd000?style=for-the-badge&logo=livechat)](https://github.com/Lissy93/dashy/discussions)
-## Spread the word
-Dashy is still a relatively young project, and as such not many people know of it. It would be great to see more users, and so it would be awesome if you could consider sharing on social platforms.
-
-[![Share Dashy on Mastodon](https://img.shields.io/badge/Share-Mastodon-%232b90d9?style=for-the-badge&logo=mastodon)](https://mastodon.social/?text=Check%20out%20Dashy%2C%20the%20privacy-friendly%2C%20self-hosted%20startpage%20for%20organizing%20your%20life%3A%20https%3A%2F%2Fgithub.com%2FLissy93%2Fdashy%20-%20By%20%40lissy93%40mastodon.social)
-[![Share Dashy on Reddit](https://img.shields.io/badge/Share-Reddit-%23FF5700?style=for-the-badge&logo=reddit)](http://www.reddit.com/submit?url=https://github.com/Lissy93/dashy&title=Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
-[![Share Dashy on Twitter](https://img.shields.io/badge/Share-Twitter-%231DA1F2?style=for-the-badge&logo=twitter)](https://twitter.com/intent/tweet?url=https://github.com/lissy93/dashy&text=Check%20out%20Dashy%20by%20@Lissy_Sykes,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
-[![Share Dashy on Facebook](https://img.shields.io/badge/Share-Facebook-%234267B2?style=for-the-badge&logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/lissy93/dashy)
-[![Share Dashy on LinkedIn](https://img.shields.io/badge/Share-LinkedIn-%230077b5?style=for-the-badge&logo=linkedin)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/lissy93/dashy)
-[![Share Dashy on Pinterest](https://img.shields.io/badge/Share-Pinterest-%23E60023?style=for-the-badge&logo=pinterest)](https://pinterest.com/pin/create/button/?url=https://github.com/lissy93/dashy&media=https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png&description=Check%20out%20Dashy,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
-[![Share Dashy on VK](https://img.shields.io/badge/Share-VK-%234C75A3?style=for-the-badge&logo=vk)](https://vk.com/share.php?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%2F&title=Check%20out%20Dashy%20-%20The%20Self-Hosted%20Dashboard%20for%20your%20Homelab%20%F0%9F%9A%80)
-[![Share Dashy via Viber](https://img.shields.io/badge/Share-Viber-%238176d6?style=for-the-badge&logo=viber)](viber://forward?text=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%0ACheck%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
-[![Share Dashy via Telegram](https://img.shields.io/badge/Share-Telegram-%230088cc?style=for-the-badge&logo=telegram)](https://t.me/share/url?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy&text=Check%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
-[![Share Dashy via Email](https://img.shields.io/badge/Share-Email-%238A90C7?style=for-the-badge&logo=protonmail)](mailto:info@example.com?&subject=Check%20out%20Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80&cc=&bcc=&body=https://github.com/lissy93/dashy)
-
-## Star, Upvote or Leave a Review
-Dashy is on the following platforms, and if you could spare a few seconds to give it an upvote or review, this will also help new users find it.
-
-[![ProductHunt](https://img.shields.io/badge/Review-ProductHunt-%23b74424?style=for-the-badge&logo=producthunt)](https://www.producthunt.com/posts/dashy)
-[![AlternativeTo](https://img.shields.io/badge/Review-AlternativeTo-%235581a6?style=for-the-badge&logo=abletonlive)](https://alternativeto.net/software/dashy/about/)
-[![Slant](https://img.shields.io/badge/Review-Slant-%2346a1df?style=for-the-badge&logo=capacitor)](https://www.slant.co/improve/topics/27783/viewpoints/1/~self-hosted-homelab-startpage~dashy)
-[![Star on GitHub](https://img.shields.io/github/stars/Lissy93/Dashy?color=ba96d6&label=Star%20-%20GitHub&logo=github&style=for-the-badge)](https://github.com/Lissy93/dashy/stargazers)
-[![Star on DockerHub](https://img.shields.io/docker/stars/lissy93/dashy?color=4cb6e0&label=Star%20-%20Docker&logo=docker&style=for-the-badge)](https://hub.docker.com/r/lissy93/dashy)
-
-## Make a small donation
-Please only do this is you can definitely afford to. Don't feel any pressure to donate anything, as Dashy and my other projects will always be 100% free, for everyone, for ever.
-
-[![Sponsor Lissy93 on GitHub](./assets/sponsor-button.svg)](https://github.com/sponsors/Lissy93)
-
-Sponsoring will give you several perks, from $1 / ÂŖ0.70 per month, as well as a sponsor badge on your profile, you can also be credited on the readme, with a link to your website/ profile/ socials, get priority support, have your feature ideas implemented, plus lots more. For more info, see [@Lissy93's Sponsor Page](https://github.com/sponsors/Lissy93).
-
## Request a feature via BountySource
BountySource is a platform for sponsoring the development of certain features on open source projects. If there is a feature you'd like implemented into Dashy, but either isn't high enough priority or is deemed to be more work than it's worth, then you can instead contribute a bounty towards it's development. You won't pay a penny until your proposal is fully built, and you are satisfied with the result. This helps support the developers, and makes Dashy better for everyone.
[![Request a Feature on BountySource](https://img.shields.io/badge/BountySource-Dashy-%23F67909?style=for-the-badge&logo=openbugbounty)](https://www.bountysource.com/teams/dashy)
-## Enable Anonymous Bug Reports
-[Sentry](https://github.com/getsentry/sentry) is an open source error tracking and performance monitoring tool, which enables the identification any errors which occur in the production app (only if you enable it). It helps me to discover bugs I was unaware of, and then fix them, in order to make Dashy more reliable long term. This is a simple, yet really helpful step you can take to help improve Dashy.
+## Spread the word
+Dashy is still a relatively young project, and as such not many people know of it. It would be great to see more users, and so it would be awesome if you could consider sharing with your friends or on social platforms.
-To enable error reporting:
-```yaml
-appConfig:
- enableErrorReporting: true
-```
+[![Share Dashy on Mastodon](https://img.shields.io/badge/Share-Mastodon-%232b90d9?style=flat-square&logo=mastodon)](https://mastodon.social/?text=Check%20out%20Dashy%2C%20the%20privacy-friendly%2C%20self-hosted%20startpage%20for%20organizing%20your%20life%3A%20https%3A%2F%2Fgithub.com%2FLissy93%2Fdashy%20-%20By%20%40lissy93%40mastodon.social)
+[![Share Dashy on Reddit](https://img.shields.io/badge/Share-Reddit-%23FF5700?style=flat-square&logo=reddit)](http://www.reddit.com/submit?url=https://github.com/Lissy93/dashy&title=Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
+[![Share Dashy on Twitter](https://img.shields.io/badge/Share-Twitter-%231DA1F2?style=flat-square&logo=twitter)](https://twitter.com/intent/tweet?url=https://github.com/lissy93/dashy&text=Check%20out%20Dashy%20by%20@Lissy_Sykes,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
+[![Share Dashy on Facebook](https://img.shields.io/badge/Share-Facebook-%234267B2?style=flat-square&logo=facebook)](https://www.facebook.com/sharer/sharer.php?u=https://github.com/lissy93/dashy)
+[![Share Dashy on LinkedIn](https://img.shields.io/badge/Share-LinkedIn-%230077b5?style=flat-square&logo=linkedin)](https://www.linkedin.com/shareArticle?mini=true&url=https://github.com/lissy93/dashy)
+[![Share Dashy on Pinterest](https://img.shields.io/badge/Share-Pinterest-%23E60023?style=flat-square&logo=pinterest)](https://pinterest.com/pin/create/button/?url=https://github.com/lissy93/dashy&media=https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png&description=Check%20out%20Dashy,%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
+[![Share Dashy on VK](https://img.shields.io/badge/Share-VK-%234C75A3?style=flat-square&logo=vk)](https://vk.com/share.php?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%2F&title=Check%20out%20Dashy%20-%20The%20Self-Hosted%20Dashboard%20for%20your%20Homelab%20%F0%9F%9A%80)
+[![Share Dashy via Viber](https://img.shields.io/badge/Share-Viber-%238176d6?style=flat-square&logo=viber)](viber://forward?text=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy%0ACheck%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
+[![Share Dashy via Telegram](https://img.shields.io/badge/Share-Telegram-%230088cc?style=flat-square&logo=telegram)](https://t.me/share/url?url=https%3A%2F%2Fgithub.com%2Flissy93%2Fdashy&text=Check%20out%20Dashy%2C%20the%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80)
+[![Share Dashy via Email](https://img.shields.io/badge/Share-Email-%238A90C7?style=flat-square&logo=protonmail)](mailto:info@example.com?&subject=Check%20out%20Dashy%20-%20The%20self-hosted%20dashboard%20for%20your%20homelab%20%F0%9F%9A%80&cc=&bcc=&body=https://github.com/lissy93/dashy)
-All reporting is **disabled** by default, and no data will ever be sent to any external endpoint without your explicit consent. In fact, the error tracking package will not even be imported unless you have actively enabled it. All statistics are anonomized and stored securely. For more about privacy and security, see the [Sentry Docs](https://sentry.io/security/).
+## Star, Upvote or Leave a Review
+Dashy is on the following platforms, and if you could spare a few seconds to give it an upvote or review, this will also help new users discover Dashy
+
+[![ProductHunt](https://img.shields.io/badge/Review-ProductHunt-%23b74424?style=flat-square&logo=producthunt)](https://www.producthunt.com/posts/dashy)
+[![AlternativeTo](https://img.shields.io/badge/Review-AlternativeTo-%235581a6?style=flat-square&logo=abletonlive)](https://alternativeto.net/software/dashy/about/)
+[![Slant](https://img.shields.io/badge/Review-Slant-%2346a1df?style=flat-square&logo=capacitor)](https://www.slant.co/improve/topics/27783/viewpoints/1/~self-hosted-homelab-startpage~dashy)
+[![Star on GitHub](https://img.shields.io/github/stars/Lissy93/Dashy?color=ba96d6&label=Star%20-%20GitHub&logo=github&style=flat-square)](https://github.com/Lissy93/dashy/stargazers)
+[![Star on DockerHub](https://img.shields.io/docker/stars/lissy93/dashy?color=4cb6e0&label=Star%20-%20Docker&logo=docker&style=flat-square)](https://hub.docker.com/r/lissy93/dashy)
## Follow for More
If you've enjoyed Dashy, you can follow the me to get updates about other projects that I am working on.
@@ -84,11 +90,11 @@ If you've enjoyed Dashy, you can follow the me to get updates about other projec
[![Alicia Sykes on GitHub](https://img.shields.io/github/followers/lissy93?label=Lissy93&style=social)](https://github.com/Lissy93)
[![Alicia Sykes on Mastodon](https://img.shields.io/mastodon/follow/1032965?domain=https%3A%2F%2Fmastodon.social)](https://mastodon.social/web/accounts/1032965)
[![Alicia Sykes on Keybase](https://img.shields.io/badge/aliciasykes--lightgrey?style=social&logo=Keybase)](https://keybase.io/aliciasykes)
-[![Alicia Sykes's PGP](https://img.shields.io/badge/PGP--lightgrey?style=social&logo=Let%E2%80%99s%20Encrypt)](https://keybase.io/aliciasykes/pgp_keys.asc)
[![Alicia Sykes's Website](https://img.shields.io/badge/aliciasykes.com--lightgrey?style=social&logo=Tencent%20QQ)](https://aliciasykes.com)
[![Alicia Sykes's Blog](https://img.shields.io/badge/Blog--lightgrey?style=social&logo=micro.blog)](https://notes.aliciasykes.com/)
+[![Alicia Sykes's PGP](https://img.shields.io/badge/PGP--lightgrey?style=social&logo=Let%E2%80%99s%20Encrypt)](https://keybase.io/aliciasykes/pgp_keys.asc)
-If you like, you could also consider [subscribing to my mailing list](https://notes.aliciasykes.com/subscribe) for very occasional blog post updates.
+If you like, you could also consider [subscribing to my mailing list](https://notes.aliciasykes.com/subscribe) for occasional blog post updates.
---
diff --git a/docs/credits.md b/docs/credits.md
index a1248762..b164b5c1 100644
--- a/docs/credits.md
+++ b/docs/credits.md
@@ -4,10 +4,10 @@
@@ -36,13 +50,6 @@
Alicia Sykes
-
-
-
-
- EVOTk
-
-
@@ -51,10 +58,10 @@
-
-
+
+
- Erik Vroon
+ EVOTk
@@ -64,6 +71,13 @@
Snyk Bot
+
+
+
+
+ Erik Vroon
+
+
@@ -72,6 +86,13 @@
+
+
+
+
+ Walkx
+
+
@@ -79,6 +100,13 @@
áĒŅÎŊΚΡ áˇĪ
ĐŊĘ
+
+
+
+
+ Stephen Rigney
+
+
@@ -99,7 +127,8 @@
David
-
+
+
@@ -113,8 +142,21 @@
FormatToday
-
-
+
+
+
+
+
+ Iaroslav Dronskii
+
+
+
+
+
+
+ Kieren Connell
+
+
@@ -128,13 +170,28 @@
Ryan Turner
-
+
+
Shreya Roy
+
+
+
+
+
+ Xert
+
+
+
+
+
+
+ Jnach
+
@@ -160,7 +217,7 @@
- urekd
+ Urekd
@@ -255,6 +312,7 @@ At it's core, the application uses [**Vue.js**](https://github.com/vuejs/vue), a
- [`axios`](https://github.com/axios/axios) - Promise based HTTP client by @mzabriskie and community `MIT`
- [`ajv`](https://github.com/ajv-validator/ajv) - JSON schema Validator by @epoberezkin and community `MIT`
- [`i18n`](https://github.com/kazupon/vue-i18n) - Internationalization plugin by @kazupon and community `MIT`
+- [`frappe-charts`](https://github.com/frappe/charts) - Lightweight charting library by @frappe `MIT`
#### Frontend Components
- [`vue-select`](https://github.com/sagalbot/vue-select) - Dropdown component by @sagalbot `MIT`
diff --git a/docs/deployment.md b/docs/deployment.md
index 7ac2aca6..02329ea4 100644
--- a/docs/deployment.md
+++ b/docs/deployment.md
@@ -16,6 +16,8 @@ Once you've got Dashy up and running, you'll want to configure it with your own
- [Deploy with Docker](#deploy-with-docker)
- [Using Docker Compose](#using-docker-compose)
+- [Unraid](#unraid)
+- [Synology NAS](#synology-nas)
- [Build from Source](#build-from-source)
- [Hosting with CDN](#hosting-with-cdn)
- [Run as executable](#run-as-executable)
@@ -23,7 +25,9 @@ Once you've got Dashy up and running, you'll want to configure it with your own
- [Deploy to cloud service](#deploy-to-cloud-service)
- [Use managed instance](#use-managed-instance)
-### Deploy with Docker
+---
+
+## Deploy with Docker
**Container Info**: [
![Docker Supported Architecture](https://img.shields.io/badge/Architectures-amd64%20|%20arm32v7%20|%20arm64v8-6ba6e5)
@@ -66,7 +70,9 @@ If you're deploying Dashy on a modern ARM-based board, such as a Raspberry Pi (2
The image defaults to `:latest`, but you can instead specify a specific version, e.g. `docker pull lissy93/dashy:release-1.5.0`
-### Using Docker Compose
+---
+
+## Using Docker Compose
Using Docker Compose can be useful for saving your specific config in files, without having to type out a long run command each time. Save compose config as a YAML file, and then run `docker compose up -d` (optionally use the `-f` flag to specify file location, if it isn't located at `./docker-compose.yml`), `-d` is detached mode (not running in the foreground of your terminal). Compose is also useful if you are using clusters, as the format is very similar to stack files, used with Docker Swarm.
@@ -106,7 +112,21 @@ You can use a different tag, by for example setting `image: lissy93/dashy:arm64v
If you are building from source, and would like to use one of the [other Dockerfiles](https://github.com/Lissy93/dashy/tree/master/docker), then under `services.dashy` first set `context: .`, then specify the the path to the dockerfile, e.g. `dockerfile: ./docker/Dockerfile-arm32v7`
-### Build from Source
+---
+
+## Unraid
+
+// TODO
+
+---
+
+## Synology NAS
+
+// TODO
+
+---
+
+## Build from Source
If you do not want to use Docker, you can run Dashy directly on your host system. For this, you will need both [git](https://git-scm.com/downloads) and the latest or LTS version of [Node.js](https://nodejs.org/) installed, and optionally [yarn](https://yarnpkg.com/)
@@ -116,6 +136,8 @@ If you do not want to use Docker, you can run Dashy directly on your host system
4. Build: `yarn build`
5. Run: `yarn start`
+---
+
### Deploy to cloud service
If you don't have a home server, then fear not - Dashy can be deployed to pretty much any cloud provider. The above Docker and NPM guides will work exactly the same on a VPS, but I've also setup some 1-Click deploy links for 10+ of the most common cloud providers, to make things easier. Note that if your instance is exposed to the internet, it will be your responsibility to adequately secure it.
@@ -236,13 +258,16 @@ yarn build
surge ./dist
```
+---
-### Hosting with CDN
+## Hosting with CDN
Once Dashy has been built, it is effectivley just a static web app. This means that it can be served up with pretty much any static host, CDN or web server. To host Dashy through a CDN, the steps are very similar to building from source: clone the project, cd into it, install dependencies, write your config file and build the app. Once build is complete you will have a `./dist` directory within Dashy's root, and this is the build application which is ready to be served up.
However without Dashy's node server, there are a couple of features that will be unavailible to you, including: Writing config changes to disk through the UI, triggering a rebuild through the UI and application status checks. Everything else will work fine.
+---
+
## Requirements
diff --git a/docs/developing.md b/docs/developing.md
index 80237766..886d3c83 100644
--- a/docs/developing.md
+++ b/docs/developing.md
@@ -193,6 +193,7 @@ Styleguides:
âââ package.json # Project meta-data, dependencies and paths to scripts
âââ src/ # Project front-end source code
âââ server.js # A Node.js server to serve up the /dist directory
+âââ services/ # All server-side endpoints and utilities
âââ vue.config.js # Vue.js configuration
âââ Dockerfile # The blueprint for building the Docker container
âââ docker-compose.yml # A Docker run command
@@ -214,6 +215,9 @@ Styleguides:
â âââ locales # All app text, each language in a separate JSON file
â â°ââ interface-icons # SVG icons used in the app
âââ components # All front-end Vue web components
+â âââ Charts # Charting components for dynamically displaying widget data
+â â âââ Gauge.vue # A speed-dial style chart for showing 0 - 100 values
+â â â°ââ PercentageChart.vue # A horizontal bar for showing percentage breakdowns
â âââ Configuration # Components relating to the user config pop-up
â â âââ AppInfoModal.vue # A modal showing core app info, like version, language, etc
â â âââ AppVersion.vue # Shows current version from package.json, compares with GitHub
@@ -225,15 +229,30 @@ Styleguides:
â â â°ââ RebuildApp.vue # A component allowing user to trigger a rebuild through the UI
â âââ FormElements # Basic form elements used throughout the app
â â âââ Button.vue # Standard button component
-â â â°ââ Input.vue # Standard text field input component
+â â âââ Radio.vue # Standard radio button input
+â â âââ Select.vue # Standard dropdown input selector
+â â âââ Input.vue # Standard text field input component
+â â â°ââ Toggle.vue # Standard on / off toggle switch
+â âââ InteractiveEditor # Components for the interactive UI config editor
+â â âââ AddNewSectionLauncher # Button that launches the EditSection form, used for adding new section
+â â âââ EditAppConfig.vue # Form for editing appConfig
+â â âââ EditPageInfo.vue # Form for editing pageInfo
+â â âââ EditSection.vue # Form for adding / editing sections
+â â âââ EditItem.vue # Form for adding or editing items
+â â âââ EditModeSaveMenu.vue # The bar at the bottom of screen in edit mode, containing save buttons
+â â âââ EditModeTopBanner.vue # The bar at the top of screen in edit mode
+â â âââ ExportConfigMenu.vue # Modal for viewing / exporting edited config
+â â âââ MoveItemTo.vue # Form for moving / copying items to other sections
+â â â°ââ SaveCancelButtons.vue # Buttons visible in all the edit menus, to save or cancel changes
â âââ LinkItems # Components for Sections and Link Items
â â âââ Collapsable.vue # The collapsible functionality of sections
-â â âââ ContextMenu.vue # The right-click menu, for showing Item opening methods and info
â â âââ IframeModal.vue # Pop-up iframe modal, for viewing websites within the app
â â âââ Item.vue # Main link item, which is displayed within an item group
â â âââ ItemGroup.vue # Item group is a section containing icons
â â âââ ItemIcon.vue # The icon used by both items and sections
â â âââ ItemOpenMethodIcon.vue # A small icon, visible on hover, indicating opening method
+â â âââ ItemContextMenu.vue # The right-click menu, for showing Item opening methods and info
+â â âââ SectionContextMenu.vue # The right-click menu, for showing Section edit/ open options
â â â°ââ StatusIndicator.vue # Traffic light dot, showing if app is online or down
â âââ Minimal View # Components used for the startpage / minimal alternative view
â â âââ MinimalHeading.vue # Title part of minimal view
@@ -250,7 +269,10 @@ Styleguides:
â â âââ SideBar.vue # The left sidebar for the workspace view
â â âââ SideBarItem.vue # App item for the sidebar view
â â âââ SideBarSection.vue # Collapsible collection of items within workspace sidebar
-â â â°ââ WebContent.vue # Workspace iframe view, displays content of current app
+â â âââ WebContent.vue # Workspace iframe view, displays content of current app
+â â â°ââ WidgetView.vue # Workspace container for displaying widgets in main content
+â âââ Widgets # Directory contains all custom widget components
+â â â°ââ .... # Too many to list, see widget docs instead
â â°ââ Settings # Components relating to the quick-settings, in the top-right
â âââ AuthButtons.vue # Logout button and other app info
â âââ ConfigLauncher.vue # Icon that when clicked will launch the Configuration component
@@ -266,6 +288,19 @@ Styleguides:
âââ registerServiceWorker.js # Registers and manages service workers, for PWA apps
âââ router.js # Defines all available application routes
âââ styles # Directory of all globally used common SCSS styles
+â âââ color-palette.scss # All color variable names and default values
+â âââ color-themes.scss # All variable values for built-in themes
+â âââ dimensions.scss # Dimensions and sizes as variables
+â âââ global-styles.scss # Basics and style resets used globally
+â âââ media-queries.scss # Screen sizes and media queries
+â âââ style-helpers.scss # SCSS functions used for modifying values
+â âââ typography.scss # Font and text styles used globally
+â â°ââ user-defined-themes.scss # Empty, put any custom styles or themes here
+âââ mixins # Reusable component bases, extended by other views / components
+â âââ ChartingMixin.js # Functions for rendering charts in widget components
+â âââ GlancesMixin.js # Functions for fetching system info from Glances for widgets
+â âââ HomeMixin.js # Functions for homepage, used by default, minimal and workspace views
+â â°ââ WidgetMixin.js # Functions for all widgets, like data fetching, updating and error handling
âââ utils # Directory of re-used helper functions
â âââ ArrowKeyNavigation.js # Functionality for arrow-key navigation
â âââ Auth.js # Handles all authentication related actions
@@ -285,6 +320,7 @@ Styleguides:
â âââ InitServiceWorker.js # Initializes and manages service worker, if enabled
â âââ Search.js # Helper functions for searching/ filtering items in all views
â âââ JsonToYaml.js # Function that parses and converts raw JSON into valid YAML
+â âââ KeycloakAuth.js # Singleton class to manage Keycloak authentication
â âââ languages.js # Handles fetching, switching and validating languages
â â°ââ ThemeHelper.js # Function that handles the fetching and setting of user themes
â°ââ views # Directory of available pages, corresponding to available routes
diff --git a/docs/development-guides.md b/docs/development-guides.md
index 240c310f..2b6e7fc9 100644
--- a/docs/development-guides.md
+++ b/docs/development-guides.md
@@ -1,221 +1,432 @@
-# Development Guides
-
-A series of short tutorials, to guide you through the most common development tasks.
-
-Sections:
-- [Creating a new theme](#creating-a-new-theme)
-- [Writing Translations](#writing-translations)
-- [Adding a new option in the config file](#adding-a-new-option-in-the-config-file)
-- [Updating Dependencies](#updating-dependencies)
-
-## Creating a new theme
-
-Adding a new theme is really easy. There's two things you need to do: Pass the theme name to Dashy, so that it can be added to the theme selector dropdown menu, and then write some styles!
-
-##### 1. Add Theme Name
-Choose a snappy name for you're theme, and add it to the `builtInThemes` array inside [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js#L27).
-
-##### 2. Write some Styles!
-Put your theme's styles inside [`color-themes.scss`](https://github.com/Lissy93/dashy/blob/master/src/styles/color-themes.scss).
-Create a new block, and make sure that `data-theme` matches the theme name you chose above. For example:
-
-```css
-html[data-theme='tiger'] {
- --primary: #f58233;
- --background: #0b1021;
-}
-```
-
-Then you can go ahead and write you're own custom CSS. Although all CSS is supported here, the best way to define you're theme is by setting the CSS variables. You can find a [list of all CSS variables, here](https://github.com/Lissy93/dashy/blob/master/docs/theming#css-variables).
-
-For a full guide on styling, see [Theming Docs](./theming).
-
-Note that if you're theme is just for yourself, and you're not submitting a PR, then you can instead just pass it under `appConfig.cssThemes` inside your config file. And then put your theme in your own stylesheet, and pass it into the Docker container - [see how](https://github.com/Lissy93/dashy/blob/master/docs/theming#adding-your-own-theme).
-
-## Writing Translations
-
-For full docs about Dashy's multi-language support, see [Multi-Language Support](./multi-language-support)
-
-Dashy is using [vue-i18n](https://vue-i18n.intlify.dev/guide/) to manage multi-language support.
-
-Adding a new language is pretty straightforward, with just three steps:
-
-##### 1. Create a new Language File
-Create a new JSON file in `./src/assets/locales` name is a 2-digit [ISO-639 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for your language, E.g. for German `de.json`, French `fr.json` or Spanish `es.json` - You can find a list of all ISO codes at [iso.org](https://www.iso.org/obp/ui).
-
-##### 2. Translate!
-Using [`en.json`](https://github.com/Lissy93/dashy/tree/master/src/assets/locales/en.json) as an example, translate the JSON values to your language, while leaving the keys as they are. It's fine to leave out certain items, as if they're missing they will fall-back to English. If you see any attribute which include curly braces (`{xxx}`), then leave the inner value of these braces as is, as this is for variables.
-
-```json
-{
- "theme-maker": {
- "export-button": "Benutzerdefinierte Variablen exportieren",
- "reset-button": "Stile zurÃŧcksetzen fÃŧr",
- "show-all-button": "Alle Variablen anzeigen",
- "save-button": "Speichern",
- "cancel-button": "Abbrechen",
- "saved-toast": "{theme} Erfolgreich aktualisiert",
- "reset-toast": "Benutzerdefinierte Farben fÃŧr {theme} entfernt"
- },
-}
-```
-
-##### 3. Add your file to the app
-
-In [`./src/utils/languages.js`](https://github.com/Lissy93/dashy/tree/master/src/utils/languages.js), you need to do 2 small things:
-
-First import your new translation file, do this at the top of the page.
-E.g. `import de from '@/assets/locales/de.json';`
-
-Second, add it to the array of languages, e.g:
-```javascript
-export const languages = [
- {
- name: 'English',
- code: 'en',
- locale: en,
- flag: 'đŦđ§',
- },
- {
- name: 'German', // The name of your language
- code: 'de', // The ISO code of your language
- locale: de, // The name of the file you imported (no quotes)
- flag: 'đŠđĒ', // An optional flag emoji
- },
-];
-```
-You can also add your new language to the readme, under the [Language Switching](https://github.com/Lissy93/dashy#language-switching-) section, and optionally include your name/ username if you'd like to be credited for your work. Done!
-
-If you are not comfortable with making pull requests, or do not want to modify the code, then feel free to instead send the translated file to me, and I can add it into the application. I will be sure to credit you appropriately.
-
-# Adding a new option in the config file
-
-This section is for, if you're adding a new component or setting, that requires an additional item to be added to the users config file.
-
-All of the users config is specified in `./public/conf.yml` - see [Configuring Docs](./configuring) for info.
-Before adding a new option in the config file, first ensure that there is nothing similar available, that is is definitely necessary, it will not conflict with any other options and most importantly that it will not cause any breaking changes. Ensure that you choose an appropriate and relevant section to place it under.
-
-Next decide the most appropriate place for your attribute:
-- Application settings should be located under `appConfig`
-- Page info (such as text and metadata) should be under `pageInfo`
-- Data relating to specific sections should be under `section[n].displayData`
-- And for setting applied to specific items, it should be under `item[n]`
-
-In order for the user to be able to add your new attribute using the Config Editor, and for the build validation to pass, your attribute must be included within the [ConfigSchema](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigSchema.js). You can read about how to do this on the [ajv docs](https://ajv.js.org/json-schema.html). Give your property a type and a description, as well as any other optional fields that you feel are relevant. For example:
-
-```json
-"fontAwesomeKey": {
- "type": "string",
- "pattern": "^[a-z0-9]{10}$",
- "description": "API key for font-awesome",
- "example": "0821c65656"
-}
-```
-or
-```json
-"iconSize": {
- "enum": [ "small", "medium", "large" ],
- "default": "medium",
- "description": "The size of each link item / icon"
-}
-```
-
-Next, if you're property should have a default value, then add it to [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js). This ensures that nothing will break if the user does not use your property, and having all defaults together keeps things organised and easy to manage.
-
-If your property needs additional logic for fetching, setting or processing, then you can add a helper function within [`ConfigHelpers.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigHelpers.js).
-
-Finally, add your new property to the [`configuring`](./configuring) API docs. Put it under the relevant section, and be sure to include field name, data type, a description and mention that it is optional. If your new feature needs more explaining, then you can also document it under the relevant section elsewhere in the documentation.
-
-Checklist:
-- [ ] Ensure the new attribute is actually necessary, and nothing similar already exists
-- [ ] Update the [Schema](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigSchema.js) with the parameters for your new option
-- [ ] Set a default value (if required) within [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js)
-- [ ] Document the new value in [`configuring`](./configuring)
-- [ ] Test that the reading of the new attribute is properly handled, and will not cause any errors when it is missing or populated with an unexpected value
-
----
-
-## Updating Dependencies
-
-Running `yarn upgrade` will updated all dependencies based on the ranges specified in the `package.json`. The `yarn.lock` file will be updated, as will the contents of `./node_modules`, for more info, see the [yarn upgrade documentation](https://classic.yarnpkg.com/en/docs/cli/upgrade/). It is important to thoroughly test after any big dependency updates.
-
----
-
-## Developing Netlify Cloud Functions
-
-When Dashy is deployed to Netlify, it is effectively running as a static app, and therefore the server-side code for the Node.js endpoints is not available. However Netlify now supports serverless cloud lambda functions, which can be used to replace most functionality.
-
-#### 1. Run Netlify Dev Server
-
-First off, install the Netlify CLI: `npm install netlify-cli -g`
-Then, from within the root of Dashy's directory, start the server, by running: `netlify dev`
-
-#### 2. Create a lambda function
-
-This should be saved it in the [`./services/serverless-functions`](https://github.com/Lissy93/dashy/tree/master/services/serverless-functions) directory
-
-```javascript
-exports.handler = async () => ({
- statusCode: 200,
- body: 'Return some data here...',
-});
-```
-
-#### 3. Redirect the Node endpoint to the function
-
-In the [`netlify.toml`](https://github.com/Lissy93/dashy/blob/FEATURE/serverless-functions/netlify.toml) file, add a 301 redirect, with the path to the original Node.js endpoint, and the name of your cloud function
-
-```toml
-[[redirects]]
- from = "/status-check"
- to = "/.netlify/functions/cloud-status-check"
- status = 301
- force = true
-```
-
----
-
-## Hiding Page Furniture on Certain Routes
-For some pages (such as the login page, the minimal start page, etc) the basic page furniture, (like header, footer, nav, etc) is not needed. This section explains how you can hide furniture on a new view (step 1), or add a component that should be hidden on certain views (step 2).
-
-##### 1. Add the route name to the should hide array
-
-In [`./src/utils/defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js), there's an array called `hideFurnitureOn`. Append the name of the route (the same as it appears in [`router.js`](https://github.com/Lissy93/dashy/blob/master/src/router.js)) here.
-
-##### 2. Add the conditional to the structural component to hide
-
-First, import the helper function:
-```javascript
-import { shouldBeVisible } from '@/utils/MiscHelpers';
-```
-
-Then you can create a computed value, that calls this function, passing in the route name:
-```javascript
-export default {
- ...
- computed: {
- ...
- isVisible() {
- return shouldBeVisible(this.$route.name);
- },
- },
-};
-```
-
-Finally, in the markup of your component, just add a `v-if` statement, referencing your computed value
-```vue
-
-```
-
----
-
-## Adding / Using Environmental Variables
-All environmental variables are optional. Currently there are not many environmental variables used, as most of the user preferences are stored under `appConfig` in the `conf.yml` file.
-
-You can set variables either in your environment, or using the [`.env`](https://github.com/Lissy93/dashy/blob/master/.env) file.
-
-Any environmental variables used by the frontend are preceded with `VUE_APP_`. Vue will merge the contents of your `.env` file into the app in a similar way to the ['dotenv'](https://github.com/motdotla/dotenv) package, where any variables that you set on your system will always take preference over the contents of any `.env` file.
-
-If add any new variables, ensure that there is always a fallback (define it in [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js)), so as to not cause breaking changes. Don't commit the contents of your `.env` file to git, but instead take a few moments to document what you've added under the appropriate section. Try and follow the concepts outlined in the [12 factor app](https://12factor.net/config).
+# Development Guides
+
+A series of short tutorials, to guide you through the most common development tasks.
+
+Sections:
+- [Creating a new theme](#creating-a-new-theme)
+- [Writing Translations](#writing-translations)
+- [Adding a new option in the config file](#adding-a-new-option-in-the-config-file)
+- [Updating Dependencies](#updating-dependencies)
+- [Writing Netlify Cloud Functions](#developing-netlify-cloud-functions)
+- [Hiding Page Furniture](#hiding-page-furniture-on-certain-routes)
+- [Adding / Using Environmental Variables](#adding--using-environmental-variables)
+- [Building a Widget](#building-a-widget)
+
+## Creating a new theme
+
+Adding a new theme is really easy. There's two things you need to do: Pass the theme name to Dashy, so that it can be added to the theme selector dropdown menu, and then write some styles!
+
+##### 1. Add Theme Name
+Choose a snappy name for you're theme, and add it to the `builtInThemes` array inside [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js#L27).
+
+##### 2. Write some Styles!
+Put your theme's styles inside [`color-themes.scss`](https://github.com/Lissy93/dashy/blob/master/src/styles/color-themes.scss).
+Create a new block, and make sure that `data-theme` matches the theme name you chose above. For example:
+
+```css
+html[data-theme='tiger'] {
+ --primary: #f58233;
+ --background: #0b1021;
+}
+```
+
+Then you can go ahead and write you're own custom CSS. Although all CSS is supported here, the best way to define you're theme is by setting the CSS variables. You can find a [list of all CSS variables, here](https://github.com/Lissy93/dashy/blob/master/docs/theming.md#css-variables).
+
+For a full guide on styling, see [Theming Docs](./theming).
+
+Note that if you're theme is just for yourself, and you're not submitting a PR, then you can instead just pass it under `appConfig.cssThemes` inside your config file. And then put your theme in your own stylesheet, and pass it into the Docker container - [see how](https://github.com/Lissy93/dashy/blob/master/docs/theming.md#adding-your-own-theme).
+
+## Writing Translations
+
+For full docs about Dashy's multi-language support, see [Multi-Language Support](./multi-language-support)
+
+Dashy is using [vue-i18n](https://vue-i18n.intlify.dev/guide/) to manage multi-language support.
+
+Adding a new language is pretty straightforward, with just three steps:
+
+##### 1. Create a new Language File
+Create a new JSON file in `./src/assets/locales` name is a 2-digit [ISO-639 code](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) for your language, E.g. for German `de.json`, French `fr.json` or Spanish `es.json` - You can find a list of all ISO codes at [iso.org](https://www.iso.org/obp/ui).
+
+##### 2. Translate!
+Using [`en.json`](https://github.com/Lissy93/dashy/tree/master/src/assets/locales/en.json) as an example, translate the JSON values to your language, while leaving the keys as they are. It's fine to leave out certain items, as if they're missing they will fall-back to English. If you see any attribute which include curly braces (`{xxx}`), then leave the inner value of these braces as is, as this is for variables.
+
+```json
+{
+ "theme-maker": {
+ "export-button": "Benutzerdefinierte Variablen exportieren",
+ "reset-button": "Stile zurÃŧcksetzen fÃŧr",
+ "show-all-button": "Alle Variablen anzeigen",
+ "save-button": "Speichern",
+ "cancel-button": "Abbrechen",
+ "saved-toast": "{theme} Erfolgreich aktualisiert",
+ "reset-toast": "Benutzerdefinierte Farben fÃŧr {theme} entfernt"
+ },
+}
+```
+
+##### 3. Add your file to the app
+
+In [`./src/utils/languages.js`](https://github.com/Lissy93/dashy/tree/master/src/utils/languages.js), you need to do 2 small things:
+
+First import your new translation file, do this at the top of the page.
+E.g. `import de from '@/assets/locales/de.json';`
+
+Second, add it to the array of languages, e.g:
+```javascript
+export const languages = [
+ {
+ name: 'English',
+ code: 'en',
+ locale: en,
+ flag: 'đŦđ§',
+ },
+ {
+ name: 'German', // The name of your language
+ code: 'de', // The ISO code of your language
+ locale: de, // The name of the file you imported (no quotes)
+ flag: 'đŠđĒ', // An optional flag emoji
+ },
+];
+```
+You can also add your new language to the readme, under the [Language Switching](https://github.com/Lissy93/dashy#language-switching-) section, and optionally include your name/ username if you'd like to be credited for your work. Done!
+
+If you are not comfortable with making pull requests, or do not want to modify the code, then feel free to instead send the translated file to me, and I can add it into the application. I will be sure to credit you appropriately.
+
+# Adding a new option in the config file
+
+This section is for, if you're adding a new component or setting, that requires an additional item to be added to the users config file.
+
+All of the users config is specified in `./public/conf.yml` - see [Configuring Docs](./configuring) for info.
+Before adding a new option in the config file, first ensure that there is nothing similar available, that is is definitely necessary, it will not conflict with any other options and most importantly that it will not cause any breaking changes. Ensure that you choose an appropriate and relevant section to place it under.
+
+Next decide the most appropriate place for your attribute:
+- Application settings should be located under `appConfig`
+- Page info (such as text and metadata) should be under `pageInfo`
+- Data relating to specific sections should be under `section[n].displayData`
+- And for setting applied to specific items, it should be under `item[n]`
+
+In order for the user to be able to add your new attribute using the Config Editor, and for the build validation to pass, your attribute must be included within the [ConfigSchema](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigSchema.js). You can read about how to do this on the [ajv docs](https://ajv.js.org/json-schema.html). Give your property a type and a description, as well as any other optional fields that you feel are relevant. For example:
+
+```json
+"fontAwesomeKey": {
+ "type": "string",
+ "pattern": "^[a-z0-9]{10}$",
+ "description": "API key for font-awesome",
+ "example": "0821c65656"
+}
+```
+or
+```json
+"iconSize": {
+ "enum": [ "small", "medium", "large" ],
+ "default": "medium",
+ "description": "The size of each link item / icon"
+}
+```
+
+Next, if you're property should have a default value, then add it to [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js). This ensures that nothing will break if the user does not use your property, and having all defaults together keeps things organised and easy to manage.
+
+If your property needs additional logic for fetching, setting or processing, then you can add a helper function within [`ConfigHelpers.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigHelpers.js).
+
+Finally, add your new property to the [`configuring.md`](./configuring) API docs. Put it under the relevant section, and be sure to include field name, data type, a description and mention that it is optional. If your new feature needs more explaining, then you can also document it under the relevant section elsewhere in the documentation.
+
+Checklist:
+- [ ] Ensure the new attribute is actually necessary, and nothing similar already exists
+- [ ] Update the [Schema](https://github.com/Lissy93/dashy/blob/master/src/utils/ConfigSchema.js) with the parameters for your new option
+- [ ] Set a default value (if required) within [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js)
+- [ ] Document the new value in [`configuring.md`](./configuring)
+- [ ] Test that the reading of the new attribute is properly handled, and will not cause any errors when it is missing or populated with an unexpected value
+
+---
+
+## Updating Dependencies
+
+Running `yarn upgrade` will updated all dependencies based on the ranges specified in the `package.json`. The `yarn.lock` file will be updated, as will the contents of `./node_modules`, for more info, see the [yarn upgrade documentation](https://classic.yarnpkg.com/en/docs/cli/upgrade/). It is important to thoroughly test after any big dependency updates.
+
+---
+
+## Developing Netlify Cloud Functions
+
+When Dashy is deployed to Netlify, it is effectively running as a static app, and therefore the server-side code for the Node.js endpoints is not available. However Netlify now supports serverless cloud lambda functions, which can be used to replace most functionality.
+
+#### 1. Run Netlify Dev Server
+
+First off, install the Netlify CLI: `npm install netlify-cli -g`
+Then, from within the root of Dashy's directory, start the server, by running: `netlify dev`
+
+#### 2. Create a lambda function
+
+This should be saved it in the [`./services/serverless-functions`](https://github.com/Lissy93/dashy/tree/master/services/serverless-functions) directory
+
+```javascript
+exports.handler = async () => ({
+ statusCode: 200,
+ body: 'Return some data here...',
+});
+```
+
+#### 3. Redirect the Node endpoint to the function
+
+In the [`netlify.toml`](https://github.com/Lissy93/dashy/blob/FEATURE/serverless-functions/netlify.toml) file, add a 301 redirect, with the path to the original Node.js endpoint, and the name of your cloud function
+
+```toml
+[[redirects]]
+ from = "/status-check"
+ to = "/.netlify/functions/cloud-status-check"
+ status = 301
+ force = true
+```
+
+---
+
+## Hiding Page Furniture on Certain Routes
+For some pages (such as the login page, the minimal start page, etc) the basic page furniture, (like header, footer, nav, etc) is not needed. This section explains how you can hide furniture on a new view (step 1), or add a component that should be hidden on certain views (step 2).
+
+##### 1. Add the route name to the should hide array
+
+In [`./src/utils/defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js), there's an array called `hideFurnitureOn`. Append the name of the route (the same as it appears in [`router.js`](https://github.com/Lissy93/dashy/blob/master/src/router.js)) here.
+
+##### 2. Add the conditional to the structural component to hide
+
+First, import the helper function:
+```javascript
+import { shouldBeVisible } from '@/utils/SectionHelpers';
+```
+
+Then you can create a computed value, that calls this function, passing in the route name:
+```javascript
+export default {
+ ...
+ computed: {
+ ...
+ isVisible() {
+ return shouldBeVisible(this.$route.name);
+ },
+ },
+};
+```
+
+Finally, in the markup of your component, just add a `v-if` statement, referencing your computed value
+```vue
+
+```
+
+---
+
+## Adding / Using Environmental Variables
+All environmental variables are optional. Currently there are not many environmental variables used, as most of the user preferences are stored under `appConfig` in the `conf.yml` file.
+
+You can set variables either in your environment, or using the [`.env`](https://github.com/Lissy93/dashy/blob/master/.env) file.
+
+Any environmental variables used by the frontend are preceded with `VUE_APP_`. Vue will merge the contents of your `.env` file into the app in a similar way to the ['dotenv'](https://github.com/motdotla/dotenv) package, where any variables that you set on your system will always take preference over the contents of any `.env` file.
+
+If add any new variables, ensure that there is always a fallback (define it in [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js)), so as to not cause breaking changes. Don't commit the contents of your `.env` file to git, but instead take a few moments to document what you've added under the appropriate section. Try and follow the concepts outlined in the [12 factor app](https://12factor.net/config).
+
+---
+
+## Building a Widget
+
+### Step 0 - Prerequisites
+
+If this is your first time working on Dashy, then the [Developing Docs](https://github.com/Lissy93/dashy/blob/master/docs/developing.md) instructions for project setup and running. In short, you just need to clone the project, cd into it, install dependencies (`yarn`) and then start the development server (`yarn dev`).
+
+To build a widget, you'll also need some basic knowledge of Vue.js. The [official Vue docs](https://vuejs.org/v2/guide/) provides a good starting point, as does [this guide](https://www.taniarascia.com/getting-started-with-vue/) by Tania Rascia
+
+If you just want to jump straight in, then [here](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e) is a complete implementation of a new example widget, or take a look at the [`XkcdComic.vue`](https://github.com/Lissy93/dashy/blob/master/src/components/Widgets/XkcdComic.vue) widget, which is pretty simple.
+
+
+### Step 1 - Create Widget
+
+Firstly, create a new `.vue` file under [`./src/components/Widgets`](https://github.com/Lissy93/dashy/tree/master/src/components/Widgets).
+
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+All widgets extend from the [Widget](https://github.com/Lissy93/dashy/blob/master/src/mixins/WidgetMixin.js) mixin. This provides some basic functionality that is shared by all widgets. The mixin includes the following `options`, `startLoading()`, `finishLoading()`, `error()` and `update()`.
+- **Getting user options: `options`**
+ - Any user-specific config can be accessed with `this.options.something` (where something is the data key your accessing)
+- **Loading state: `startLoading()` and `finishLoading()`**
+ - You can show the loader with `this.startLoading()`, then when your data request completes, hide it again with `this.finishLoading()`
+- **Error handling: `error()`**
+ - If something goes wrong (such as API error, or missing user parameters), then call `this.error()` to show message to user
+- **Updating data: `update()`**
+ - When the user clicks the update button, or if continuous updates are enabled, then the `update()` method within your widget will be called
+
+### Step 2 - Adding Functionality
+
+**Accessing User Options**
+
+If your widget is going to accept any parameters from the user, then we can access these with `this.options.[parmName]`. It's best to put these as computed properties, which will enable us to check it exists, is valid, and if needed format it. For example, if we have an optional property called `count` (to determine number of results), we can do the following, and then reference it within our component with `this.count`
+
+```javascript
+computed: {
+ count() {
+ if (!this.options.count) {
+ return 5;
+ }
+ return this.options.count;
+ },
+ ...
+},
+```
+
+**Adding an API Endpoint**
+
+If your widget makes a data request, then add the URL for the API under point to the `widgetApiEndpoints` array in [`defaults.js`](https://github.com/Lissy93/dashy/blob/master/src/utils/defaults.js#L207)
+
+```javascript
+widgetApiEndpoints: {
+ ...
+ exampleEndpoint: 'https://hub.dummyapis.com/ImagesList',
+},
+```
+
+Then in your widget file:
+
+```javascript
+import { widgetApiEndpoints } from '@/utils/defaults';
+```
+
+For GET requests, you may need to add some parameters onto the end of the URL. We can use another computed property for this, for example:
+
+```javascript
+endpoint() {
+ return `${widgetApiEndpoints.exampleEndpoint}?count=${this.count}`;
+},
+```
+
+**Making an API Request**
+
+Axios is used for making data requests, so import it into your component: `import axios from 'axios';`
+
+Under the `methods` block, we'll create a function called `fetchData`, here we can use Axios to make a call to our endpoint.
+
+```javascript
+fetchData() {
+ this.makeRequest(this.endpoint, this.headers).then(this.processData);
+},
+```
+
+There are three things happening here:
+- If the response completes successfully, we'll pass the results to another function that will handle them
+- If there's an error, then we call `this.error()`, which will show a message to the user
+- Whatever the result, once the request has completed, we call `this.finishLoading()`, which will hide the loader
+
+**Processing Response**
+
+In the above example, we call the `processData()` method with the result from the API, so we need to create that under the `methods` section. How you handle this data will vary depending on what's returned by the API, and what you want to render to the user. But however you do it, you will likely need to create a data variable to store the response, so that it can be easily displayed in the HTML.
+
+```javascript
+data() {
+ return {
+ myResults: null,
+ };
+},
+```
+
+And then, inside your `processData()` method, you can set the value of this, with:
+
+```javascript
+`this.myResults = 'whatever'`
+```
+
+**Rendering Response**
+
+Now that the results are in the correct format, and stored as data variables, we can use them within the `` to render results to the user. Again, how you do this will depend on the structure of your data, and what you want to display, but at it's simplest, it might look something like this:
+
+```vue
+{{ myResults }}
+```
+
+**Styling**
+
+Styles can be written your your widget within the `
+```
+
+For examples of finished widget components, see the [Widgets](https://github.com/Lissy93/dashy/tree/master/src/components/Widgets) directory. Specifically, the [`XkcdComic.vue`](https://github.com/Lissy93/dashy/blob/master/src/components/Widgets/XkcdComic.vue) widget is quite minimal, so would make a good example, as will [this example implementation](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e).
+
+
+### Step 3 - Register
+
+Next, import and register your new widget, in [`WidgetBase.vue`](https://github.com/Lissy93/dashy/blob/master/src/components/Widgets/WidgetBase.vue). In this file, you'll need to add the following:
+
+Import your widget file
+```javascript
+import ExampleWidget from '@/components/Widgets/ExampleWidget.vue';
+```
+
+Then register the component
+```javascript
+components: {
+ ...
+ ExampleWidget,
+},
+```
+
+Finally, add the markup to render it. The only attribute you need to change here is, setting `widgetType === 'example'` to your widget's name.
+```vue
+
+```
+
+### Step 4 - Docs
+
+Finally, add some documentation for your widget in the [Widget Docs](https://github.com/Lissy93/dashy/blob/master/docs/widgets.md), so that others know hoe to use it. Include the following information: Title, short description, screenshot, config options and some example YAML.
+
+
+**Summary**: For a complete example of everything discussed here, see: [`3da76ce`](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e)
diff --git a/docs/icons.md b/docs/icons.md
index ac4adeaf..ff98f799 100644
--- a/docs/icons.md
+++ b/docs/icons.md
@@ -1,190 +1,191 @@
-# Icons
-
-Both sections and items can have an icon, which is specified using the `icon` attribute. Using icons improves the aesthetics of your UI and makes the app more intuitive to use. Dashy supports multiple different icon providers, usage instructions for which are explained here.
-
-- [Auto-Fetched Favicons](#favicons)
-- [Font Awesome Icons](#font-awesome)
-- [Simple Icons](#simple-icons)
-- [Generative Icons](#generative-icons)
-- [Emoji Icons](#emoji-icons)
-- [Home-Lab Icons](#home-lab-icons)
-- [Material Icons](#material-design-icons)
-- [Icons by URL](#icons-by-url)
-- [Local Icons](#local-icons)
-- [No Icon](#no-icon)
-
-
-
-
-
----
-
-## Favicons
-Dashy can auto-fetch an icon for a given service, using it's favicon. Just set `icon: favicon` to use this feature.
-
-
-
-
-
-Since different websites host their favicons at different paths, for the best results Dashy can use an API to resolve a websites icon.
-
-The default favicon API is [allesedv.com](https://favicon.allesedv.com/), but you can change this under `appConfig.faviconApi`. If you'd prefer not to use an API, just set this value to `local`. You can also use different APIs for individual items, by setting `icon: favicon-[api]`, e.g. `favicon-clearbit`.
-
-The following favicon APIs are supported:
-- `allesedv` - [allesedv.com](https://favicon.allesedv.com/) is a highly efficient IPv6-enabled service
-- `clearbit` - [Clearbit](https://clearbit.com/logo) returns high-quality square logos from mainstream websites
-- `faviconkit` - [faviconkit.com](https://faviconkit.com/) good quality icons and most sites supported (Note: down as of Nov '21)
-- `besticon` - [BestIcon](https://github.com/mat/besticon) fetches websites icons from manifest
-- `mcapi` - [MC-API](https://eu.mc-api.net/) fetches default website favicon, originally a Minecraft util
-- `duckduckgo` - Returns decent quality website icons, from DuckDuckGo search
-- `google` - Official Google favicon API service, good support for all sites, but poor quality
-- `yandex` - Lower quality icons, but useful in some regions where other services are blocked
-- `local` - Set to local to fetch the default icon at /favicon.ico instead of using an API
-
-If for a given service none of the APIs work in your situation, and nor does local, then the best option is to find the path of the services logo or favicon, and set the icon to the URL of the raw image. For example, `icon: https://monitoring.local/faviconx128.png`- you can find this path using the browser dev tools.
-
----
-
-## Font Awesome
-You can use any [Font Awesome Icon](https://fontawesome.com/icons) simply by specifying it's identifier. This is in the format of `[category] [name]` and can be found on the page for that icon on the Font Awesome site. For example: `fas fa-rocket`, `fab fa-monero` or `fas fa-unicorn`.
-
-Font-Awesome has a wide variety of free icons, but you can also use their pro icons if you have a membership. To do so, you need to specify your license key under: `appConfig.fontAwesomeKey`. This is usually a 10-digit string, for example `13014ae648`.
-
-
-
-
-
----
-
-## Simple Icons
-[SimpleIcons.org](https://simpleicons.org/) is a collection of 2000+ high quality, free and open source brand and logo SVG icons. Usage of which is very similar to font-awesome icons. First find the glyph you want to use on the [website](https://simpleicons.org/), then just set your icon the the simple icon slug, prefixed with `si-`.
-
-
-
-
-
-For example:
-```yaml
-sections:
-- name: Simple Icons Example
- items:
- - title: Portainer
- icon: si-portainer
- - title: FreeNAS
- icon: si-freenas
- - title: NextCloud
- icon: si-nextcloud
- - title: Home Assistant
- icon: si-homeassistant
-```
-
----
-
-## Generative Icons
-To uses a unique and programmatically generated icon for a given service just set `icon: generative`. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with [DiceBear](https://avatars.dicebear.com/) (or [Evatar](https://evatar.io/) for fallback), and use a hash of the services domain/ ip for entropy, so each domain will have a unique icon.
-
-
-
-
-
----
-
-## Emoji Icons
-You can use almost any emoji as an icon for items or sections. You can specify the emoji either by pasting it directly, using it's unicode ( e.g. `'U+1F680'`) or shortcode (e.g. `':rocket:'`). You can find these codes for any emoji using [Emojipedia](https://emojipedia.org/) (near the bottom of emoji each page), or for a quick reference to emoji shortcodes, check out [emojis.ninja](https://emojis.ninja/) by @nomanoff.
-
-
-
-
-
-For example, these will all render the same rocket (đ) emoji: `icon: ':rocket:'` or `icon: 'U+1F680'` or `icon: đ`
-
----
-
-## Home-Lab Icons
-
-The [dashboard-icons](https://github.com/WalkxCode/dashboard-icons) repo by [@WalkxCode](https://github.com/WalkxCode) provides a comprehensive collection of 360+ high-quality PNG icons for commonly self-hosted services. Dashy natively supports these icons, and you can use them just by specifying the icon name (without extension) preceded by `hl-`. See [here](https://github.com/WalkxCode/dashboard-icons/tree/master/png) for a full list of all available icons. Note that these are fetched and cached strait from GitHub, so if you require offline access, the [Local Icons](#local-icons) method may be a better option for you.
-
-For example:
-```yaml
-sections:
-- name: Home Lab Icons Example
- items:
- - title: AdGuard Home
- icon: hl-adguardhome
- - title: Long Horn
- icon: hl-longhorn
- - title: Nagios
- icon: hl-nagios
- - title: Whoogle Search
- icon: hl-whooglesearch
-```
-
-
-
-
-
-
----
-
-## Material Design Icons
-Dashy also supports 5000+ [material-design-icons](https://github.com/Templarian/MaterialDesign). To use these, first find the name/ slug for your icon [here](https://dev.materialdesignicons.com/icons), and then prefix is with `mdi-`.
-
-For example:
-```yaml
-sections:
-- name: Material Design Icons Example
- items:
- - title: Alien Icon
- icon: mdi-alien
- - title: Fire Icon
- icon: mdi-fire
- - title: Dino Icon
- icon: mdi-google-downasaur
-```
-
-
-
-
-
----
-
-## Icons by URL
-You can also set an icon by passing in a valid URL pointing to the icons location. For example `icon: https://i.ibb.co/710B3Yc/space-invader-x256.png`, this can be in .png, .jpg or .svg format, and hosted anywhere (local or remote) - so long as it's accessible from where you are hosting Dashy. The icon will be automatically scaled to fit, however loading in a lot of large icons may have a negative impact on performance, especially if you visit Dashy from new devices often.
-
----
-
-## Local Icons
-You may also want to store your icons locally, bundled within Dashy so that there is no reliance on outside services. This can be done by putting the icons within Dashy's `./public/item-icons/` directory. If you are using Docker, then the easiest option is to map a volume from your host system, for example: `-v /local/image/directory:/app/public/item-icons/`. To reference an icon stored locally, just specify it's name and extension. For example, if my icon was stored in `/app/public/item-icons/maltrail.png`, then I would just set `icon: maltrail.png`.
-
-You can also use sub-folders within the `item-icons` directory to keep things organized. You would then specify an icon with it's folder name slash image name. For example: `networking/monit.png`
-
----
-
-## No Icon
-If you don't wish for a given item or section to have an icon, just leave out the `icon` attribute.
-
----
-
-## Icon Collections and Resources
-
-The following websites provide good-quality, free icon sets. To use any of these icons, either copy the link to the raw icon (it should end in `.svg` or `.png`) and paste it as your `icon`, or download and save the icons in `/public/item-icons` / mapped Docker volume. Full credit to the authors, please see the licenses for each service for usage and copyright information.
-
-- [Icons for Self-Hosted Apps](https://thehomelab.wiki/books/helpful-tools-resources/page/icons-for-self-hosted-dashboards) - 350+ high-quality icons for commonly self-hosted services
-- [SVG Box](https://svgbox.net/iconsets/) - Cryptocurrency, social media apps and flag icons
-- [Simple Icons](https://simpleicons.org/) - Free SVG brand icons, with easy API access
-- [Material Design Icons](https://github.com/google/material-design-icons/) - Hundreds of Open source PNG + SVG icons by Google
-- [Icons8](https://icons8.com/icons) - Thousands of icons, all with free versions at 64x64
-- [Flat Icon](https://www.flaticon.com/) - Wide variety of icon sets, most of which are free to use
-- [SVG Repo](https://www.svgrepo.com/) - 300,000+ Vector Icons
-
-If you are a student, then you can get free access to premium icons on [Icon Scout](https://education.github.com/pack/redeem/iconscout-student) or [Icons8](https://icons8.com/github-students) using the [GitHub Student Pack](https://education.github.com/pack).
-
----
-
-## Notes
-
-If you are using icons from an external source, these will be fetched on initial page load automatically, if and when needed. But combining icons from multiple services may have a negative impact on performance.
-
-You can improve load speeds, by downloading your required icons, and serving them locally. Scaling icons to the minimum required dimensions (e.g. 128x128 or 64x64) will also greatly improve application load times.
-
-For icons from external sources, please see the Privacy Policies and Licenses for that provider.
+# Icons
+
+Both sections and items can have an icon, which is specified using the `icon` attribute. Using icons improves the aesthetics of your UI and makes the app more intuitive to use. Dashy supports multiple different icon providers, usage instructions for which are explained here.
+
+- [Auto-Fetched Favicons](#favicons)
+- [Font Awesome Icons](#font-awesome)
+- [Simple Icons](#simple-icons)
+- [Generative Icons](#generative-icons)
+- [Emoji Icons](#emoji-icons)
+- [Home-Lab Icons](#home-lab-icons)
+- [Material Icons](#material-design-icons)
+- [Icons by URL](#icons-by-url)
+- [Local Icons](#local-icons)
+- [No Icon](#no-icon)
+
+
+
+
+
+---
+
+## Favicons
+Dashy can auto-fetch an icon for a given service, using it's favicon. Just set `icon: favicon` to use this feature.
+
+
+
+
+
+Since different websites host their favicons at different paths, for the best results Dashy can use an API to resolve a websites icon.
+
+The default favicon API is [allesedv.com](https://favicon.allesedv.com/), but you can change this under `appConfig.faviconApi`. If you'd prefer not to use an API, just set this value to `local`. You can also use different APIs for individual items, by setting `icon: favicon-[api]`, e.g. `favicon-clearbit`.
+
+The following favicon APIs are supported:
+- `allesedv` - [allesedv.com](https://favicon.allesedv.com/) is a highly efficient IPv6-enabled service
+- `iconhorse` - [Icon.Horse](https://icon.horse/) returns quality icons for any site, with caching for speed and fallbacks for sites without an icon
+- `clearbit` - [Clearbit](https://clearbit.com/logo) returns high-quality square logos from mainstream websites
+- `faviconkit` - [faviconkit.com](https://faviconkit.com/) good quality icons and most sites supported (Note: down as of Nov '21)
+- `besticon` - [BestIcon](https://github.com/mat/besticon) fetches websites icons from manifest
+- `mcapi` - [MC-API](https://eu.mc-api.net/) fetches default website favicon, originally a Minecraft util
+- `duckduckgo` - Returns decent quality website icons, from DuckDuckGo search
+- `google` - Official Google favicon API service, good support for all sites, but poor quality
+- `yandex` - Lower quality icons, but useful in some regions where other services are blocked
+- `local` - Set to local to fetch the default icon at /favicon.ico instead of using an API
+
+If for a given service none of the APIs work in your situation, and nor does local, then the best option is to find the path of the services logo or favicon, and set the icon to the URL of the raw image. For example, `icon: https://monitoring.local/faviconx128.png`- you can find this path using the browser dev tools.
+
+---
+
+## Font Awesome
+You can use any [Font Awesome Icon](https://fontawesome.com/icons) simply by specifying it's identifier. This is in the format of `[category] [name]` and can be found on the page for that icon on the Font Awesome site. For example: `fas fa-rocket`, `fab fa-monero` or `fas fa-unicorn`.
+
+Font-Awesome has a wide variety of free icons, but you can also use their pro icons if you have a membership. To do so, you need to specify your license key under: `appConfig.fontAwesomeKey`. This is usually a 10-digit string, for example `13014ae648`.
+
+
+
+
+
+---
+
+## Simple Icons
+[SimpleIcons.org](https://simpleicons.org/) is a collection of 2000+ high quality, free and open source brand and logo SVG icons. Usage of which is very similar to font-awesome icons. First find the glyph you want to use on the [website](https://simpleicons.org/), then just set your icon the the simple icon slug, prefixed with `si-`.
+
+
+
+
+
+For example:
+```yaml
+sections:
+- name: Simple Icons Example
+ items:
+ - title: Portainer
+ icon: si-portainer
+ - title: FreeNAS
+ icon: si-freenas
+ - title: NextCloud
+ icon: si-nextcloud
+ - title: Home Assistant
+ icon: si-homeassistant
+```
+
+---
+
+## Generative Icons
+To uses a unique and programmatically generated icon for a given service just set `icon: generative`. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with [DiceBear](https://avatars.dicebear.com/) (or [Evatar](https://evatar.io/) for fallback), and use a hash of the services domain/ ip for entropy, so each domain will have a unique icon.
+
+
+
+
+
+---
+
+## Emoji Icons
+You can use almost any emoji as an icon for items or sections. You can specify the emoji either by pasting it directly, using it's unicode ( e.g. `'U+1F680'`) or shortcode (e.g. `':rocket:'`). You can find these codes for any emoji using [Emojipedia](https://emojipedia.org/) (near the bottom of emoji each page), or for a quick reference to emoji shortcodes, check out [emojis.ninja](https://emojis.ninja/) by @nomanoff.
+
+
+
+
+
+For example, these will all render the same rocket (đ) emoji: `icon: ':rocket:'` or `icon: 'U+1F680'` or `icon: đ`
+
+---
+
+## Home-Lab Icons
+
+The [dashboard-icons](https://github.com/WalkxCode/dashboard-icons) repo by [@WalkxCode](https://github.com/WalkxCode) provides a comprehensive collection of 360+ high-quality PNG icons for commonly self-hosted services. Dashy natively supports these icons, and you can use them just by specifying the icon name (without extension) preceded by `hl-`. See [here](https://github.com/WalkxCode/dashboard-icons/tree/master/png) for a full list of all available icons. Note that these are fetched and cached strait from GitHub, so if you require offline access, the [Local Icons](#local-icons) method may be a better option for you.
+
+For example:
+```yaml
+sections:
+- name: Home Lab Icons Example
+ items:
+ - title: AdGuard Home
+ icon: hl-adguardhome
+ - title: Long Horn
+ icon: hl-longhorn
+ - title: Nagios
+ icon: hl-nagios
+ - title: Whoogle Search
+ icon: hl-whooglesearch
+```
+
+
+
+
+
+
+---
+
+## Material Design Icons
+Dashy also supports 5000+ [material-design-icons](https://github.com/Templarian/MaterialDesign). To use these, first find the name/ slug for your icon [here](https://dev.materialdesignicons.com/icons), and then prefix is with `mdi-`.
+
+For example:
+```yaml
+sections:
+- name: Material Design Icons Example
+ items:
+ - title: Alien Icon
+ icon: mdi-alien
+ - title: Fire Icon
+ icon: mdi-fire
+ - title: Dino Icon
+ icon: mdi-google-downasaur
+```
+
+
+
+
+
+---
+
+## Icons by URL
+You can also set an icon by passing in a valid URL pointing to the icons location. For example `icon: https://i.ibb.co/710B3Yc/space-invader-x256.png`, this can be in .png, .jpg or .svg format, and hosted anywhere (local or remote) - so long as it's accessible from where you are hosting Dashy. The icon will be automatically scaled to fit, however loading in a lot of large icons may have a negative impact on performance, especially if you visit Dashy from new devices often.
+
+---
+
+## Local Icons
+You may also want to store your icons locally, bundled within Dashy so that there is no reliance on outside services. This can be done by putting the icons within Dashy's `./public/item-icons/` directory. If you are using Docker, then the easiest option is to map a volume from your host system, for example: `-v /local/image/directory:/app/public/item-icons/`. To reference an icon stored locally, just specify it's name and extension. For example, if my icon was stored in `/app/public/item-icons/maltrail.png`, then I would just set `icon: maltrail.png`.
+
+You can also use sub-folders within the `item-icons` directory to keep things organized. You would then specify an icon with it's folder name slash image name. For example: `networking/monit.png`
+
+---
+
+## No Icon
+If you don't wish for a given item or section to have an icon, just leave out the `icon` attribute.
+
+---
+
+## Icon Collections and Resources
+
+The following websites provide good-quality, free icon sets. To use any of these icons, either copy the link to the raw icon (it should end in `.svg` or `.png`) and paste it as your `icon`, or download and save the icons in `/public/item-icons` / mapped Docker volume. Full credit to the authors, please see the licenses for each service for usage and copyright information.
+
+- [Icons for Self-Hosted Apps](https://thehomelab.wiki/books/helpful-tools-resources/page/icons-for-self-hosted-dashboards) - 350+ high-quality icons for commonly self-hosted services
+- [SVG Box](https://svgbox.net/iconsets/) - Cryptocurrency, social media apps and flag icons
+- [Simple Icons](https://simpleicons.org/) - Free SVG brand icons, with easy API access
+- [Material Design Icons](https://github.com/google/material-design-icons/) - Hundreds of Open source PNG + SVG icons by Google
+- [Icons8](https://icons8.com/icons) - Thousands of icons, all with free versions at 64x64
+- [Flat Icon](https://www.flaticon.com/) - Wide variety of icon sets, most of which are free to use
+- [SVG Repo](https://www.svgrepo.com/) - 300,000+ Vector Icons
+
+If you are a student, then you can get free access to premium icons on [Icon Scout](https://education.github.com/pack/redeem/iconscout-student) or [Icons8](https://icons8.com/github-students) using the [GitHub Student Pack](https://education.github.com/pack).
+
+---
+
+## Notes
+
+If you are using icons from an external source, these will be fetched on initial page load automatically, if and when needed. But combining icons from multiple services may have a negative impact on performance.
+
+You can improve load speeds, by downloading your required icons, and serving them locally. Scaling icons to the minimum required dimensions (e.g. 128x128 or 64x64) will also greatly improve application load times.
+
+For icons from external sources, please see the Privacy Policies and Licenses for that provider.
diff --git a/docs/management.md b/docs/management.md
index 343e7655..03a7cbe7 100644
--- a/docs/management.md
+++ b/docs/management.md
@@ -1,707 +1,775 @@
-# Management
-
-_The following article explains aspects of app management, and is useful to know for when self-hosting. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom environments. It's like a top-20 list of need-to-know knowledge for self-hosting._
-
-## Contents
-- [Providing Assets](#providing-assets)
-- [Running Commands](#running-commands)
-- [Healthchecks](#healthchecks)
-- [Logs and Performance](#logs-and-performance)
-- [Auto-Starting at Boot](#auto-starting-at-system-boot)
-- [Updating](#updating)
-- [Backing Up](#backing-up)
-- [Scheduling](#scheduling)
-- [SSL Certificates](#ssl-certificates)
-- [Authentication](#authentication)
-- [Managing with Compose](#managing-containers-with-docker-compose)
-- [Environmental Variables](#passing-in-environmental-variables)
-- [Securing Containers](#container-security)
-- [Remote Access](#remote-access)
-- [Custom Domain](#custom-domain)
-- [Web Server Configuration](#web-server-configuration)
-- [Running a Modified App](#running-a-modified-version-of-the-app)
-- [Building your Own Container](#building-your-own-container)
-
----
-
-## Providing Assets
-Although not essential, you will most likely want to provide several assets to your running app.
-
-This is easy to do using [Docker Volumes](https://docs.docker.com/storage/volumes/), which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the `--volume` or `-v` flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (`:`), and must be in the correct order. For example: `-v ~/alicia/my-local-conf.yml:/app/public/conf.yml`
-
-In Dashy, commonly configured resources include:
-- `./public/conf.yml` - Your main application config file
-- `./public/item-icons` - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN
-- Also within `./public` you'll find standard website assets, including `favicon.ico`, `manifest.json`, `robots.txt`, etc. There's no need to pass these in, but you can do so if you wish
-- `/src/styles/user-defined-themes.scss` - A stylesheet for applying custom CSS to your app. You can also write your own themes here.
-
-**[âŦī¸ Back to Top](#)**
-
----
-## Running Commands
-
- If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with `docker exec -it [container-id]`, where container ID can be found by running `docker ps`. For example `docker exec -it 26c156c467b4 yarn build`. You can also enter the container, with `docker exec -it [container-id] /bin/ash`, and navigate around it with normal Linux commands.
-
- Dashy has several commands that can be used for various tasks, you can find a list of these either in the [Developing Docs](/docs/developing#project-commands), or by looking at the [`package.json`](https://github.com/Lissy93/dashy/blob/master/package.json#L5). These can be used by running `yarn [command-name]`.
-
-**[âŦī¸ Back to Top](#)**
-
----
-## Healthchecks
-
-Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the `--health-interval` option. You can check the current container health with: `docker inspect --format "{{json .State.Health }}" [container-id]`, and a summary of health status will show up under `docker ps`. You can also manually request the current application status by running `docker exec -it [container-id] yarn health-check`. You can disable healthchecks altogether by adding the `--no-healthcheck` flag to your Docker run command.
-
-To restart unhealthy containers automatically, check out [Autoheal](https://hub.docker.com/r/willfarrell/autoheal/). This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's `--exit-on-unhealthy` that was proposed, but [not merged](https://github.com/moby/moby/pull/22719)). There's also [Deunhealth](https://github.com/qdm12/deunhealth), which is super light-weight, and doesn't require network access.
-
-```
-docker run -d \
- --name autoheal \
- --restart=always \
- -e AUTOHEAL_CONTAINER_LABEL=all \
- -v /var/run/docker.sock:/var/run/docker.sock \
- willfarrell/autoheal
-```
-
-**[âŦī¸ Back to Top](#)**
-
----
-## Logs and Performance
-
-#### Container Logs
-You can view logs for a given Docker container with `docker logs [container-id]`, add the `--follow` flag to stream the logs. For more info, see the [Logging Documentation](https://docs.docker.com/config/containers/logging/). There's also [Dozzle](https://dozzle.dev/), a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app.
-
-#### Container Performance
-You can check the resource usage for your running Docker containers with `docker stats` or `docker stats [container-id]`. For more info, see the [Stats Documentation](https://docs.docker.com/engine/reference/commandline/stats/). There's also [cAdvisor](https://github.com/google/cadvisor), a useful web app for viewing and analyzing resource usage and performance of all your running containers.
-
-#### Management Apps
-You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example [Portainer](https://github.com/portainer/portainer) an all-in-one open source management web UI for Docker and Kubernetes, or [LazyDocker](https://github.com/jesseduffield/lazydocker) a terminal UI for Docker container management and monitoring.
-
-#### Advanced Logging and Monitoring
-Docker supports using [Prometheus](https://prometheus.io/) to collect logs, which can then be visualized using a platform like [Grafana](https://grafana.com/). For more info, see [this guide](https://docs.docker.com/config/daemon/prometheus/). If you need to route your logs to a remote syslog, then consider using [logspout](https://github.com/gliderlabs/logspout). For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as [Sematext](https://sematext.com/blog/docker-container-monitoring-with-sematext/) with [Logagent](https://github.com/sematext/logagent-js).
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Auto-Starting at System Boot
-
-You can use Docker's [restart policies](https://docs.docker.com/engine/reference/run/#restart-policies---restart) to instruct the container to start after a system reboot, or restart after a crash. Just add the `--restart=always` flag to your Docker compose script or Docker run command. For more information, see the docs on [Starting Containers Automatically](https://docs.docker.com/config/containers/start-containers-automatically/).
-
-For Podman, you can use `systemd` to create a service that launches your container, [the docs](https://podman.io/blogs/2018/09/13/systemd.html) explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction.
-
-To restart the container after something within it has crashed, consider using [`docker-autoheal`](https://github.com/willfarrell/docker-autoheal) by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the [Healthchecks](#healthchecks) section above.
-
-**[âŦī¸ Back to Top](#)**
-
----
-## Updating
-
-Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again.
-
-### Updating Docker Container
-1. Pull latest image: `docker pull lissy93/dashy:latest`
-2. Kill off existing container
- - Find container ID: `docker ps`
- - Stop container: `docker stop [container_id]`
- - Remove container: `docker rm [container_id]`
-3. Spin up new container: `docker run [params] lissy93/dashy`
-
-### Automatic Docker Updates
-
-You can automate the above process using [Watchtower](https://github.com/containrrr/watchtower).
-Watchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially.
-
-To get started, spin up the watchtower container:
-
-```
-docker run -d \
- --name watchtower \
- -v /var/run/docker.sock:/var/run/docker.sock \
- containrrr/watchtower
-```
-
-For more information, see the [Watchtower Docs](https://containrrr.dev/watchtower/)
-
-### Updating Dashy from Source
-Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with `git pull origin master`, then update dependencies with `yarn`, rebuild with `yarn build`, and start the server again with `yarn start`.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Backing Up
-
-### Backing Up Containers
-
-You can make a backup of any running container really easily, using [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit/) and save it with [`docker export`](https://docs.docker.com/engine/reference/commandline/export/), to do so:
-- First find the container ID, you can do this with `docker container ls`
-- Now to create the snapshot, just run `docker commit -p [container-id] my-backup`
-- Finally, to save the backup locally, run `docker save -o ~/dashy-backup.tar my-backup`
-- If you want to push this to a container registry, run `docker push my-backup:latest`
-
-Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system.
-
-### Backing Up Volumes
-[offen/docker-volume-backup](https://github.com/offen/docker-volume-backup) is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups.
-
-To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their [documentation](https://github.com/offen/docker-volume-backup), which is very clear.
-
-```yaml
-version: '3'
-services:
- backup:
- image: offen/docker-volume-backup:latest
- environment:
- BACKUP_CRON_EXPRESSION: "0 * * * *"
- BACKUP_PRUNING_PREFIX: backup-
- BACKUP_RETENTION_DAYS: 7
- AWS_BUCKET_NAME: backup-bucket
- AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
- AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- volumes:
- - data:/backup/my-app-backup:ro
- - /var/run/docker.sock:/var/run/docker.sock:ro
-volumes:
- data:
-```
-
-It's worth noting that this process can also be done manually, using the following commands:
-
-Backup:
-```
-docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./
-```
-Restore:
-```
-docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"
-```
-### Dashy-Specific Backup
-Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed.
-
-Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the [Cloud Backup Docs](/docs/backup-restore)
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Scheduling
-
-If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it [ofelia](https://github.com/mcuadros/ofelia). This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is [crontab.guru](https://crontab.guru/). This can also be done natively with Alpine: `docker run -it alpine ls /etc/periodic`.
-I recommend combining this with [healthchecks](https://github.com/healthchecks/healthchecks) for easy monitoring of jobs, and failure notifications.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## SSL Certificates
-
-Enabling HTTPS with an SSL certificate is recommended, especially if you hare hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit.
-
-### Auto-SSL
-If you are using [NGINX Proxy Manager](https://nginxproxymanager.com/), then SSL is supported out of the box. Once you've added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.
-
-If you're hosting Dashy behind Cloudflare, then they offer [free and easy SSL](https://www.cloudflare.com/en-gb/learning/ssl/what-is-an-ssl-certificate/)- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find [this tutorial](https://www.sitepoint.com/a-guide-to-setting-up-lets-encrypt-ssl-on-shared-hosting/) helpful.
-
-### Getting a Self-Signed SSL Certificate
-[Let's Encrypt](https://letsencrypt.org/docs/) is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS [compatibility](https://letsencrypt.org/docs/certificate-compatibility/) with their ISRG X1 and DST CA X3 root certificates, support [Wildcard issuance](https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578) done via ACMEv2 using the DNS-01 and have [Multi-Perspective Validation](https://letsencrypt.org/2020/02/19/multi-perspective-validation.html). Let's Encrypt provide [CertBot](https://certbot.eff.org/) an easy app for generating and setting up an SSL certificate.
-
-This process can be automated, using something like the [Docker-NGINX-Auto-SSL Container](https://github.com/Valian/docker-nginx-auto-ssl) to generate and renew certificates when needed.
-
-If you're not so comfortable on the command line, then you can use a tool like [SSL For Free](https://www.sslforfree.com/) or [ZeroSSL](https://zerossl.com/) to generate your cert. They also provide step-by-step setup instructions for most platforms.
-
-### Passing a Self-Signed Certificate to Dashy
-Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the `SSL_PRIV_KEY_PATH` and `SSL_PUB_KEY_PATH` environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under `/etc/ssl/certs/dashy-pub.pem` and `/etc/ssl/certs/dashy-priv.key` respectively, e.g:
-
-```
-docker run -d \
- -p 8080:80 \
- -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \
- -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \
- lissy93/dashy:latest
-```
-
-By default the SSL port is `443` within a Docker container, or `4001` if running on bare metal, but you can override this with the `SSL_PORT` environmental variable.
-
-Once everything is setup, you can verify your site is secured using a tool like [SSL Checker](https://www.sslchecker.com/sslchecker).
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Authentication
-
-Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the **[Authentication Docs](/docs/authentication)** page.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Managing Containers with Docker Compose
-
-When you have a lot of containers, it quickly becomes hard to manage with `docker run` commands. The solution to this is [docker compose](https://docs.docker.com/compose/), a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - `docker compose up`. A good example of which can be seen in [@abhilesh's docker compose collection](https://github.com/abhilesh/self-hosted_docker_setups).
-
-You can use Dashy's default [`docker-compose.yml`](https://github.com/Lissy93/dashy/blob/master/docker-compose.yml) file as a template, and modify it according to your needs.
-
-An example Docker compose, using the default base image from DockerHub, might look something like this:
-
-```yaml
----
-version: "3.8"
-services:
- dashy:
- container_name: Dashy
- image: lissy93/dashy
- volumes:
- - /root/my-config.yml:/app/public/conf.yml
- ports:
- - 4000:80
- environment:
- - BASE_URL=/my-dashboard
- restart: unless-stopped
- healthcheck:
- test: ['CMD', 'node', '/app/services/healthcheck']
- interval: 1m30s
- timeout: 10s
- retries: 3
- start_period: 40s
-```
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Passing in Environmental Variables
-
-With Docker, you can define environmental variables under the `environment` section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see [the developing docs](/docs/developing#environmental-variables), or the default [`.env`](https://github.com/Lissy93/dashy/blob/master/.env) file.
-
-A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. `https://my-homelab.local/dashy` instead of `https://dashy.my-homelab.local`). In this use-case, you'd specify the `BASE_URL` variable in your compose file.
-
-```yaml
-environment:
- - BASE_URL=/dashy
-```
-
-You can also do the same thing with the docker run command, using the [`--env`](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) flag.
-If you've got many environmental variables, you might find it useful to put them in a [`.env` file](https://docs.docker.com/compose/env-file/). Similarly, for Docker run you can use [`--env-file`](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) if you'd like to pass in a file containing all your environmental variables.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Container Security
-
-- [Keep Docker Up-To-Date](#keep-docker-up-to-date)
-- [Set Resource Quotas](#set-resource-quotas)
-- [Don't Run as Root](#dont-run-as-root)
-- [Specify a User](#specify-a-user)
-- [Limit Capabilities](#limit-capabilities)
-- [Prevent new Privilages being Added](#prevent-new-privilages-being-added)
-- [Disable Inter-Container Communication](#disable-inter-container-communication)
-- [Don't Expose the Docker Daemon Socket](#dont-expose-the-docker-daemon-socket)
-- [Use Read-Only Volumes](#use-read-only-volumes)
-- [Set the Logging Level](#set-the-logging-level)
-- [Verify Image before Pulling](#verify-image-before-pulling)
-- [Specify the Tag](#specify-the-tag)
-- [Container Security Scanning](#container-security-scanning)
-- [Registry Security](#registry-security)
-- [Security Modules](#security-modules)
-
-### Keep Docker Up-To-Date
-To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the [Docker Installation Docs](https://docs.docker.com/engine/install/).
-
-### Set Resource Quotas
-Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the [Resource Constraints Docs](https://docs.docker.com/config/containers/resource_constraints/)
-
-For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core:
-`docker run -d -p 8080:80 --cpus=".5" --memory="1024m" lissy93/dashy:latest`
-
-### Don't Run as Root
-Running a container with admin privileges gives it more power than it needs, and can be abused. Dashy does not need any root privileges, and Docker by default doesn't run containers as root, so providing you don't specifically type sudo, you should be all good here.
-
-Note that if you're facing permission issues on Debian-based systems, you may need to add your user to the Docker group. First create the group: `sudo groupadd docker`, then add your (non-root) user: `sudo usermod âaG docker [my-username]`, finally `newgrp docker` to refresh.
-
-### Specify a User
-One of the best ways to prevent privilege escalation attacks, is to configure the container to use an unprivileged user. This also means that any files created by the container and mounted, will be owned by the specified user (and not root), which makes things much easier.
-
-You can specify a user, using the [`--user` param](https://docs.docker.com/engine/reference/run/#user), and should include the user ID (`UID`), which can be found by running `id -u`, and the and the group ID (`GID`), using `id -g`.
-
-With Docker run, you specify it like:
-`docker run --user 1000:1000 -p 8080:80 lissy93/dashy`
-
-Of if you're using Docker-compose, you could use an environmental variable
-
-```yaml
-version: "3.8"
-services:
- dashy:
- image: lissy93/dashy
- user: ${CURRENT_UID}
- ports: [ 4000:80 ]
-```
-
-And then to set the variable, and start the container, run: `CURRENT_UID=$(id -u):$(id -g) docker-compose up`
-
-### Limit capabilities
-Docker containers run with a subset of [Linux Kernal's Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) by default. It's good practice to drop privilege permissions that are not needed for any given container.
-
-With Docker run, you can use the `--cap-drop` flag to remove capabilities, you can also use `--cap-drop=all` and then define just the required permissions using the `--cap-add` option. For a list of available capabilities, see the [Privilege Capabilities Docs](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities).
-
-Here's an example using docker-compose, removing privileges that are not required for Dashy to run:
-
-```yaml
-version: "3.8"
-services:
- dashy:
- image: lissy93/dashy
- ports: [ 4000:80 ]
- cap_drop:
- - ALL
- cap_add:
- - CHOWN
- - SETGID
- - SETUID
- - DAC_OVERRIDE
- - NET_BIND_SERVICE
-```
-
-### Prevent new Privilages being Added
-To prevent processes inside the container from getting additional privileges, pass in the `--security-opt=no-new-privileges:true` option to the Docker run command (see [docs](https://docs.docker.com/engine/reference/run/#security-configuration)).
-
-Run Command:
-`docker run --security-opt=no-new-privileges:true -p 8080:80 lissy93/dashy`
-
-Docker Compose
-```yaml
-security_opt:
-- no-new-privileges:true
-```
-
-### Disable Inter-Container Communication
-By default Docker containers can talk to each other (using [`docker0` bridged network](https://docs.docker.com/config/containers/container-networking/)). If you don't need this capability, then it should be disabled. This can be done with the `--icc=false` in your run command. You can learn more about how to facilitate secure communication between containers in the [Compose Networking docs](https://docs.docker.com/compose/networking/).
-
-### Don't Expose the Docker Daemon Socket
-Docker socket `/var/run/docker.sock` is the UNIX socket that Docker is listening to. This is the primary entry point for the Docker API. The owner of this socket is root. Giving someone access to it is equivalent to giving unrestricted root access to your host.
-
-You should **not** enable TCP Docker daemon socket (`-H tcp://0.0.0.0:XXX`), as doing so exposes un-encrypted and unauthenticated direct access to the Docker daemon, and if the host is connected to the internet, the daemon on your computer can be used by anyone from the public internet- which is bad. If you need TCP, you should [see the docs](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option) to understand how to do this more securely.
-Similarly, never expose `/var/run/docker.sock` to other containers as a volume, as it can be exploited.
-
-### Use Read-Only Volumes
-You can specify that a specific volume should be read-only by appending `:ro` to the `-v` switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:
-```
-docker run -d \
- -p 8080:80 \
- -v ~/dashy-conf.yml:/app/public/conf.yml \
- -v ~/dashy-icons:/app/public/item-icons:ro \
- -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \
- lissy93/dashy:latest
-```
-
-You can also prevent a container from writing any changes to volumes on your host's disk, using the `--read-only` flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with `--tmpfs /app/public/conf.yml` - but that this will not write the volume back to your host.
-
-### Set the Logging Level
-Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is `INFO`, and this is also the recommendation, use `--log-level info` to ensure this is set.
-
-### Verify Image before Pulling
-Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,
-
-Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have.
-
-### Specify the Tag
-Using fixed tags (as opposed to `:latest` ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements.
-
-### Container Security Scanning
-It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using [Docker scan](https://docs.docker.com/engine/scan/), e.g: `docker scan lissy93/dashy:latest`.
-
-A similar product is [Trivy](https://github.com/aquasecurity/trivy), which is free an open source. First install it (with your package manager), then to scan an image, just run: `trivy image lissy93/dashy:latest`
-
-For larger systems, RedHat [Clair](https://www.redhat.com/en/topics/containers/what-is-clair) is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities.
-
-### Registry Security
-Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the [Deploying a Registry Docs](https://docs.docker.com/registry/deploying/) for more info. Another option is [Docker Trusted Registry](https://docker-docs.netlify.app/ee/dtr/), it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet.
-
-### Security Modules
-Docker supports several modules that let you write your own security profiles.
-
-[AppArmor](https://www.apparmor.net/)is a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the `apparmor` flag in docker run. Learn more about writing profiles, [here](https://gitlab.com/apparmor/apparmor/-/wikis/QuickProfileLanguage).
-
-[Seccomp](https://en.wikipedia.org/wiki/Seccomp) (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Hostâs Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running `docker info | grep seccomp`. A great resource for learning more about this is [DockerLabs](https://training.play-with-docker.com/security-seccomp/).
-
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Remote Access
-
-- [WireGuard](#wireguard)
-- [Reverse SSH Tunnel](#reverse-ssh-tunnel)
-
-### WireGuard
-
-Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. [WireGuard](https://www.wireguard.com/) is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead.
-
-- **Install Wireguard** - See the [Install Docs](https://www.wireguard.com/install/) for download links + instructions
- - On Debian-based systems, it's `sudo apt install wireguard`
-- **Generate a Private Key** - Run `wg genkey` on the Wireguard server, and copy it to somewhere safe for later
-- **Create Server Config** - Open or create a file at `/etc/wireguard/wg0.conf` and under `[Interface]` add the following (see example below):
- - `Address` - as a subnet of all desired IPs
- - `PrivateKey` - that you just generated
- - `ListenPort` - Default is `51820`, but can be anything
-- **Get Client App** - Download the [WG client app](https://www.wireguard.com/install/) for your platform (Linux, Windows, MacOS, Android or iOS are all supported)
-- **Create new Client Tunnel** - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the `wg genkey` command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config
-- **Add Clients to Server Config** - Head back to your `wg0.conf` file on the server, create a `[Peer]` section, and populate the following info
- - `AllowedIPs` - List of IP address inside the subnet, the client should have access to
- - `PublicKey` - The public key for the client you just generated
-- **Start the Server** - You can now start the WG server, using: `wg-quick up wg0` on your server
-- **Finish Client Setup** - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:
- - `PublicKey` - The public key of the server
- - `Address` - This should match the `AllowedIPs` section on the servers config file
- - `DNS` - The DNS server that'll be used when accessing the network through the VPN
- - `Endpoint` - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)
-- **Done** - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server
-
-**Example Server Config**
-
-```ini
-# Server file
-[Interface]
-# Which networks does my interface belong to? Notice: /24 and /64
-Address = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64
-PrivateKey = xxx
-ListenPort = 51820
-
-# Peer 1
-[Peer]
-PublicKey = xxx
-# Which source IPs can I expect from that peer? Notice: /32 and /128
-AllowedIps = 10.5.0.35/32, 2001:470:xxxx:xxxx::746f:786f/128
-
-# Peer 2
-[Peer]
-PublicKey = xxx
-# Which source IPs can I expect from that peer? This one has a LAN which can
-# access hosts/jails without NAT.
-# Peer 2 has a single IP address inside the VPN: it's 10.5.0.25/32
-AllowedIps = 10.5.0.25/32,10.21.10.0/24,10.21.20.0/24,10.21.30.0/24,10.31.0.0/24,2001:470:xxxx:xxxx::ca:571e/128
-```
-
-**Example Client Config**
-
-```ini
-[Interface]
-# Which networks does my interface belong to? Notice: /24 and /64
-Address = 10.5.0.35/24, 2001:470:xxxx:xxxx::746f:786f/64
-PrivateKey = xxx
-
-# Server
-[Peer]
-PublicKey = xxx
-# I want to route everything through the server, both IPv4 and IPv6. All IPs are
-# thus available through the Server, and I can expect packets from any IP to
-# come from that peer.
-AllowedIPs = 0.0.0.0/0, ::0/0
-# Where is the server on the internet? This is a public address. The port
-# (:51820) is the same as ListenPort in the [Interface] of the Server file above
-Endpoint = 1.2.3.4:51820
-# Usually, clients are behind NAT. to keep the connection running, keep alive.
-PersistentKeepalive = 15
-```
-
-
-A useful tool for getting WG setup is [Algo](https://github.com/trailofbits/algo). It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in [this blog post](https://blog.trailofbits.com/2016/12/12/meet-algo-the-vpn-that-works/).
-
-
-### Reverse SSH Tunnel
-
-SSH (or [Secure Shell](https://en.wikipedia.org/wiki/Secure_Shell)) is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option.
-
-Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network.
-
-The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the _mothership_), which in turn connects to your home network.
-
-Now all of this is starting to sound like quite a lot of work, but this is where services like [remot3.it](https://remote.it/) come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as [RemoteIoT](https://remoteiot.com/), or you could create your own on a cloud VPS (see [this tutorial](https://gist.github.com/nileshtrivedi/4c615e8d3c1bf053b0d31176b9e69e42) for more info on that).
-
-Before getting started, you'll need to head over to [Remote.it](https://app.remote.it/auth/#/sign-up) and create an account.
-
-Then setup your local device:
-1. If you haven't already done so, you'll need to enable and configure SSH.
- - This is out-of-scope of this article, but I've explained it in detail in [this post](https://notes.aliciasykes.com/22798/my-server-setup#configure-ssh).
-2. Download the Remote.it install script from their [GitHub](https://github.com/remoteit/installer)
- - `curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh`
-3. Make it executable, with `chmod +x ./auto-install.sh`, and then run it with `sudo ./auto-install.sh`
-4. Finally, configure your device, by running `sudo connectd_installer` and following the on-screen instructions
-
-And when you're ready to connect to it:
-1. Login to [app.remote.it](https://app.remote.it/), and select the name of your device
-2. You should see a list of running services, click SSH
-3. You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers
-
-Done :)
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Custom Domain
-
-- [Using DNS](#using-nginx)
-- [Using NGINX](#using-dns)
-
-### Using DNS
-For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: `192.168.0.2 dashy.homelab.local`.
-
-If you're using Pi-Hole, a similar thing can be done in the `/etc/dnsmasq.d/03-custom-dns.conf` file, add a line like: `address=/dashy.example.com/192.168.2.0` for each of your services.
-
-If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in [this article](https://homenetworkguy.com/how-to/use-custom-domain-name-in-internal-network/), by Dustin Casto.
-
-### Using NGINX
-If you're using NGINX, then you can use your own domain name, with a config similar to the below example.
-
-```
-upstream dashy {
- server 127.0.0.1:32400;
-}
-
-server {
- listen 80;
- server_name dashy.mydomain.com;
-
- # Setup SSL
- ssl_certificate /var/www/mydomain/sslcert.pem;
- ssl_certificate_key /var/www/mydomain/sslkey.pem;
- ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
- ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
- ssl_session_timeout 5m;
- ssl_prefer_server_ciphers on;
-
- location / {
- proxy_pass http://dashy;
- proxy_redirect off;
- proxy_buffering off;
- proxy_set_header host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
- }
-}
-```
-Similarly, a basic `Caddyfile` might look like:
-
-```
-dashy.example.com {
- reverse_proxy / nginx:80
-}
-```
-
-For more info, [this guide](https://thehomelab.wiki/books/dns-reverse-proxy/page/create-domain-records-to-point-to-your-home-server-on-cloudflare-using-nginx-progy-manager) on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful.
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Web Server Configuration
-
-_The following section only applies if you are not using Docker, and would like to use your own web server_
-
-Dashy ships with a pre-configured Node.js server, in [`server.js`](https://github.com/Lissy93/dashy/blob/master/server.js) which serves up the contents of the `./dist` directory on a given port. You can start the server by running `node server`. Note that the app must have been build (run `yarn build`), and you need [Node.js](https://nodejs.org) installed.
-
-If you wish to run Dashy from a sub page (e.g. `example.com/dashy`), then just set the `BASE_URL` environmental variable to that page name (in this example, `/dashy`), before building the app, and the path to all assets will then resolve to the new path, instead of `./`.
-
-However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server.
-
-Note, that if you choose not to use `server.js` to serve up the app, you will loose access to the following features:
-- Loading page, while the app is building
-- Writing config file to disk from the UI
-- Website status indicators, and ping checks
-
-Example Configs
-- [NGINX](#nginx)
-- [Apache](#apache)
-- [cPanel](#cpanel)
-
-### NGINX
-
-Create a new file in `/etc/nginx/sites-enabled/dashy`
-
-```
-server {
- listen 80;
- listen [::]:80;
-
- root /var/www/dashy/html;
- index index.html;
-
- server_name your-domain.com www.your-domain.com;
-
- location / {
- try_files $uri $uri/ =404;
- }
-}
-```
-Then upload the build contents of Dashy's dist directory to that location.
-For example: `scp -r ./dist/* [username]@[server_ip]:/var/www/dashy/html`
-
-### Apache
-
-Copy Dashy's dist folder to your apache server, `sudo cp -r ./dashy/dist /var/www/html/dashy`.
-
-In your Apache config, `/etc/apche2/apache2.conf` add:
-```
-
- Options Indexes FollowSymLinks
- AllowOverride All
- Require all granted
-
-```
-
-Add a `.htaccess` file within `/var/www/html/dashy/.htaccess`, and add:
-```
-Options -MultiViews
-RewriteEngine On
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^ index.html [QSA,L]
-```
-
-Then restart Apache, with `sudo systemctl restart apache2`
-
-### cPanel
-1. Login to your WHM
-2. Open 'Feature Manager' on the left sidebar
-3. Under 'Manage feature list', click 'Edit'
-4. Find 'Application manager' in the list, enable it and hit 'Save'
-5. Log into your users cPanel account, and under 'Software' find 'Application Manager'
-6. Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'
-7. The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'
-8. If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'.
-9. Dashy should now be running at your selected path an on a given port
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Running a Modified Version of the App
-
-If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how.
-
-The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (`yarn`), and start the development server (`yarn dev`) and visit `localhost:8080` in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running `yarn build` will build the app for production, and output the assets into `./dist` which can then be deployed using a web server, CDN or the built-in Node server with `yarn start`. For more info on all of this, take a look at the [Developing Docs](/docs/developing). To build your own Docker container from the modified app, see [Building your Own Container](#building-your-own-container)
-
-**[âŦī¸ Back to Top](#)**
-
----
-
-## Building your Own Container
-
-Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies.
-
-Then, either use Dashy's default [`Dockerfile`](https://github.com/Lissy93/dashy/blob/master/Dockerfile) as is, or modify it according to your needs.
-
-To build and deploy locally, first build the app with: `docker build -t dashy .`, and then start the app with `docker run -p 8080:80 --name my-dashboard dashy`. Or modify the `docker-compose.yml` file, replacing `image: lissy93/dashy` with `build: .` and run `docker compose up`.
-
-Your container should now be running, and will appear in the list when you run `docker container ls âa`. If you'd like to enter the container, run `docker exec -it [container-id] /bin/ash`.
-
-You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image.
-You can push your build image, by running: `docker push ghcr.io/OWNER/IMAGE_NAME:latest`. You will first need to authenticate, this can be done by running `echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin`, where `CR_PAT` is an environmental variable containing a token generated from your GitHub account. For more info, see the [Container Registry Docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry).
-
-**[âŦī¸ Back to Top](#)**
-
----
\ No newline at end of file
+# App Management
+
+_The following article is a primer on managing self-hosted apps. It covers everything from keeping the Dashy (or any other app) up-to-date, secure, backed up, to other topics like auto-starting, monitoring, log management, web server configuration and using custom domains._
+
+## Contents
+- [Providing Assets](#providing-assets)
+- [Running Commands](#running-commands)
+- [Healthchecks](#healthchecks)
+- [Logs and Performance](#logs-and-performance)
+- [Auto-Starting at Boot](#auto-starting-at-system-boot)
+- [Updating](#updating)
+- [Backing Up](#backing-up)
+- [Scheduling](#scheduling)
+- [SSL Certificates](#ssl-certificates)
+- [Authentication](#authentication)
+- [Managing with Compose](#managing-containers-with-docker-compose)
+- [Environmental Variables](#passing-in-environmental-variables)
+- [Remote Access](#remote-access)
+- [Custom Domain](#custom-domain)
+- [Securing Containers](#container-security)
+- [Web Server Configuration](#web-server-configuration)
+- [Running a Modified App](#running-a-modified-version-of-the-app)
+- [Building your Own Container](#building-your-own-container)
+
+---
+
+## Providing Assets
+Although not essential, you will most likely want to provide several assets to your running app.
+
+This is easy to do using [Docker Volumes](https://docs.docker.com/storage/volumes/), which lets you share a file or directory between your host system, and the container. Volumes are specified in the Docker run command, or Docker compose file, using the `--volume` or `-v` flags. The value of which consists of the path to the file / directory on your host system, followed by the destination path within the container. Fields are separated by a colon (`:`), and must be in the correct order. For example: `-v ~/alicia/my-local-conf.yml:/app/public/conf.yml`
+
+In Dashy, commonly configured resources include:
+- `./public/conf.yml` - Your main application config file
+- `./public/item-icons` - A directory containing your own icons. This allows for offline access, and better performance than fetching from a CDN
+- Also within `./public` you'll find standard website assets, including `favicon.ico`, `manifest.json`, `robots.txt`, etc. There's no need to pass these in, but you can do so if you wish
+- `/src/styles/user-defined-themes.scss` - A stylesheet for applying custom CSS to your app. You can also write your own themes here.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+## Running Commands
+
+ If you're running an app in Docker, then commands will need to be passed to the container to be executed. This can be done by preceding each command with `docker exec -it [container-id]`, where container ID can be found by running `docker ps`. For example `docker exec -it 26c156c467b4 yarn build`. You can also enter the container, with `docker exec -it [container-id] /bin/ash`, and navigate around it with normal Linux commands.
+
+ Dashy has several commands that can be used for various tasks, you can find a list of these either in the [Developing Docs](/docs/developing#project-commands), or by looking at the [`package.json`](https://github.com/Lissy93/dashy/blob/master/package.json#L5). These can be used by running `yarn [command-name]`.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+## Healthchecks
+
+Healthchecks are configured to periodically check that Dashy is up and running correctly on the specified port. By default, the health script is called every 5 minutes, but this can be modified with the `--health-interval` option. You can check the current container health with: `docker inspect --format "{{json .State.Health }}" [container-id]`, and a summary of health status will show up under `docker ps`. You can also manually request the current application status by running `docker exec -it [container-id] yarn health-check`. You can disable healthchecks altogether by adding the `--no-healthcheck` flag to your Docker run command.
+
+To restart unhealthy containers automatically, check out [Autoheal](https://hub.docker.com/r/willfarrell/autoheal/). This image watches for unhealthy containers, and automatically triggers a restart. (This is a stand in for Docker's `--exit-on-unhealthy` that was proposed, but [not merged](https://github.com/moby/moby/pull/22719)). There's also [Deunhealth](https://github.com/qdm12/deunhealth), which is super light-weight, and doesn't require network access.
+
+```
+docker run -d \
+ --name autoheal \
+ --restart=always \
+ -e AUTOHEAL_CONTAINER_LABEL=all \
+ -v /var/run/docker.sock:/var/run/docker.sock \
+ willfarrell/autoheal
+```
+
+**[âŦī¸ Back to Top](#)**
+
+---
+## Logs and Performance
+
+#### Container Logs
+You can view logs for a given Docker container with `docker logs [container-id]`, add the `--follow` flag to stream the logs. For more info, see the [Logging Documentation](https://docs.docker.com/config/containers/logging/). There's also [Dozzle](https://dozzle.dev/), a useful tool, that provides a web interface where you can stream and query logs from all your running containers from a single web app.
+
+#### Container Performance
+You can check the resource usage for your running Docker containers with `docker stats` or `docker stats [container-id]`. For more info, see the [Stats Documentation](https://docs.docker.com/engine/reference/commandline/stats/). There's also [cAdvisor](https://github.com/google/cadvisor), a useful web app for viewing and analyzing resource usage and performance of all your running containers.
+
+#### Management Apps
+You can also view logs, resource usage and other info as well as manage your entire Docker workflow in third-party Docker management apps. For example [Portainer](https://github.com/portainer/portainer) an all-in-one open source management web UI for Docker and Kubernetes, or [LazyDocker](https://github.com/jesseduffield/lazydocker) a terminal UI for Docker container management and monitoring.
+
+#### Advanced Logging and Monitoring
+Docker supports using [Prometheus](https://prometheus.io/) to collect logs, which can then be visualized using a platform like [Grafana](https://grafana.com/). For more info, see [this guide](https://docs.docker.com/config/daemon/prometheus/). If you need to route your logs to a remote syslog, then consider using [logspout](https://github.com/gliderlabs/logspout). For enterprise-grade instances, there are managed services, that make monitoring container logs and metrics very easy, such as [Sematext](https://sematext.com/blog/docker-container-monitoring-with-sematext/) with [Logagent](https://github.com/sematext/logagent-js).
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Auto-Starting at System Boot
+
+You can use Docker's [restart policies](https://docs.docker.com/engine/reference/run/#restart-policies---restart) to instruct the container to start after a system reboot, or restart after a crash. Just add the `--restart=always` flag to your Docker compose script or Docker run command. For more information, see the docs on [Starting Containers Automatically](https://docs.docker.com/config/containers/start-containers-automatically/).
+
+For Podman, you can use `systemd` to create a service that launches your container, [the docs](https://podman.io/blogs/2018/09/13/systemd.html) explains things further. A similar approach can be used with Docker, if you need to start containers after a reboot, but before any user interaction.
+
+To restart the container after something within it has crashed, consider using [`docker-autoheal`](https://github.com/willfarrell/docker-autoheal) by @willfarrell, a service that monitors and restarts unhealthy containers. For more info, see the [Healthchecks](#healthchecks) section above.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+## Updating
+
+Dashy is under active development, so to take advantage of the latest features, you may need to update your instance every now and again.
+
+### Updating Docker Container
+1. Pull latest image: `docker pull lissy93/dashy:latest`
+2. Kill off existing container
+ - Find container ID: `docker ps`
+ - Stop container: `docker stop [container_id]`
+ - Remove container: `docker rm [container_id]`
+3. Spin up new container: `docker run [params] lissy93/dashy`
+
+### Automatic Docker Updates
+
+You can automate the above process using [Watchtower](https://github.com/containrrr/watchtower).
+Watchtower will watch for new versions of a given image on Docker Hub, pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially.
+
+To get started, spin up the watchtower container:
+
+```
+docker run -d \
+ --name watchtower \
+ -v /var/run/docker.sock:/var/run/docker.sock \
+ containrrr/watchtower
+```
+
+For more information, see the [Watchtower Docs](https://containrrr.dev/watchtower/)
+
+### Updating Dashy from Source
+Stop your current instance of Dashy, then navigate into the source directory. Pull down the latest code, with `git pull origin master`, then update dependencies with `yarn`, rebuild with `yarn build`, and start the server again with `yarn start`.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Backing Up
+
+### Backing Up Containers
+
+You can make a backup of any running container really easily, using [`docker commit`](https://docs.docker.com/engine/reference/commandline/commit/) and save it with [`docker export`](https://docs.docker.com/engine/reference/commandline/export/), to do so:
+- First find the container ID, you can do this with `docker container ls`
+- Now to create the snapshot, just run `docker commit -p [container-id] my-backup`
+- Finally, to save the backup locally, run `docker save -o ~/dashy-backup.tar my-backup`
+- If you want to push this to a container registry, run `docker push my-backup:latest`
+
+Note that this will not include any data in docker volumes, and the process here is a bit different. Since these files exist on your host system, if you have an existing backup solution implemented, you can incorporate and volume files within that system.
+
+### Backing Up Volumes
+[offen/docker-volume-backup](https://github.com/offen/docker-volume-backup) is a useful tool for periodic Docker volume backups, to any S3-compatible storage provider. It's run as a light-weight Docker container, and is easy to setup, and also supports GPG-encryption, email notification, and routing away older backups.
+
+To get started, create a docker-compose similar to the example below, and then start the container. For more info, check out their [documentation](https://github.com/offen/docker-volume-backup), which is very clear.
+
+```yaml
+version: '3'
+services:
+ backup:
+ image: offen/docker-volume-backup:latest
+ environment:
+ BACKUP_CRON_EXPRESSION: "0 * * * *"
+ BACKUP_PRUNING_PREFIX: backup-
+ BACKUP_RETENTION_DAYS: 7
+ AWS_BUCKET_NAME: backup-bucket
+ AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
+ AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
+ volumes:
+ - data:/backup/my-app-backup:ro
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+volumes:
+ data:
+```
+
+It's worth noting that this process can also be done manually, using the following commands:
+
+Backup:
+```
+docker run --rm -v some_volume:/volume -v /tmp:/backup alpine tar -cjf /backup/some_archive.tar.bz2 -C /volume ./
+```
+Restore:
+```
+docker run --rm -v some_volume:/volume -v /tmp:/backup alpine sh -c "rm -rf /volume/* /volume/..?* /volume/.[!.]* ; tar -C /volume/ -xjf /backup/some_archive.tar.bz2"
+```
+### Dashy-Specific Backup
+Since Dashy is open source, and freely available, providing you're configuration data is passed in as volumes, there shouldn't be any need to backup the main container. Your main config file, and any assets you're using should be kept backed up, preferably in at least two places, and you should ensure that you can easily restore from backup, if needed.
+
+Dashy also has a built-in cloud backup feature, which is free for personal users, and will let you make and restore fully encrypted backups of your config directly through the UI. To learn more, see the [Cloud Backup Docs](/docs/backup-restore)
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Scheduling
+
+If you need to periodically schedule the running of a given command on Dashy (or any other container), then a useful tool for doing so it [ofelia](https://github.com/mcuadros/ofelia). This runs as a Docker container and is really useful for things like backups, logging, updating, notifications, etc. Crons are specified using Go's crontab format, and a useful tool for visualizing this is [crontab.guru](https://crontab.guru/). This can also be done natively with Alpine: `docker run -it alpine ls /etc/periodic`.
+I recommend combining this with [healthchecks](https://github.com/healthchecks/healthchecks) for easy monitoring of jobs, and failure notifications.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## SSL Certificates
+
+Enabling HTTPS with an SSL certificate is recommended, especially if you hare hosting Dashy anywhere other than your home. This will ensure that all traffic is encrypted in transit.
+
+### Auto-SSL
+If you are using [NGINX Proxy Manager](https://nginxproxymanager.com/), then SSL is supported out of the box. Once you've added your proxy host and web address, then set the scheme to HTTPS, then under the SSL Tab select "Request a new SSL certificate" and follow the on-screen instructions.
+
+If you're hosting Dashy behind Cloudflare, then they offer [free and easy SSL](https://www.cloudflare.com/en-gb/learning/ssl/what-is-an-ssl-certificate/)- all you need to do is enable it under the SSL/TLS tab. Or if you are using shared hosting, you may find [this tutorial](https://www.sitepoint.com/a-guide-to-setting-up-lets-encrypt-ssl-on-shared-hosting/) helpful.
+
+### Getting a Self-Signed SSL Certificate
+[Let's Encrypt](https://letsencrypt.org/docs/) is a global Certificate Authority, providing free SSL/TLS Domain Validation certificates in order to enable secure HTTPS access to your website. They have good browser/ OS [compatibility](https://letsencrypt.org/docs/certificate-compatibility/) with their ISRG X1 and DST CA X3 root certificates, support [Wildcard issuance](https://community.letsencrypt.org/t/acme-v2-production-environment-wildcards/55578) done via ACMEv2 using the DNS-01 and have [Multi-Perspective Validation](https://letsencrypt.org/2020/02/19/multi-perspective-validation.html). Let's Encrypt provide [CertBot](https://certbot.eff.org/) an easy app for generating and setting up an SSL certificate.
+
+This process can be automated, using something like the [Docker-NGINX-Auto-SSL Container](https://github.com/Valian/docker-nginx-auto-ssl) to generate and renew certificates when needed.
+
+If you're not so comfortable on the command line, then you can use a tool like [SSL For Free](https://www.sslforfree.com/) or [ZeroSSL](https://zerossl.com/) to generate your cert. They also provide step-by-step setup instructions for most platforms.
+
+### Passing a Self-Signed Certificate to Dashy
+Once you've generated your SSL cert, you'll need to pass it to Dashy. This can be done by specifying the paths to your public and private keys using the `SSL_PRIV_KEY_PATH` and `SSL_PUB_KEY_PATH` environmental variables. Or if you're using Docker, then just pass public + private SSL keys in under `/etc/ssl/certs/dashy-pub.pem` and `/etc/ssl/certs/dashy-priv.key` respectively, e.g:
+
+```
+docker run -d \
+ -p 8080:80 \
+ -v ~/my-private-key.key:/etc/ssl/certs/dashy-priv.key:ro \
+ -v ~/my-public-key.pem:/etc/ssl/certs/dashy-pub.pem:ro \
+ lissy93/dashy:latest
+```
+
+By default the SSL port is `443` within a Docker container, or `4001` if running on bare metal, but you can override this with the `SSL_PORT` environmental variable.
+
+Once everything is setup, you can verify your site is secured using a tool like [SSL Checker](https://www.sslchecker.com/sslchecker).
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Authentication
+
+Dashy natively supports secure authentication using KeyCloak. There is also a Simple Auth feature that doesn't require any additional setup. Usage instructions for both, as well as alternative auth methods, has now moved to the **[Authentication Docs](/docs/authentication)** page.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Managing Containers with Docker Compose
+
+When you have a lot of containers, it quickly becomes hard to manage with `docker run` commands. The solution to this is [docker compose](https://docs.docker.com/compose/), a handy tool for defining all a containers run settings in a single YAML file, and then spinning up that container with a single short command - `docker compose up`. A good example of which can be seen in [@abhilesh's docker compose collection](https://github.com/abhilesh/self-hosted_docker_setups).
+
+You can use Dashy's default [`docker-compose.yml`](https://github.com/Lissy93/dashy/blob/master/docker-compose.yml) file as a template, and modify it according to your needs.
+
+An example Docker compose, using the default base image from DockerHub, might look something like this:
+
+```yaml
+---
+version: "3.8"
+services:
+ dashy:
+ container_name: Dashy
+ image: lissy93/dashy
+ volumes:
+ - /root/my-config.yml:/app/public/conf.yml
+ ports:
+ - 4000:80
+ environment:
+ - BASE_URL=/my-dashboard
+ restart: unless-stopped
+ healthcheck:
+ test: ['CMD', 'node', '/app/services/healthcheck']
+ interval: 1m30s
+ timeout: 10s
+ retries: 3
+ start_period: 40s
+```
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Passing in Environmental Variables
+
+With Docker, you can define environmental variables under the `environment` section of your Docker compose file. Environmental variables are used to configure high-level settings, usually before the config file has been read. For a list of all supported env vars in Dashy, see [the developing docs](/docs/developing#environmental-variables), or the default [`.env`](https://github.com/Lissy93/dashy/blob/master/.env) file.
+
+A common use case, is to run Dashy under a sub-page, instead of at the root of a URL (e.g. `https://my-homelab.local/dashy` instead of `https://dashy.my-homelab.local`). In this use-case, you'd specify the `BASE_URL` variable in your compose file.
+
+```yaml
+environment:
+ - BASE_URL=/dashy
+```
+
+You can also do the same thing with the docker run command, using the [`--env`](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) flag.
+If you've got many environmental variables, you might find it useful to put them in a [`.env` file](https://docs.docker.com/compose/env-file/). Similarly, for Docker run you can use [`--env-file`](https://docs.docker.com/engine/reference/commandline/run/#set-environment-variables--e---env---env-file) if you'd like to pass in a file containing all your environmental variables.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Remote Access
+
+- [WireGuard](#wireguard)
+- [Reverse SSH Tunnel](#reverse-ssh-tunnel)
+- [TCP Tunnel](#tcp-tunnel)
+
+### WireGuard
+
+Using a VPN is one of the easiest ways to provide secure, full access to your local network from remote locations. [WireGuard](https://www.wireguard.com/) is a reasonably new open source VPN protocol, that was designed with ease of use, performance and security in mind. Unlike OpenVPN, it doesn't need to recreate the tunnel whenever connection is dropped, and it's also much easier to setup, using shared keys instead.
+
+- **Install Wireguard** - See the [Install Docs](https://www.wireguard.com/install/) for download links + instructions
+ - On Debian-based systems, it's `sudo apt install wireguard`
+- **Generate a Private Key** - Run `wg genkey` on the Wireguard server, and copy it to somewhere safe for later
+- **Create Server Config** - Open or create a file at `/etc/wireguard/wg0.conf` and under `[Interface]` add the following (see example below):
+ - `Address` - as a subnet of all desired IPs
+ - `PrivateKey` - that you just generated
+ - `ListenPort` - Default is `51820`, but can be anything
+- **Get Client App** - Download the [WG client app](https://www.wireguard.com/install/) for your platform (Linux, Windows, MacOS, Android or iOS are all supported)
+- **Create new Client Tunnel** - On your client app, there should be an option to create a new tunnel, when doing so a client private key will be generated (but if not, use the `wg genkey` command again), and keep it somewhere safe. A public key will also be generated, and this will go in our saver config
+- **Add Clients to Server Config** - Head back to your `wg0.conf` file on the server, create a `[Peer]` section, and populate the following info
+ - `AllowedIPs` - List of IP address inside the subnet, the client should have access to
+ - `PublicKey` - The public key for the client you just generated
+- **Start the Server** - You can now start the WG server, using: `wg-quick up wg0` on your server
+- **Finish Client Setup** - Head back to your client device, and edit the config file, leave the private key as is, and add the following fields:
+ - `PublicKey` - The public key of the server
+ - `Address` - This should match the `AllowedIPs` section on the servers config file
+ - `DNS` - The DNS server that'll be used when accessing the network through the VPN
+ - `Endpoint` - The hostname or IP + Port where your WG server is running (you may need to forward this in your firewall's settings)
+- **Done** - Your clients should now be able to connect to your WG server :) Depending on your networks firewall rules, you may need to port forward the address of your WG server
+
+**Example Server Config**
+
+```ini
+# Server file
+[Interface]
+# Which networks does my interface belong to? Notice: /24 and /64
+Address = 10.5.0.1/24, 2001:470:xxxx:xxxx::1/64
+PrivateKey = xxx
+ListenPort = 51820
+
+# Peer 1
+[Peer]
+PublicKey = xxx
+# Which source IPs can I expect from that peer? Notice: /32 and /128
+AllowedIps = 10.5.0.35/32, 2001:470:xxxx:xxxx::746f:786f/128
+
+# Peer 2
+[Peer]
+PublicKey = xxx
+# Which source IPs can I expect from that peer? This one has a LAN which can
+# access hosts/jails without NAT.
+# Peer 2 has a single IP address inside the VPN: it's 10.5.0.25/32
+AllowedIps = 10.5.0.25/32,10.21.10.0/24,10.21.20.0/24,10.21.30.0/24,10.31.0.0/24,2001:470:xxxx:xxxx::ca:571e/128
+```
+
+**Example Client Config**
+
+```ini
+[Interface]
+# Which networks does my interface belong to? Notice: /24 and /64
+Address = 10.5.0.35/24, 2001:470:xxxx:xxxx::746f:786f/64
+PrivateKey = xxx
+
+# Server
+[Peer]
+PublicKey = xxx
+# I want to route everything through the server, both IPv4 and IPv6. All IPs are
+# thus available through the Server, and I can expect packets from any IP to
+# come from that peer.
+AllowedIPs = 0.0.0.0/0, ::0/0
+# Where is the server on the internet? This is a public address. The port
+# (:51820) is the same as ListenPort in the [Interface] of the Server file above
+Endpoint = 1.2.3.4:51820
+# Usually, clients are behind NAT. to keep the connection running, keep alive.
+PersistentKeepalive = 15
+```
+
+
+A useful tool for getting WG setup is [Algo](https://github.com/trailofbits/algo). It includes scripts and docs which cover almost all devices, platforms and clients, and has best practices implemented, and security features enabled. All of this is better explained in [this blog post](https://blog.trailofbits.com/2016/12/12/meet-algo-the-vpn-that-works/).
+
+
+### Reverse SSH Tunnel
+
+SSH (or [Secure Shell](https://en.wikipedia.org/wiki/Secure_Shell)) is a secure tunnel that allows you to connect to a remote host. Unlike the VPN methods, an SSH connection does not require an intermediary, and will not be affected by your IP changing. However it only allows you to access a single service at a time. SSH was really designed for terminal access, but because of the latter mentioned benefits it's useful to setup, as a fallback option.
+
+Directly SSH'ing into your home, would require you to open a port (usually 22), which would be terrible for security, and is not recommended. However a reverse SSH connection is initiated from inside your network. Once the connection is established, the port is redirected, allowing you to use the established connection to SSH into your home network.
+
+The issue you've probably spotted, is that most public, corporate, and institutional networks will block SSH connections. To overcome this, you'd have to establish a server outside of your homelab that your homelab's device could SSH into to establish the reverse SSH connection. You can then connect to that remote server (the _mothership_), which in turn connects to your home network.
+
+Now all of this is starting to sound like quite a lot of work, but this is where services like [remot3.it](https://remote.it/) come in. They maintain the intermediary mothership server, and create the tunnel service for you. It's free for personal use, secure and easy. There are several similar services, such as [RemoteIoT](https://remoteiot.com/), or you could create your own on a cloud VPS (see [this tutorial](https://gist.github.com/nileshtrivedi/4c615e8d3c1bf053b0d31176b9e69e42) for more info on that).
+
+Before getting started, you'll need to head over to [Remote.it](https://app.remote.it/auth/#/sign-up) and create an account.
+
+Then setup your local device:
+1. If you haven't already done so, you'll need to enable and configure SSH.
+ - This is out-of-scope of this article, but I've explained it in detail in [this post](https://notes.aliciasykes.com/22798/my-server-setup#configure-ssh).
+2. Download the Remote.it install script from their [GitHub](https://github.com/remoteit/installer)
+ - `curl -LkO https://raw.githubusercontent.com/remoteit/installer/master/scripts/auto-install.sh`
+3. Make it executable, with `chmod +x ./auto-install.sh`, and then run it with `sudo ./auto-install.sh`
+4. Finally, configure your device, by running `sudo connectd_installer` and following the on-screen instructions
+
+And when you're ready to connect to it:
+1. Login to [app.remote.it](https://app.remote.it/), and select the name of your device
+2. You should see a list of running services, click SSH
+3. You'll then be presented with some SSH credentials that you can now use to securely connect to your home, via the Remote.it servers
+
+Done :)
+
+### TCP Tunnel
+
+If you're running Dashy on your local network, behind a firewall, but need to temporarily share it with someone external, this can be achieved quickly and securely using [Ngrok](https://ngrok.com/). Itâs basically a super slick, encrypted TCP tunnel that provides an internet-accessible address that anyone use to access your local service, from anywhere.
+
+To get started, [Download](https://ngrok.com/download) and install Ngrok for your system, then just run `ngrok http [port]` (replace the port with the http port where Dashy is running, e.g. 8080). When [using https](https://ngrok.com/docs#http-local-https), specify the full local url/ ip including the protocol.
+
+Some Ngrok features require you to be authenticated, you can [create a free account](https://dashboard.ngrok.com/signup) and generate a token in [your dashboard](https://dashboard.ngrok.com/auth/your-authtoken), then run `ngrok authtoken [token]`.
+
+It's recommended to use authentication for any publicly accessible service. Dashy has an [Auth](/docs/authentication) feature built in, but an even easier method it to use the [`-auth`](https://ngrok.com/docs#http-auth) switch. E.g. `ngrok http -auth=âusername:password123â 8080`
+
+By default, your web app is assigned a randomly generated ngrok domain, but you can also use your own custom domain. Under the [Domains Tab](https://dashboard.ngrok.com/endpoints/domains) of your Ngrok dashboard, add your domain, and follow the CNAME instructions. You can now use your domain, with the [`-hostname`](https://ngrok.com/docs#http-custom-domains) switch, e.g. `ngrok http -region=us -hostname=dashy.example.com 8080`. If you don't have your own domain name, you can instead use a custom sub-domain (e.g. `alicia-dashy.ngrok.io`), using the [`-subdomain`](https://ngrok.com/docs#custom-subdomain-names) switch.
+
+To integrate this into your docker-compose, take a look at the [gtriggiano/ngrok-tunnel](https://github.com/gtriggiano/ngrok-tunnel) container.
+
+There's so much more you can do with Ngrok, such as exposing a directory as a file browser, using websockets, relaying requests, rewriting headers, inspecting traffic, TLS and TCP tunnels and lots more. All or which is explained in [the Documentation](https://ngrok.com/docs).
+
+It's worth noting that Ngrok isn't the only option here, other options include: [FRP](https://github.com/fatedier/frp), [Inlets](https://inlets.dev), [Local Tunnel](https://localtunnel.me/), [TailScale](https://tailscale.com/), etc. Check out [Awesome Tunneling](https://github.com/anderspitman/awesome-tunneling) for a list of alternatives.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Custom Domain
+
+- [Using DNS](#using-nginx)
+- [Using NGINX](#using-dns)
+
+### Using DNS
+For locally running services, a domain can be set up directly in the DNS records. This method is really quick and easy, and doesn't require you to purchase an actual domain. Just update your networks DNS resolver, to point your desired URL to the local IP where Dashy (or any other app) is running. For example, a line in your hosts file might look something like: `192.168.0.2 dashy.homelab.local`.
+
+If you're using Pi-Hole, a similar thing can be done in the `/etc/dnsmasq.d/03-custom-dns.conf` file, add a line like: `address=/dashy.example.com/192.168.2.0` for each of your services.
+
+If you're running OPNSense/ PfSense, then this can be done through the UI with Unbound, it's explained nicely in [this article](https://homenetworkguy.com/how-to/use-custom-domain-name-in-internal-network/), by Dustin Casto.
+
+### Using NGINX
+If you're using NGINX, then you can use your own domain name, with a config similar to the below example.
+
+```
+upstream dashy {
+ server 127.0.0.1:32400;
+}
+
+server {
+ listen 80;
+ server_name dashy.mydomain.com;
+
+ # Setup SSL
+ ssl_certificate /var/www/mydomain/sslcert.pem;
+ ssl_certificate_key /var/www/mydomain/sslkey.pem;
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
+ ssl_session_timeout 5m;
+ ssl_prefer_server_ciphers on;
+
+ location / {
+ proxy_pass http://dashy;
+ proxy_redirect off;
+ proxy_buffering off;
+ proxy_set_header host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
+ }
+}
+```
+Similarly, a basic `Caddyfile` might look like:
+
+```
+dashy.example.com {
+ reverse_proxy / nginx:80
+}
+```
+
+For more info, [this guide](https://thehomelab.wiki/books/dns-reverse-proxy/page/create-domain-records-to-point-to-your-home-server-on-cloudflare-using-nginx-progy-manager) on Setting up Domains with NGINX Proxy Manager and CloudFlare may be useful.
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Container Security
+
+- [Keep Docker Up-To-Date](#keep-docker-up-to-date)
+- [Set Resource Quotas](#set-resource-quotas)
+- [Don't Run as Root](#dont-run-as-root)
+- [Specify a User](#specify-a-user)
+- [Limit Capabilities](#limit-capabilities)
+- [Prevent new Privilages being Added](#prevent-new-privilages-being-added)
+- [Disable Inter-Container Communication](#disable-inter-container-communication)
+- [Don't Expose the Docker Daemon Socket](#dont-expose-the-docker-daemon-socket)
+- [Use Read-Only Volumes](#use-read-only-volumes)
+- [Set the Logging Level](#set-the-logging-level)
+- [Verify Image before Pulling](#verify-image-before-pulling)
+- [Specify the Tag](#specify-the-tag)
+- [Container Security Scanning](#container-security-scanning)
+- [Registry Security](#registry-security)
+- [Security Modules](#security-modules)
+
+### Keep Docker Up-To-Date
+To prevent known container escape vulnerabilities, which typically end in escalating to root/administrator privileges, patching Docker Engine and Docker Machine is crucial. For more info, see the [Docker Installation Docs](https://docs.docker.com/engine/install/).
+
+### Set Resource Quotas
+Docker enables you to limit resource consumption (CPU, memory, disk) on a per-container basis. This not only enhances system performance, but also prevents a compromised container from consuming a large amount of resources, in order to disrupt service or perform malicious activities. To learn more, see the [Resource Constraints Docs](https://docs.docker.com/config/containers/resource_constraints/)
+
+For example, to run Dashy with max of 1GB ram, and max of 50% of 1 CP core:
+`docker run -d -p 8080:80 --cpus=".5" --memory="1024m" lissy93/dashy:latest`
+
+### Don't Run as Root
+Running a container with admin privileges gives it more power than it needs, and can be abused. Dashy does not need any root privileges, and Docker by default doesn't run containers as root, so providing you don't specifically type sudo, you should be all good here.
+
+Note that if you're facing permission issues on Debian-based systems, you may need to add your user to the Docker group. First create the group: `sudo groupadd docker`, then add your (non-root) user: `sudo usermod âaG docker [my-username]`, finally `newgrp docker` to refresh.
+
+### Specify a User
+One of the best ways to prevent privilege escalation attacks, is to configure the container to use an unprivileged user. This also means that any files created by the container and mounted, will be owned by the specified user (and not root), which makes things much easier.
+
+You can specify a user, using the [`--user` param](https://docs.docker.com/engine/reference/run/#user), and should include the user ID (`UID`), which can be found by running `id -u`, and the and the group ID (`GID`), using `id -g`.
+
+With Docker run, you specify it like:
+`docker run --user 1000:1000 -p 8080:80 lissy93/dashy`
+
+Of if you're using Docker-compose, you could use an environmental variable
+
+```yaml
+version: "3.8"
+services:
+ dashy:
+ image: lissy93/dashy
+ user: ${CURRENT_UID}
+ ports: [ 4000:80 ]
+```
+
+And then to set the variable, and start the container, run: `CURRENT_UID=$(id -u):$(id -g) docker-compose up`
+
+### Limit capabilities
+Docker containers run with a subset of [Linux Kernal's Capabilities](https://man7.org/linux/man-pages/man7/capabilities.7.html) by default. It's good practice to drop privilege permissions that are not needed for any given container.
+
+With Docker run, you can use the `--cap-drop` flag to remove capabilities, you can also use `--cap-drop=all` and then define just the required permissions using the `--cap-add` option. For a list of available capabilities, see the [Privilege Capabilities Docs](https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities).
+
+Note that dropping privileges and capabilities on runtime is not fool-proof, and often any leftover privileges can be used to re-escalate, see [POS36-C](https://wiki.sei.cmu.edu/confluence/display/c/POS36-C.+Observe+correct+revocation+order+while+relinquishing+privileges).
+
+Here's an example using docker-compose, removing privileges that are not required for Dashy to run:
+
+```yaml
+version: "3.8"
+services:
+ dashy:
+ image: lissy93/dashy
+ ports: [ 4000:80 ]
+ cap_drop:
+ - ALL
+ cap_add:
+ - CHOWN
+ - SETGID
+ - SETUID
+ - DAC_OVERRIDE
+ - NET_BIND_SERVICE
+```
+
+### Prevent new Privilages being Added
+To prevent processes inside the container from getting additional privileges, pass in the `--security-opt=no-new-privileges:true` option to the Docker run command (see [docs](https://docs.docker.com/engine/reference/run/#security-configuration)).
+
+Run Command:
+`docker run --security-opt=no-new-privileges:true -p 8080:80 lissy93/dashy`
+
+Docker Compose
+```yaml
+security_opt:
+- no-new-privileges:true
+```
+
+### Disable Inter-Container Communication
+By default Docker containers can talk to each other (using [`docker0` bridged network](https://docs.docker.com/config/containers/container-networking/)). If you don't need this capability, then it should be disabled. This can be done with the `--icc=false` in your run command. You can learn more about how to facilitate secure communication between containers in the [Compose Networking docs](https://docs.docker.com/compose/networking/).
+
+### Don't Expose the Docker Daemon Socket
+Docker socket `/var/run/docker.sock` is the UNIX socket that Docker is listening to. This is the primary entry point for the Docker API. The owner of this socket is root. Giving someone access to it is equivalent to giving unrestricted root access to your host.
+
+You should **not** enable TCP Docker daemon socket (`-H tcp://0.0.0.0:XXX`), as doing so exposes un-encrypted and unauthenticated direct access to the Docker daemon, and if the host is connected to the internet, the daemon on your computer can be used by anyone from the public internet- which is bad. If you need TCP, you should [see the docs](https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option) to understand how to do this more securely.
+Similarly, never expose `/var/run/docker.sock` to other containers as a volume, as it can be exploited.
+
+### Use Read-Only Volumes
+You can specify that a specific volume should be read-only by appending `:ro` to the `-v` switch. For example, while running Dashy, if we want our config to be writable, but keep all other assets protected, we would do:
+```
+docker run -d \
+ -p 8080:80 \
+ -v ~/dashy-conf.yml:/app/public/conf.yml \
+ -v ~/dashy-icons:/app/public/item-icons:ro \
+ -v ~/dashy-theme.scss:/app/src/styles/user-defined-themes.scss:ro \
+ lissy93/dashy:latest
+```
+
+You can also prevent a container from writing any changes to volumes on your host's disk, using the `--read-only` flag. Although, for Dashy, you will not be able to write config changes to disk, when edited through the UI with this method. You could make this work, by specifying the config directory as a temp write location, with `--tmpfs /app/public/conf.yml` - but that this will not write the volume back to your host.
+
+### Set the Logging Level
+Logging is important, as it enables you to review events in the future, and in the case of a compromise this will let get an idea of what may have happened. The default log level is `INFO`, and this is also the recommendation, use `--log-level info` to ensure this is set.
+
+### Verify Image before Pulling
+Only use trusted images, from verified/ official sources. If an app is open source, it is more likely to be safe, as anyone can verify the code. There are also tools available for scanning containers,
+
+Unless otherwise configured, containers can communicate among each other, so running one bad image may lead to other areas of your setup being compromised. Docker images typically contain both original code, as well as up-stream packages, and even if that image has come from a trusted source, the up-stream packages it includes may not have.
+
+### Specify the Tag
+Using fixed tags (as opposed to `:latest` ) will ensure immutability, meaning the base image will not change between builds. Note that for Dashy, the app is being actively developed, new features, bug fixes and general improvements are merged each week, and if you use a fixed version you will not enjoy these benefits. So it's up to you weather you would prefer a stable and reproducible environment, or the latest features and enhancements.
+
+### Container Security Scanning
+It's helpful to be aware of any potential security issues in any of the Docker images you are using. You can run a quick scan using Snyk on any image to output known vulnerabilities using [Docker scan](https://docs.docker.com/engine/scan/), e.g: `docker scan lissy93/dashy:latest`.
+
+A similar product is [Trivy](https://github.com/aquasecurity/trivy), which is free an open source. First install it (with your package manager), then to scan an image, just run: `trivy image lissy93/dashy:latest`
+
+For larger systems, RedHat [Clair](https://www.redhat.com/en/topics/containers/what-is-clair) is an app for parsing image contents and reporting on any found vulnerabilities. You run it locally in a container, and configure it with YAML. It can be integrated with Red Hat Quay, to show results on a dashboard. Most of these use static analysis to find potential issues, and scan included packages for any known security vulnerabilities.
+
+### Registry Security
+Although over-kill for most users, you could run your own registry locally which would give you ultimate control over all images, see the [Deploying a Registry Docs](https://docs.docker.com/registry/deploying/) for more info. Another option is [Docker Trusted Registry](https://docker-docs.netlify.app/ee/dtr/), it's great for enterprise applications, it sits behind your firewall, running on a swarm managed by Docker Universal Control Plane, and lets you securely store and manage your Docker images, mitigating the risk of breaches from the internet.
+
+### Security Modules
+Docker supports several modules that let you write your own security profiles.
+
+[AppArmor](https://www.apparmor.net/)is a kernel module that proactively protects the operating system and applications from external or internal threats, by enabling you to restrict programs' capabilities with per-program profiles. You can specify either a security policy by name, or by file path with the `apparmor` flag in docker run. Learn more about writing profiles, [here](https://gitlab.com/apparmor/apparmor/-/wikis/QuickProfileLanguage).
+
+[Seccomp](https://en.wikipedia.org/wiki/Seccomp) (Secure Computing Mode) is a sandboxing facility in the Linux kernel that acts like a firewall for system calls (syscalls). It uses Berkeley Packet Filter (BPF) rules to filter syscalls and control how they are handled. These filters can significantly limit a containers access to the Docker Hostâs Linux kernel - especially for simple containers/applications. It requires a Linux-based Docker host, with secomp enabled, and you can check for this by running `docker info | grep seccomp`. A great resource for learning more about this is [DockerLabs](https://training.play-with-docker.com/security-seccomp/).
+
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Web Server Configuration
+
+_The following section only applies if you are not using Docker, and would like to use your own web server_
+
+Dashy ships with a pre-configured Node.js server, in [`server.js`](https://github.com/Lissy93/dashy/blob/master/server.js) which serves up the contents of the `./dist` directory on a given port. You can start the server by running `node server`. Note that the app must have been build (run `yarn build`), and you need [Node.js](https://nodejs.org) installed.
+
+If you wish to run Dashy from a sub page (e.g. `example.com/dashy`), then just set the `BASE_URL` environmental variable to that page name (in this example, `/dashy`), before building the app, and the path to all assets will then resolve to the new path, instead of `./`.
+
+However, since Dashy is just a static web application, it can be served with whatever server you like. The following section outlines how you can configure a web server.
+
+Note, that if you choose not to use `server.js` to serve up the app, you will loose access to the following features:
+- Loading page, while the app is building
+- Writing config file to disk from the UI
+- Website status indicators, and ping checks
+
+Example Configs
+- [NGINX](#nginx)
+- [Apache](#apache)
+- [Caddy](#caddy)
+- [Firebase](#firebase-hosting)
+- [cPanel](#cpanel)
+
+### NGINX
+
+Create a new file in `/etc/nginx/sites-enabled/dashy`
+
+```
+server {
+ listen 80;
+ listen [::]:80;
+
+ root /var/www/dashy/html;
+ index index.html;
+
+ server_name your-domain.com www.your-domain.com;
+
+ location / {
+ try_files $uri $uri/ =404;
+ }
+}
+```
+
+To use HTML5 history mode (`appConfig.routingMode: history`), replace the inside of the location block with: `try_files $uri $uri/ /index.html;`.
+
+Then upload the build contents of Dashy's dist directory to that location.
+For example: `scp -r ./dist/* [username]@[server_ip]:/var/www/dashy/html`
+
+### Apache
+
+Copy Dashy's dist folder to your apache server, `sudo cp -r ./dashy/dist /var/www/html/dashy`.
+
+In your Apache config, `/etc/apche2/apache2.conf` add:
+```
+
+ Options Indexes FollowSymLinks
+ AllowOverride All
+ Require all granted
+
+
+
+ RewriteEngine On
+ RewriteBase /
+ RewriteRule ^index\.html$ - [L]
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+ RewriteRule . /index.html [L]
+
+```
+
+Add a `.htaccess` file within `/var/www/html/dashy/.htaccess`, and add:
+```
+Options -MultiViews
+RewriteEngine On
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^ index.html [QSA,L]
+```
+
+Then restart Apache, with `sudo systemctl restart apache2`
+
+### Caddy
+
+Caddy v2
+```
+try_files {path} /
+```
+
+Caddy v1
+```
+rewrite {
+ regexp .*
+ to {path} /
+}
+```
+
+### Firebase Hosting
+
+Create a file names `firebase.json`, and populate it with something similar to:
+
+```
+{
+ "hosting": {
+ "public": "dist",
+ "rewrites": [
+ {
+ "source": "**",
+ "destination": "/index.html"
+ }
+ ]
+ }
+}
+```
+
+### cPanel
+1. Login to your WHM
+2. Open 'Feature Manager' on the left sidebar
+3. Under 'Manage feature list', click 'Edit'
+4. Find 'Application manager' in the list, enable it and hit 'Save'
+5. Log into your users cPanel account, and under 'Software' find 'Application Manager'
+6. Click 'Register Application', fill in the form using the path that Dashy is located, and choose a domain, and hit 'Save'
+7. The application should now show up in the list, click 'Ensure dependencies', and move the toggle switch to 'Enabled'
+8. If you need to change the port, click 'Add environmental variable', give it the name 'PORT', choose a port number and press 'Save'.
+9. Dashy should now be running at your selected path an on a given port
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Running a Modified Version of the App
+
+If you'd like to make any code changes to the app, and deploy your modified version, this section briefly explains how.
+
+The first step is to fork the project on GitHub, and clone it to your local system. Next, install the dependencies (`yarn`), and start the development server (`yarn dev`) and visit `localhost:8080` in your browser. You can then make changes to the codebase, and see the live app update in real-time. Once you've finished, running `yarn build` will build the app for production, and output the assets into `./dist` which can then be deployed using a web server, CDN or the built-in Node server with `yarn start`. For more info on all of this, take a look at the [Developing Docs](/docs/developing). To build your own Docker container from the modified app, see [Building your Own Container](#building-your-own-container)
+
+**[âŦī¸ Back to Top](#)**
+
+---
+
+## Building your Own Container
+
+Similar to above, you'll first need to fork and clone Dashy to your local system, and then install dependencies.
+
+Then, either use Dashy's default [`Dockerfile`](https://github.com/Lissy93/dashy/blob/master/Dockerfile) as is, or modify it according to your needs.
+
+To build and deploy locally, first build the app with: `docker build -t dashy .`, and then start the app with `docker run -p 8080:80 --name my-dashboard dashy`. Or modify the `docker-compose.yml` file, replacing `image: lissy93/dashy` with `build: .` and run `docker compose up`.
+
+Your container should now be running, and will appear in the list when you run `docker container ls âa`. If you'd like to enter the container, run `docker exec -it [container-id] /bin/ash`.
+
+You may wish to upload your image to a container registry for easier access. Note that if you choose to do this on a public registry, please name your container something other than just 'dashy', to avoid confusion with the official image.
+You can push your build image, by running: `docker push ghcr.io/OWNER/IMAGE_NAME:latest`. You will first need to authenticate, this can be done by running `echo $CR_PAT | docker login ghcr.io -u USERNAME --password-stdin`, where `CR_PAT` is an environmental variable containing a token generated from your GitHub account. For more info, see the [Container Registry Docs](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry).
+
+**[âŦī¸ Back to Top](#)**
+
+---
diff --git a/docs/privacy.md b/docs/privacy.md
index 2ad02e05..de9a7cd9 100644
--- a/docs/privacy.md
+++ b/docs/privacy.md
@@ -1,5 +1,7 @@
# Privacy & Security
-Dashy was built with privacy in mind. Self-hosting your own apps and services is a great way to protect yourself from the mass data collection employed by big tech companies, and Dashy was designed to keep your local services organized and accessible from a single place.
+
+Dashy was built with privacy in mind.
+Self-hosting your own apps and services is a great way to protect yourself from the mass data collection employed by big tech companies, and Dashy was designed to keep your local services organized and accessible from a single place.
It's fully open source, and I've tried to keep to code as clear and thoroughly documented as possible, which will make it easy for you to understand exactly how it works, and what goes on behind the scenes.
@@ -8,7 +10,7 @@ For privacy and security tips, check out another project of mine: **[Personal Se
---
## External Requests
-By default, Dashy will not make any external requests, unless you configure it to. Some features (which are all off by default) do require internat access, and this section outlines those features, the services used, and links to their privacy policies.
+By default, Dashy will not make any external requests, unless you configure it to. Some features (which are off by default) do require internat access, and this section outlines those features, the services used, and links to their privacy policies.
### Font Awesome
If either any of your sections or items are using font-awesome icons, then these will be fetched directly from font-awesome on page load. See the [Font Awesome Privacy Policy](https://fontawesome.com/privacy) for more info.
@@ -43,6 +45,8 @@ Enabling anonymous error reporting helps me to discover bugs I was unaware of, a
If you need to monitor bugs yourself, then you can [self-host your own Sentry Server](https://develop.sentry.dev/self-hosted/), and use it by setting `appConfig.sentryDsn` to your Sentry instances [Data Source Name](https://docs.sentry.io/product/sentry-basics/dsn-explainer/), then just enable error reporting in Dashy.
+### Widgets
+
---
## Local Storage
@@ -79,7 +83,7 @@ As with most web projects, Dashy relies on several [dependencies](https://github
Dependencies can introduce security vulnerabilities, but since all these packages are open source any issues are usually very quickly spotted. Dashy is using Snyk for dependency security monitoring, and you can see [the latest report here](https://snyk.io/test/github/lissy93/dashy). If any issue is detected by Snyk, a note about it will appear at the top of the Reamde, and will usually be fixed within 48 hours.
-Note that packages listed under `deDependencies` section are only used for building the project, and are not included in the production environment.
+Note that packages listed under `devDependencies` section are only used for building the project, and are not included in the production environment.
---
diff --git a/docs/quick-start.md b/docs/quick-start.md
index 7f9a0824..33ebb237 100644
--- a/docs/quick-start.md
+++ b/docs/quick-start.md
@@ -25,7 +25,7 @@ docker run -d \
lissy93/dashy:latest
```
-Either replace the -v path to point to your config file, or leave it out. For a full list of available options, then see [Dashy with Docker](/docs/deployment#deploy-with-docker) Docs. If you'd prefer to use Docker Compose, then see [Dashy with Docker Compose](/docs/deployment#using-docker-compose) Docs. Alternate registries, architectures and pinned versions are also supported.
+Either replace the -v path to point to your config file, or leave it out. For a full list of available options, then see [Dashy with Docker](h/docs/deployment#deploy-with-docker) Docs. If you'd prefer to use Docker Compose, then see [Dashy with Docker Compose](/docs/deployment#using-docker-compose) Docs. Alternate registries, architectures and pinned versions are also supported.
Your dashboard should now be up and running at `http://localhost:8080` (or your servers IP address/ domain, and the port that you chose). The first time you build, it may take a few minutes.
@@ -80,7 +80,7 @@ Notes:
## 4. Further Customisation
-Once you've got Dashy setup, you'll want to ensure the container is properly healthy, secured, backed up and kept up-to-date. All this is covered in the [Management Docs](/docs/management).
+Once you've got Dashy setup, you'll want to ensure the container is properly healthy, secured, backed up and kept up-to-date. All this is covered in the [Management Docs](https://github.com/Lissy93/dashy/blob/master/docs/management).
You might also want to check out the docs for specific features you'd like to use:
@@ -97,12 +97,9 @@ You might also want to check out the docs for specific features you'd like to us
## 5. Final Note
-If you're enjoying Dashy, and have a few minutes to spare, please do take a moment to look at the [Contributing Page](/docs/contributing). There are a few things that we really need some help with, and whatever your skill set, there are ways you can help out. Any contributions, however small would be greatly appreciated.
-Thank you to [everyone](/docs/credits) who is already doing so, without developing and maintaining Dashy would not have been so possible.
+If you need any help or support in getting Dashy running, head over to the [Discussions](https://github.com/Lissy93/dashy/discussions) page. If you think you've found a bug, please do [raise it](https://github.com/Lissy93/dashy/issues/new/choose) so it can be fixed. For contact options, see the [Support Page](https://github.com/Lissy93/dashy/blob/master/.github/SUPPORT.md).
-You can also consider sharing your dashboard in the [Showcase](/docs/showcase), to help provide inspiration for others.
-
-If you're enjoying Dashy, and have a few minutes to spare, please do take a moment to look at the [Contributing Page](/docs/contributing). Huge thanks to [everyone](/docs/credits) who has already helped out!
+If you're enjoying Dashy, and have a few minutes to spare, please do take a moment to look at the [Contributing Page](/docs/contributing). Huge thanks to [everyone](https://github.com/Lissy93/dashy/blob/master/docs/credits.md) who has already helped out!
Enjoy your dashboard :)
@@ -126,7 +123,7 @@ Then edit `./public/conf.yml` and rebuild the app with `yarn build`
Don't have a server? No problem! You can run Dashy for free on Netlify (as well as many [other cloud providers](/docs/deployment#deploy-to-cloud-service)). All you need it a GitHub account.
1. Fork Dashy's repository on GitHub
-2. [Log in](https://app.netlify.com/login/) to Netlify with GitHub
+2. [Log in](app.netlify.com/login/) to Netlify with GitHub
3. Click "New site from Git" and select your forked repo, then click **Deploy**!
4. You can then edit the config in `./public/conf.yml` in your repo, and Netlify will rebuild the app
diff --git a/docs/readme.md b/docs/readme.md
index b0fccb64..bd63c98c 100644
--- a/docs/readme.md
+++ b/docs/readme.md
@@ -18,16 +18,17 @@
### Feature Docs
- [Authentication](/docs/authentication) - Guide to setting up authentication to protect your dashboard
- [Alternate Views](/docs/alternate-views) - Outline of available pages / views and item opening methods
-- [Backup & Restore](/docs/backup-restore) - Guide to Dashy's cloud sync feature
-- [Icons](/docs/icons) - Outline of all available icon types for sections and items
+- [Backup & Restore](/docs/backup-restore) - Guide to backing up config with Dashy's cloud sync feature
+- [Icons](/docs/icons) - Outline of all available icon types for sections and items, with examples
- [Language Switching](/docs/multi-language-support) - Details on how to switch language, or add a new locale
- [Status Indicators](/docs/status-indicators) - Using Dashy to monitor uptime and status of your apps
-- [Searching & Shortcuts](/docs/searching) - Finding and launching your apps, and using keyboard shortcuts
-- [Theming](/docs/theming) - Complete guide to applying, writing and modifying themes and styles
+- [Searching & Shortcuts](/docs/searching) - Searching, launching methods + keyboard shortcuts
+- [Theming](/docs/theming) - Complete guide to applying, writing and modifying themes + styles
+- [Widgets](/docs/widgets) - List of all dynamic content widgets, with usage guides and examples
### Misc
- [Privacy & Security](/docs/privacy) - List of requests, potential issues, and security resources
-- [License](/docs/license) - Copy of the MIT License
-- [Legal](https://github.com/Lissy93/dashy/blob/master/.github/LEGAL.md) - Licenses of direct dependencies
-- [Code of Conduct](https://github.com/Lissy93/dashy/blob/master/.github/CODE_OF_CONDUCT.md) - Contributor Covenant Code of Conduct
-- [Changelog](https://github.com/Lissy93/dashy/blob/master/.github/CHANGELOG.md) - Details of recent changes, and historical versions
+- [License](/LICENSE) - Copy of the MIT License
+- [Legal](/.github/LEGAL) - Licenses of direct dependencies
+- [Code of Conduct](/.github/CODE_OF_CONDUCT) - Contributor Covenant Code of Conduct
+- [Changelog](/.github/CHANGELOG) - Details of recent changes, and historical versions
diff --git a/docs/showcase.md b/docs/showcase.md
index f8cd4c12..b9eeb868 100644
--- a/docs/showcase.md
+++ b/docs/showcase.md
@@ -1,132 +1,171 @@
-# User Showcase
-
-| đ Do you use Dashy? Got a sweet dashboard? Submit it to the showcase! đ [See How](#submitting-your-dashboard) |
-|-|
-
-### Home Lab 2.0
-
-![screenshot-homelab](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png)
-
----
-
-### Networking Services
-> By [@Lissy93](https://github.com/lissy93)
-
-![screenshot-networking-services](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/2-networking-services-minimal-dark.png)
-
----
-
-### Homelab & VPS dashboard
-> By [@shadowking001](https://github.com/shadowking001)
-
-![screenshot-shadowking001-dashy](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/8-shadowking001s-dashy.png)
-
----
-
-### EVO Dashboard
-
-> By [@EVOTk](https://github.com/EVOTk)
-
-![screenshot-evo-dashboard](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/12-evo-dashboard.png)
-
----
-
-### NAS Home Dashboard
-> By [@cerealconyogurt](https://github.com/cerealconyogurt)
-
-![screenshot-networking-services](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/6-nas-home-dashboard.png)
-
----
-
-### Dashy Live
-> By [@Lissy93](https://github.com/lissy93)
-
-> A dashboard I made to manage all project development links from one place. View demo at [live.dashy.to](https://live.dashy.to/).
-
-![screenshot-dashy-live](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/10-dashy-live.png)
-
-### CFT Toolbox
-
-![screenshot-cft-toolbox](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/3-cft-toolbox.png)
-
----
-
-### Bookmarks
-
-![screenshot-bookmarks](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/4-bookmarks-colourful.png)
-
----
-
-### Project Management
-
-![screenshot-project-managment](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/5-project-managment.png)
-
----
-
-### Dashy Example
-
-> An example dashboard, by [@Lissy93](https://github.com/lissy93). View live at [demo.dashy.to](https://demo.dashy.to/).
-
-![screenshot-dashy-example](https://i.ibb.co/YbzqPK7/demo-dashy.png)
-
----
-
-### First Week of Self-Hosting
-> By [u//RickyCZ](https://www.reddit.com/user/RickyCZ)
-
-![screenshot-week-of-self-hosting](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/11-ricky-cz.png)
-
----
-
-### HomeLAb 3.0
-
-> By [@skoogee](https://github.com/skoogee) (http://zhrn.cc)
-
-> Dashy, is the most complete dashboard I ever tried, has all the features, and it sets itself apart from the rest. It is my default homepage now. I am thankful to the developer @Lissy93 for sharing such a wonderful creation.
-
-[![screenshot-12-skoogee-homelab-3](https://i.ibb.co/F5yBTsT/12-skoogee-homelab-3.png)](https://ibb.co/album/ynSwzm)
-
----
-
-### Ground Control
-> By [@dtctek](https://github.com/dtctek)
-
-![screenshot-ground-control](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/7-ground-control-dtctek.png)
-
----
-
-### Yet Another Homelab
-
-![screenshot-yet-another-homelab](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/9-home-lab-oblivion.png)
-
----
-
-## Submitting your Dashboard
-
-#### How to Submit
-- [Open an Issue](https://git.io/JEtgM)
-- [Open a PR](https://github.com/Lissy93/dashy/compare)
-
-#### What to Include
-Please include the following information:
-- A single high-quality screenshot of your Dashboard
-- A short title (it doesn't have to be particularly imaginative)
-- An optional description, you could include details on anything interesting or unique about your dashboard, or say how you use it, and why it's awesome
-- Optionally leave your name or username, with a link to your GitHub, Twitter or Website
-
-#### Template
-
-If you're submitting a pull request, please use a format similar to this:
-
-```
-### [Dashboard Name] (required)
-
-> Submitted by [@username](https://github.com/user) (optional)
-
-![dashboard-screenshot](/docs/showcase/screenshot-name.jpg) (required)
-
-[An optional text description, or any interesting details] (optional)
-
----
-
-```
+# *Dashy Showcase* đ
+
+| đ Got a sweet dashboard? Submit it to the showcase! đ [See How](#submitting-your-dashboard) |
+|-|
+
+### Home Lab 2.0
+
+![screenshot-homelab](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/1-home-lab-material.png)
+
+---
+
+### Ratty222
+> By [@ratty222](https://github.com/ratty222) [#384](https://github.com/Lissy93/dashy/discussions/384)
+
+![screenshot-ratty222-dashy](https://user-images.githubusercontent.com/1862727/147582551-4c655d37-8bcc-4f95-ab41-164a9d0d6a07.png)
+
+---
+
+### Networking Services
+> By [@Lissy93](https://github.com/lissy93)
+
+![screenshot-networking-services](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/2-networking-services-minimal-dark.png)
+
+---
+
+### Homelab & VPS dashboard
+> By [@shadowking001](https://github.com/shadowking001)
+
+![screenshot-shadowking001-dashy](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/8-shadowking001s-dashy.png)
+
+---
+
+### EVO Dashboard
+
+> By [@EVOTk](https://github.com/EVOTk)
+
+![screenshot-evo-dashboard](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/12-evo-dashboard.png)
+
+---
+
+### The Private Dashboard
+
+> By [@DylanBeMe](https://github.com/DylanBeMe) [#419](https://github.com/Lissy93/dashy/issues/419)
+
+![screenshot-evo-dashboard](https://i.ibb.co/hKS483T/private-dashboard-Dylan-Be-Me.png)
+
+---
+
+### NAS Home Dashboard
+> By [@cerealconyogurt](https://github.com/cerealconyogurt)
+
+![screenshot-networking-services](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/6-nas-home-dashboard.png)
+
+---
+
+### Dashy Live
+> By [@Lissy93](https://github.com/lissy93)
+
+> A dashboard I made to manage all project development links from one place. View demo at [live.dashy.to](https://live.dashy.to/).
+
+![screenshot-dashy-live](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/10-dashy-live.png)
+
+---
+
+### System Monitor
+> An aggregated board for monitoring system resource usage from a single view
+
+![screenshot-monitor](https://i.ibb.co/xfK6BGb/system-monitor-board.png)
+
+---
+
+### CFT Toolbox
+
+![screenshot-cft-toolbox](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/3-cft-toolbox.png)
+
+---
+
+### Bookmarks
+
+![screenshot-bookmarks](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/4-bookmarks-colourful.png)
+
+---
+
+### Project Management
+
+![screenshot-project-managment](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/5-project-managment.png)
+
+---
+
+### Dashy Example
+
+> An example dashboard, by [@Lissy93](https://github.com/lissy93). View live at [demo.dashy.to](https://demo.dashy.to/).
+
+![screenshot-dashy-example](https://i.ibb.co/YbzqPK7/demo-dashy.png)
+
+---
+
+### First Week of Self-Hosting
+> By [u//RickyCZ](https://www.reddit.com/user/RickyCZ)
+
+![screenshot-week-of-self-hosting](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/11-ricky-cz.png)
+
+---
+
+### HomeLAb 3.0
+
+> By [@skoogee](https://github.com/skoogee) (http://zhrn.cc)
+
+> Dashy, is the most complete dashboard I ever tried, has all the features, and it sets itself apart from the rest. It is my default homepage now. I am thankful to the developer @Lissy93 for sharing such a wonderful creation.
+
+[![screenshot-12-skoogee-homelab-3](https://i.ibb.co/F5yBTsT/12-skoogee-homelab-3.png?)](https://ibb.co/album/ynSwzm)
+
+---
+
+### Ground Control
+> By [@dtctek](https://github.com/dtctek)
+
+![screenshot-ground-control](https://user-images.githubusercontent.com/1862727/149821995-e9b41dab-186c-42e6-b5b3-e233259b241d.png)
+
+---
+
+### Morning Dashboard
+> Displayed on my smart screen between 05:00 - 08:00, and includes all the info that I usually check before leaving for work
+
+![screenshot-morning-dash](https://i.ibb.co/4Wx8zb7/morning-dashboard.png)
+
+---
+
+### Crypto Dash
+> Example usage of widgets to monitor cryptocurrencies news, prices and data. Config is [available here](https://gist.github.com/Lissy93/000f712a5ce98f212817d20bc16bab10#file-example-8-dashy-crypto-widgets-conf-yml)
+
+
+![screenshot-crypto-dash](https://user-images.githubusercontent.com/1862727/147394584-352fe3bf-740d-4624-a01b-9003a97bc832.png)
+
+---
+
+### Yet Another Homelab
+
+![screenshot-yet-another-homelab](https://raw.githubusercontent.com/Lissy93/dashy/master/docs/showcase/9-home-lab-oblivion.png)
+
+---
+
+## Submitting your Dashboard
+
+#### How to Submit
+- [Open an Issue](https://git.io/JEtgM)
+- [Open a PR](https://github.com/Lissy93/dashy/compare)
+
+#### What to Include
+Please include the following information:
+- A single high-quality screenshot of your Dashboard
+- A short title (it doesn't have to be particularly imaginative)
+- An optional description, you could include details on anything interesting or unique about your dashboard, or say how you use it, and why it's awesome
+- Optionally leave your name or username, with a link to your GitHub, Twitter or Website
+
+#### Template
+
+If you're submitting a pull request, please use a format similar to this:
+
+```
+### [Dashboard Name] (required)
+
+> Submitted by [@username](https://github.com/user) (optional)
+
+[An optional text description, or any interesting details] (optional)
+
+![dashboard-screenshot](https://example.com/url-to-screenshot.png) (required)
+
+---
+
+```
diff --git a/docs/theming.md b/docs/theming.md
index dd276388..8ae58b51 100644
--- a/docs/theming.md
+++ b/docs/theming.md
@@ -1,4 +1,4 @@
-# Theming
+## Theming
By default Dashy comes with 20 built in themes, which can be applied from the dropwodwn menu in the UI
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
index 8dcdb1a3..00b78f2b 100644
--- a/docs/troubleshooting.md
+++ b/docs/troubleshooting.md
@@ -1,6 +1,29 @@
# Troubleshooting
-This document contains common problems and their solutions.
+> _**This document contains common problems and their solutions.**_
+>
+> _If you came across an issue where the solution was not immediately obvious, consider adding it to this list to help other users._
+
+### Contents
+- [Refused to Connect in Web Content View](#refused-to-connect-in-modal-or-workspace-view)
+- [404 On Static Hosting](#404-on-static-hosting)
+- [Yarn Build or Run Error](#yarn-error)
+- [Auth Validation Error: "should be object"](#auth-validation-error-should-be-object)
+- [Config Not Updating](#config-not-updating)
+- [Config Still not Updating](#config-still-not-updating)
+- [Styles and Assets not Updating](#styles-and-assets-not-updating)
+- [DockerHub toomanyrequests](#dockerhub-toomanyrequests)
+- [Config Validation Errors](#config-validation-errors)
+- [Node Sass unsupported environment](#node-sass-does-not-yet-support-your-current-environment)
+- [Cannot find module './_baseValues'](#error-cannot-find-module-_basevalues)
+- [Ngrok Invalid Host Headers](#invalid-host-header-while-running-through-ngrok)
+- [Warnings in the Console during deploy](#warnings-in-the-console-during-deploy)
+- [Docker Login Fails on Ubuntu](#docker-login-fails-on-ubuntu)
+- [Status Checks Failing](#status-checks-failing)
+- [How-To Open Browser Console](#how-to-open-browser-console)
+- [Git Contributions not Displaying](#git-contributions-not-displaying)
+
+---
## `Refused to Connect` in Modal or Workspace View
This is not an issue with Dashy, but instead caused by the target app preventing direct access through embedded elements. It can be fixed by setting the [`X-Frame-Options`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) HTTP header set to `ALLOW [path to Dashy]` or `SAMEORIGIN`, as defined in [RFC-7034](https://datatracker.ietf.org/doc/html/rfc7034). These settings are usually set in the config file for the web server that's hosting the target application, here are some examples of how to enable cross-origin access with common web servers:
@@ -35,6 +58,16 @@ Header set X-Frame-Options: "ALLOW-FROM http://[dashy-location]/"
---
+## 404 On Static Hosting
+
+If you're seeing Dashy's 404 page on initial load/ refresh, and then the main app when you go back to Home, then this is likely caused by the Vue router, and if so can be fixed in one of two ways.
+
+The first solution is to switch the routing mode, from HTML5 `history` mode to `hash` mode, by setting `appConfig.routingMode` to `hash`.
+
+If this works, but you wish to continue using HTML5 history mode, then a bit of extra [server configuration](/docs/management#web-server-configuration) is required. This is explained in more detaail in the [Vue Docs](https://router.vuejs.org/guide/essentials/history-mode.html). Once completed, you can then use `routingMode: history` again, for neater URLs.
+
+---
+
## Yarn Error
For more info, see [Issue #1](https://github.com/Lissy93/dashy/issues/1)
@@ -180,4 +213,33 @@ Currently, the status check needs a page to be rendered, so if this URL in your
For further troubleshooting, use an application like [Postman](https://postman.com) to diagnose the issue. Set the parameter to `GET`, and then make a call to: `https://[url-of-dashy]/status-check/?&url=[service-url]`. Where the service URL must have first been encoded (e.g. with `encodeURIComponent()` or [urlencoder.io](https://www.urlencoder.io/))
-If you're serving Dashy though a CDN, instead of using the Node server or Docker image, then the Node endpoint that makes requests will not be available to you, and all requests will fail. A workaround for this may be implemented in the future, but in the meantime, your only option is to use the Docker or Node deployment method.
\ No newline at end of file
+If you're serving Dashy though a CDN, instead of using the Node server or Docker image, then the Node endpoint that makes requests will not be available to you, and all requests will fail. A workaround for this may be implemented in the future, but in the meantime, your only option is to use the Docker or Node deployment method.
+
+---
+
+## How-To Open Browser Console
+When raising a bug, one crucial piece of info needed is the browser's console output. This will help the developer diagnose and fix the issue.
+
+If you've been asked for this info, but are unsure where to find it, then it is under the "Console" tab, in the browsers developer tools, which can be opened with F12 . You can right-click the console, and select Save As to download the log.
+
+To open dev tools, and jump straight to the console:
+- Win / Linux: Ctrl + Shift + J
+- MacOS: Cmd + Option + J
+
+For more detailed walk through, see [this article](https://support.shortpoint.com/support/solutions/articles/1000222881-save-browser-console-file).
+
+---
+
+## Git Contributions not Displaying
+
+If you've contributed to Dashy (or any other project), but your contributions are not showing up on your GH profile, or in Dashy's [Credits Page](https://github.com/Lissy93/dashy/blob/master/docs/credits.md), then this is likely a git config issue.
+
+These statistics are generated using the username / email associated with commits. This info needs to be setup on your local machine using [`git config`](https://git-scm.com/docs/git-config).
+
+Run the following commands (replacing name + email with your info):
+- `git config --global user.name "John Doe"`
+- `git config --global user.email johndoe@example.com`
+
+For more info, see [Git First Time Setup Docs](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup).
+
+Note that only contributions to the master / main branch or a project are counted
diff --git a/docs/widgets.md b/docs/widgets.md
new file mode 100644
index 00000000..851f1163
--- /dev/null
+++ b/docs/widgets.md
@@ -0,0 +1,1708 @@
+# Widgets
+
+Dashy has support for displaying dynamic content in the form of widgets. There are several built-in widgets available out-of-the-box as well as support for custom widgets to display stats from almost any service with an API.
+
+> âšī¸ **Note**: Widgets are still in the Alpha-phase of development.
+> If you find a bug, please raise it.
+> Adding / editing widgets through the UI isn't yet supported, you will need to do this in the YAML config file.
+
+##### Contents
+- **[General Widgets](#general-widgets)**
+ - [Clock](#clock)
+ - [Weather](#weather)
+ - [Weather Forecast](#weather-forecast)
+ - [RSS Feed](#rss-feed)
+ - [Public IP Address](#public-ip)
+ - [Crypto Watch List](#crypto-watch-list)
+ - [Crypto Price History](#crypto-token-price-history)
+ - [Crypto Wallet Balance](#wallet-balance)
+ - [Code Stats](#code-stats)
+ - [Email Aliases (AnonAddy)](#anonaddy)
+ - [Vulnerability Feed](#vulnerability-feed)
+ - [Exchange Rates](#exchange-rates)
+ - [Public Holidays](#public-holidays)
+ - [Covid-19 Status](#covid-19-status)
+ - [Sports Scores](#sports-scores)
+ - [News Headlines](#news-headlines)
+ - [TFL Status](#tfl-status)
+ - [Stock Price History](#stock-price-history)
+ - [ETH Gas Prices](#eth-gas-prices)
+ - [Joke of the Day](#joke)
+ - [XKCD Comics](#xkcd-comics)
+ - [Flight Data](#flight-data)
+ - [NASA APOD](#astronomy-picture-of-the-day)
+ - [GitHub Trending](#github-trending)
+ - [GitHub Profile Stats](#github-profile-stats)
+- **[Self-Hosted Services Widgets](#self-hosted-services-widgets)**
+ - [System Info](#system-info)
+ - [Cron Monitoring](#cron-monitoring-health-checks)
+ - [CPU History](#cpu-history-netdata)
+ - [Memory History](#memory-history-netdata)
+ - [System Load History](#load-history-netdata)
+ - [Pi Hole Stats](#pi-hole-stats)
+ - [Pi Hole Queries](#pi-hole-queries)
+ - [Recent Traffic](#recent-traffic)
+ - [Stat Ping Statuses](#stat-ping-statuses)
+- **[System Resource Monitoring](#system-resource-monitoring)**
+ - [CPU Usage Current](#current-cpu-usage)
+ - [CPU Usage Per Core](#cpu-usage-per-core)
+ - [CPU Usage History](#cpu-usage-history)
+ - [Memory Usage Current](#current-memory-usage)
+ - [Memory Usage History](#memory-usage-history)
+ - [Disk Space](#disk-space)
+ - [Disk IO](#disk-io)
+ - [System Load](#system-load)
+ - [System Load History](#system-load-history)
+ - [Network Interfaces](#network-interfaces)
+ - [Network Traffic](#network-traffic)
+ - [Resource Usage Alerts](#resource-usage-alerts)
+- **[Dynamic Widgets](#dynamic-widgets)**
+ - [Iframe Widget](#iframe-widget)
+ - [HTML Embed Widget](#html-embedded-widget)
+ - [API Response](#api-response)
+ - [Prometheus Data](#prometheus-data)
+ - [Data Feed](#data-feed)
+- **[Usage & Customizations](#usage--customizations)**
+ - [Widget Usage Guide](#widget-usage-guide)
+ - [Continuous Updates](#continuous-updates)
+ - [Proxying Requests](#proxying-requests)
+ - [Custom CSS Styling](#widget-styling)
+ - [Customizing Charts](#customizing-charts)
+ - [Language Translations](#language-translations)
+ - [Widget UI Options](#widget-ui-options)
+ - [Building a Widget](#build-your-own-widget)
+ - [Requesting a Widget](#requesting-a-widget)
+
+## General Widgets
+
+### Clock
+
+A simple, live-updating time and date widget with time-zone support. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`timeZone`** | `string` | _Optional_ | The time zone to display date and time in. Specified as Region/City, for example: `Australia/Melbourne`. See the [Time Zone DB](https://timezonedb.com/time-zones) for a full list of supported TZs. Defaults to the browser / device's local time
+**`format`** | `string` | _Optional_ | A country code for displaying the date and time in local format. Specified as `[ISO-3166]-[ISO-639]`, for example: `en-AU`. See [here](https://www.fincher.org/Utilities/CountryLanguageList.shtml) for a full list of locales. Defaults to the browser / device's region
+**`customCityName`** | `string` | _Optional_ | By default the city from the time-zone is shown, but setting this value will override that text
+**`hideDate`** | `boolean` | _Optional_ | If set to `true`, the date and city will not be shown. Defaults to `false`
+
+##### Example
+
+```yaml
+- type: clock
+ options:
+ timeZone: Europe/London
+ format: en-GB
+ hideDate: false
+```
+
+##### Info
+_No external data requests_
+
+---
+
+### Weather
+
+A simple, live-updating local weather component, showing temperature, conditions and more info.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | Your OpenWeatherMap API key. You can get one for free at [openweathermap.org](https://openweathermap.org/)
+**`city`** | `string` | Required | A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
+**`units`** | `string` | _Optional_ | The units to use for displaying data, can be either `metric` or `imperial`. Defaults to `metric`
+**`hideDetails`** | `boolean` | _Optional_ | If set to `true`, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to `false`
+
+##### Example
+
+```yaml
+- type: weather
+ options:
+ apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ city: London
+ units: metric
+ hideDetails: false
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan
+- **Privacy**: _See [OWM Privacy Policy](https://openweather.co.uk/privacy-policy)_
+
+---
+
+### Weather Forecast
+
+Displays the weather (temperature and conditions) for the next few days for a given location. Note that this requires either the free [OpenWeatherMap Student Plan](https://home.openweathermap.org/students), or the Premium Plan.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | Your OpenWeatherMap API key. You can get one at [openweathermap.org](https://openweathermap.org/) or for free via the [OWM Student Plan](https://home.openweathermap.org/students)
+**`city`** | `string` | Required | A city name to use for fetching weather. This can also be a state code or country code, following the ISO-3166 format
+**`numDays`** | `number` | _Optional_ | The number of days to display of forecast info to display. Defaults to `4`, max `16` days
+**`units`** | `string` | _Optional_ | The units to use for displaying data, can be either `metric` or `imperial`. Defaults to `metric`
+**`hideDetails`** | `boolean` | _Optional_ | If set to `true`, the additional details (wind, humidity, pressure, etc) will not be shown. Defaults to `false`
+
+##### Example
+
+```yaml
+- type: weather-forecast
+ options:
+ city: California
+ numDays: 6
+ apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ units: imperial
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ´ Premium (free for personal use only)
+- **Privacy**: _See [OWM Privacy Policy](https://openweather.co.uk/privacy-policy)_
+
+---
+
+### RSS Feed
+
+Display news and updates from any RSS-enabled service.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`rssUrl`** | `string` | Required | The URL location of your RSS feed
+**`apiKey`** | `string` | _Optional_ | An API key for [rss2json](https://rss2json.com/). It's free, and will allow you to make 10,000 requests per day, you can sign up [here](https://rss2json.com/sign-up)
+**`limit`** | `number` | _Optional_ | The number of posts to return. If you haven't specified an API key, this will be limited to 10
+**`orderBy`** | `string` | _Optional_ | How results should be sorted. Can be either `pubDate`, `author` or `title`. Defaults to `pubDate`
+**`orderDirection`** | `string` | _Optional_ | Order direction of feed items to return. Can be either `asc` or `desc`. Defaults to `desc`
+
+##### Example
+
+```yaml
+- type: rss-feed
+ options:
+ rssUrl: https://www.schneier.com/blog/atom.xml
+ apiKey: xxxx
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ Optional
+- **Price**: đ Free Plan (up to 10,000 requests / day)
+- **Privacy**: _See [Rss2Json Privacy Policy](https://rss2json.com/privacy-policy)_
+
+---
+
+### Public IP
+
+Often find yourself searching "What's my IP", just so you can check your VPN is still connected? This widget displays your public IP address, along with ISP name and approx location. Data is fetched from [IP-API.com](https://ip-api.com/).
+
+
+
+##### Options
+
+_No config options._
+
+##### Example
+
+```yaml
+- type: public-ip
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ Optional
+- **Price**: đĸ Free
+- **Host**: Managed Instance Only
+- **Privacy**: _See [IP-API Privacy Policy](https://ip-api.com/docs/legal)_
+
+---
+
+### Crypto Watch List
+
+Keep track of price changes of your favorite crypto assets. Data is fetched from [CoinGecko](https://www.coingecko.com/). All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`assets`** | `string` | _Optional_ | An array of cryptocurrencies, coins and tokens. See [list of supported assets](https://api.coingecko.com/api/v3/asset_platforms). If none are specified, then the top coins by `sortBy` (defaults to market cap) will be returned
+**`currency`** | `string` | _Optional_ | The fiat currency to display price in, expressed as an ISO-4217 alpha code (see [list of currencies](https://www.iban.com/currency-codes)). Defaults to `USD`
+**`sortBy`** | `string` | _Optional_ | The method of sorting results. Can be `marketCap`, `volume` or `alphabetical`. Defaults to `marketCap`.
+**`limit`** | `number` | _Optional_ | Number of results to return, useful when no assets are specified. Defaults to either `all` or `100`
+
+##### Example
+
+```yaml
+- type: crypto-watch-list
+ options:
+ limit: 10
+```
+
+Or
+
+```yaml
+ - type: crypto-watch-list
+ options:
+ currency: GBP
+ sortBy: marketCap
+ assets:
+ - bitcoin
+ - ethereum
+ - monero
+ - cosmos
+ - polkadot
+ - dogecoin
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Privacy**: _See [CoinGecko Privacy Policy](https://www.coingecko.com/en/privacy)_
+
+---
+
+### Crypto Token Price History
+
+Shows recent price history for a given crypto asset, using price data fetched from [CoinGecko](https://www.coingecko.com/)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`asset`** | `string` | Required | Name of a crypto asset, coin or token to fetch price data for, see [list of supported assets](https://api.coingecko.com/api/v3/asset_platforms)
+**`currency`** | `string` | _Optional_ | The fiat currency to display results in, expressed as an ISO-4217 alpha code (see [list of currencies](https://www.iban.com/currency-codes)). Defaults to `USD`
+**`numDays`** | `number` | _Optional_ | The number of days of price history to render. Defaults to `7`, min: `1`, max: `30` days
+**`chartColor`** | `string` | _Optional_ | Color of the chart value. Defaults to `--widget-text-color` which inherits dashboard primary color
+**`chartHeight`** | `number` | _Optional_ | The height of rendered chart in px. Defaults to `300`
+
+##### Example
+
+```yaml
+- type: crypto-price-chart
+ options:
+ asset: bitcoin
+ currency: GBP
+ numDays: 7
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Privacy**: _See [CoinGecko Privacy Policy](https://www.coingecko.com/en/privacy)_
+
+---
+
+### Wallet Balance
+
+Keep track of your crypto balances and see recent transactions. Data is fetched from [BlockCypher](https://www.blockcypher.com/dev/)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`coin`** | `string` | Required | Symbol of coin or asset, e.g. `btc`, `eth` or `doge`
+**`address`** | `string` | Required | Address to monitor. This is your wallet's **public** / receiving address
+**`network`** | `string` | _Optional_ | To use a different network, other than mainnet. Defaults to `main`
+**`limit`** | `number` | _Optional_ | Limit the number of transactions to display. Defaults to `10`, set to large number to show all
+
+##### Example
+
+```yaml
+- type: wallet-balance
+ options:
+ coin: btc
+ address: 3853bSxupMjvxEYfwGDGAaLZhTKxB2vEVC
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Privacy**: _See [BlockCypher Privacy Policy](https://www.blockcypher.com/privacy.html)_
+
+---
+
+### Code Stats
+
+Display your coding summary. [Code::Stats](https://codestats.net/) is a free and open source app that aggregates statistics about your programming activity. Dashy supports both the public instance, as well as self-hosted versions.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`username`** | `string` | Required | Your CodeStats username
+**`hostname`** | `string` | _Optional_ | If your self-hosting CodeStats, then supply the host name. By default it will use the public hosted instance
+**`monthsToShow`** | `number` | _Optional_ | Specify the number of months to render in the historical data chart. Defaults to `6`
+**`hideMeta`** | `boolean` | _Optional_ | Optionally hide the meta section (username, level, all-time and recent XP)
+**`hideHistory`** | `boolean` | _Optional_ | Optionally hide the historical calendar heat map
+**`hideLanguages`** | `boolean` | _Optional_ | Optionally hide the programming languages pie chart
+**`hideMachines`** | `boolean` | _Optional_ | Optionally hide the machines percentage chart
+
+##### Example
+
+```yaml
+- type: code-stats
+ options:
+ username: alicia
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted or Managed
+- **Privacy**: _See [Code::Stats Privacy Policy](https://codestats.net/tos#privacy)_
+
+---
+
+### AnonAddy
+
+[AnonAddy](https://anonaddy.com/) is a free and open source mail forwarding service. Use it to protect your real email address, by using a different alias for each of your online accounts, and have all emails land in your normal inbox(es). Supports custom domains, email replies, PGP-encryption, multiple recipients and more
+
+This widget display email addresses / aliases from AnonAddy. Click an email address to copy to clipboard, or use the toggle switch to enable/ disable it. Shows usage stats (bandwidth, used aliases etc), as well as total messages recieved, blocked and sent. Works with both self-hosted and managed instances of AnonAddy.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | Your AnonAddy API Key / Personal Access Token. You can generate this under [Account Settings](https://app.anonaddy.com/settings)
+**`hostname`** | `string` | _Optional_ | If your self-hosting AnonAddy, then supply the host name. By default it will use the public hosted instance
+**`apiVersion`** | `string` | _Optional_ | If you're using an API version that is not version `v1`, then specify it here
+**`limit`** | `number` | _Optional_ | Limit the number of emails shown per page. Defaults to `10`
+**`sortBy`** | `string` | _Optional_ | Specify the sort order for email addresses. Defaults to `updated_at`. Can be either: `local_part`, `domain`, `email`, `emails_forwarded`, `emails_blocked`, `emails_replied`, `emails_sent`, `created_at`, `updated_at` or `deleted_at`. Precede with a `-` character to reverse order.
+**`searchTerm`** | `string` | _Optional_ | A search term to filter results by, will search the email, description and domain
+**`disableControls`** | `boolean` | _Optional_ | Prevent any changes being made to account through the widget. User will not be able to enable or disable aliases through UI when this option is set
+**`hideMeta`** | `boolean` | _Optional_ | Don't show account meta info (forward/ block count, quota usage etc)
+**`hideAliases`** | `boolean` | _Optional_ | Don't show email address / alias list. Will only show account meta info
+
+##### Example
+
+```yaml
+ - type: anonaddy
+ options:
+ apiKey: "xxxxxxxxxxxxxxxxxxxxxxxx\
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ limit: 5
+ sortBy: created_at
+ disableControls: true
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free for Self-Hosted / Free Plan available on managed instance or $1/month for premium
+- **Host**: Self-Hosted or Managed
+- **Privacy**: _See [AnonAddy Privacy Policy](https://anonaddy.com/privacy/)_
+
+---
+
+### Vulnerability Feed
+
+Keep track of recent security advisories and vulnerabilities, with optional filtering by score, exploits, vendor and product. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`sortBy`** | `string` | _Optional_ | The sorting method. Can be either `publish-date`, `last-update` or `cve-code`. Defaults to `publish-date`
+**`limit`** | `number` | _Optional_ | The number of results to fetch. Can be between `5` and `30`, defaults to `10`
+**`minScore`** | `number` | _Optional_ | If set, will only display results with a CVE score higher than the number specified. Can be a number between `0` and `9.9`. By default, vulnerabilities of all CVE scores are shown
+**`hasExploit`** | `boolean` | _Optional_ | If set to `true`, will only show results with active exploits. Defaults to `false`
+**`vendorId`** | `number` | _Optional_ | Only show results from a specific vendor, specified by ID. See [Vendor Search](https://www.cvedetails.com/vendor-search.php) for list of vendors. E.g. `23` (Debian), `26` (Microsoft), `23682` (CloudFlare)
+**`productId`** | `number` | _Optional_ | Only show results from a specific app or product, specified by ID. See [Product Search](https://www.cvedetails.com/product-search.php) for list of products. E.g. `13534` (Docker), `15913` (NextCloud), `19294` (Portainer), `17908` (ProtonMail)
+
+
+##### Example
+
+```yaml
+- type: cve-vulnerabilities
+```
+
+or
+
+```yaml
+- type: cve-vulnerabilities
+ options:
+ sortBy: publish-date
+ productId: 28125
+ hasExploit: true
+ minScore: 5
+ limit: 30
+```
+
+##### Info
+- **CORS**: đ Proxied
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed
+- **Privacy**: _See [CVE Details Privacy Policy](https://www.cvedetails.com/privacy.php)_
+
+---
+
+### Exchange Rates
+
+Display current FX rates in your native currency. Hover over a row to view more info, or click to show rates in that currency.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`inputCurrency`** | `string` | Required | The base currency to show results in. Specified as a 3-letter ISO-4217 code, see [here](https://www.exchangerate-api.com/docs/supported-currencies) for the full list of supported currencies, and their symbols
+**`outputCurrencies`** | `array` | Required | List or currencies to show results for. Specified as a 3-letter ISO-4217 code, see [here](https://www.exchangerate-api.com/docs/supported-currencies) for the full list of supported currencies, and their symbols
+**`apiKey`** | `string` | Required | API key for [exchangerate-api.com](https://www.exchangerate-api.com/), usually a 24-digit alpha-numeric string. You can sign up for a free account [here](https://app.exchangerate-api.com/sign-up)
+
+##### Example
+
+```yaml
+- type: exchange-rates
+ options:
+ apiKey: xxxxxxxxxxxxxxxxxxxxxxxx
+ inputCurrency: GBP
+ outputCurrencies:
+ - USD
+ - JPY
+ - HKD
+ - KPW
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan (upto 100,000 requests/ month)
+- **Host**: Managed Instance Only
+- **Privacy**: _See [ExchangeRateAPI Privacy Policy](https://www.exchangerate-api.com/terms)_
+
+---
+
+### Public Holidays
+
+Counting down to the next day off work? This widget displays upcoming public holidays for your country. Data is fetched from [Enrico](http://kayaposoft.com/enrico/)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`country`** | `string` | Required | The region to fetch holiday data for, specified as a country code, e.g. `GB` or `US`
+**`holidayType`** | `string` | __Optional__ | The type of holidays to fetch. Can be: `all`, `public_holiday`, `observance`, `school_holiday`, `other_day` or `extra_working_day`. Defaults to `public_holiday`
+**`monthsToShow`** | `number` | __Optional__ | The number of months in advance to show. Min: `1`, max: `24`. Defaults to `12`
+
+##### Example
+
+```yaml
+- type: public-holidays
+ options:
+ country: GB
+ holidayType: all
+ monthsToShow: 12
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [jurajmajer/enrico](https://github.com/jurajmajer/enrico)) or Managed
+- **Privacy**: âĢ No Policy Available
+
+---
+
+### Covid-19 Status
+
+Keep track of the current COVID-19 status. Optionally also show cases by country, and a time-series chart. Uses live data from various sources, computed by [disease.sh](https://disease.sh/)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`showChart`** | `boolean` | _Optional_ | Also display a time-series chart showing number of recent cases
+**`showCountries`** | `boolean` | _Optional_ | Also display a list of cases per country
+**`numDays`** | `number` | _Optional_ | Specify number of days worth of history to render on the chart
+**`countries`** | `string[]` | _Optional_ | An array of countries to display, specified by their [ISO-3 codes](https://www.iso.org/obp/ui). Leave blank to show all, sorted by most cases. `showCountries` must be set to `true`
+**`limit`** | `number` | _Optional_ | If showing all countries, set a limit for number of results to return. Defaults to `10`, no maximum
+
+
+##### Example
+
+```yaml
+- type: covid-stats
+```
+
+Or
+
+```yaml
+- type: covid-stats
+ options:
+ showChart: true
+ showCountries: true
+ countries:
+ - GBR
+ - USA
+ - IND
+ - RUS
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [disease-sh/api](https://github.com/disease-sh/api))
+- **Privacy**: âĢ No Policy Available
+- **Conditions**: [Terms of Use](https://github.com/disease-sh/api/blob/master/TERMS.md)
+
+---
+
+### Sports Scores
+
+Show recent scores and upcoming matches from your favourite sports team. Data is fetched from [TheSportsDB.com](https://www.thesportsdb.com/). From the UI, you can click any other team to view their scores and upcoming games, or click a league name to see all teams.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`teamId`** | `string` | __Optional__ | The ID of a team to fetch scores from. You can search for your team on the [Teams Page](https://www.thesportsdb.com/teams_main.php)
+**`leagueId`** | `string` | __Optional__ | Alternatively, provide a league ID to fetch all games from. You can find the ID on the [Leagues Page](https://www.thesportsdb.com/Sport/Leagues)
+**`pastOrFuture`** | `string` | __Optional__ | Set to `past` to show scores for recent games, or `future` to show upcoming games. Defaults to `past`. You can change this within the UI
+**`apiKey`** | `string` | __Optional__ | Optionally specify your API key, which you can sign up for at [TheSportsDB.com](https://www.thesportsdb.com/)
+**`limit`** | `number` | __Optional__ | To limit output to a certain number of matches, defaults to `15`
+
+##### Example
+
+```yaml
+- type: sports-scores
+ options:
+ teamId: 133636
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ Optional
+- **Price**: đ Free plan (upto 30 requests / minute, limited endpoints)
+- **Host**: Managed Instance Only
+- **Privacy**: âĢ No Policy Available
+
+---
+
+### News Headlines
+
+Displays the latest news, click to read full article. Date is fetched from various news sources using [Currents API](https://currentsapi.services/en)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | Your API key for CurrentsAPI. This is free, and you can [get one here](https://currentsapi.services/en/register)
+**`country`** | `string` | _Optional_ | Fetch news only from a certain country or region. Specified as a country code, e.g. `GB` or `US`. See [here](https://api.currentsapi.services/v1/available/regions) for a list of supported regions
+**`category`** | `string` | _Optional_ | Only return news from within a given category, e.g. `sports`, `programming`, `world`, `science`. The [following categories](https://api.currentsapi.services/v1/available/categories) are supported
+**`lang`** | `string` | _Optional_ | Specify the language for returned articles as a 2-digit ISO code (limited article support). The [following languages](https://api.currentsapi.services/v1/available/languages) are supported, defaults to `en`
+**`count`** | `number` | _Optional_ | Limit the number of results. Can be between `1` and `200`, defaults to `10`
+**`keywords`** | `string` | _Optional_ | Only return articles that contain an exact match within their title or description
+**`hideImages`** | `boolean` | _Optional_ | If set to `true`, then article image thumbnails will not be displayed
+
+##### Example
+
+```yaml
+- type: news-headlines
+ options:
+ apiKey: xxxxxxx
+ category: world
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan (upto 600 requests / day)
+- **Host**: Managed Instance Only
+- **Privacy**: _See [CurrentsAPI Privacy Policy](https://currentsapi.services/privacy)_
+
+---
+
+### TFL Status
+
+Shows real-time tube status of the London Underground. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`showAll`** | `boolean` | _Optional_ | By default, details for lines with a Good Service are not visible, but you can click More Details to see all. Setting this option to `true` will show all lines on initial page load
+**`sortAlphabetically`** | `boolean` | _Optional_ | By default lines are sorted by current status, set this option to `true` to instead sort them alphabetically
+**`linesToShow`** | `array` | _Optional_ | By default all lines are shown. If you're only interested in the status of a few lines, then pass in an array of lines to show, specified by name
+
+##### Example
+
+```yaml
+- type: tfl-status
+```
+
+```yaml
+ - type: tfl-status
+ options:
+ showAll: true
+ sortAlphabetically: true
+ linesToShow:
+ - District
+ - Jubilee
+ - Central
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance Only
+- **Privacy**: _See [TFL Privacy Policy](https://tfl.gov.uk/corporate/privacy-and-cookies/)_
+
+---
+
+### Stock Price History
+
+Shows recent price history for a given publicly-traded stock or share
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | API key for [Alpha Vantage](https://www.alphavantage.co/), you can get a free API key [here](https://www.alphavantage.co/support/#api-key)
+**`stock`** | `string` | Required | The stock symbol for the asset to fetch data for
+**`priceTime`** | `string` | _Optional_ | The time to fetch price for. Can be `high`, `low`, `open` or `close`. Defaults to `high`
+**`chartColor`** | `string` | _Optional_ | Color of the chart value. Defaults to `--widget-text-color` which inherits dashboard primary color
+**`chartHeight`** | `number` | _Optional_ | The height of rendered chart in px. Defaults to `300`
+
+##### Example
+
+```yaml
+- type: stock-price-chart
+ options:
+ stock: NET
+ apiKey: PGUWSWD6CZTXMT8N
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan (upto 500 requests/day)
+- **Host**: Managed Instance Only
+- **Privacy**: _See [AlphaVantage Privacy Policy](https://www.alphavantage.co/privacy/)_
+
+---
+
+### ETH Gas Prices
+
+Renders the current Gas cost of transactions on the Ethereum network (in both GWEI and USD), along with recent historical prices. Useful for spotting a good time to transact. Uses data from [ethgas.watch](https://ethgas.watch/)
+
+
+
+##### Options
+
+_No config options._
+
+##### Example
+
+```yaml
+- type: eth-gas-prices
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [wslyvh/ethgaswatch](https://github.com/wslyvh/ethgaswatch))
+- **Privacy**: âĢ No Policy Available
+
+---
+
+### Joke
+
+Renders a programming or generic joke. Data is fetched from the [JokesAPI](https://github.com/Sv443/JokeAPI) by @Sv443. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`category`** | `string` | _Optional_ | Set the category of jokes to return. Use a string to specify a single category, or an array to pass in multiple options. Available options are: `all`, `programming`, `pun`, `dark`, `spooky`, `christmas` and `misc`. An up-to-date list of supported categories can be found [here](https://v2.jokeapi.dev/categories). Defaults to `all`
+**`safeMode`** | `boolean` | _Optional_ | Set to `true`, to prevent the fetching of any NSFW jokes. Defaults to `false`
+**`language`** | `string` | _Optional_ | Specify the language for returned jokes. The following languages are supported: `en`, `cs`, `de`, `es`, `fr` and `pt`, and an up-to-date list of supported languages can be found [here](https://v2.jokeapi.dev/languages). By default, your system language will be used, if it's supported, otherwise English
+
+##### Example
+
+```yaml
+- type: joke
+ options:
+ safeMode: true
+ language: en
+ category: Programming
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [Sv443/JokeAPI](https://github.com/Sv443/JokeAPI))
+- **Privacy**: _See [SV443's Privacy Policy](https://sv443.net/privacypolicy/en)_
+
+---
+
+### XKCD Comics
+
+Have a laugh with the daily comic from [XKCD](https://xkcd.com/). A classic webcomic website covering everything from Linux, math, romance, science and language. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`comic`** | `string / number` | _Optional_ | Choose which comic to display. Set to either `random`, `latest` or the series number of a specific comic, like `627`. Defaults to `latest`
+
+##### Example
+
+```yaml
+- type: xkcd-comic
+ options:
+ comic: latest
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Privacy**: âĢ No Policy Available
+
+---
+
+### Flight Data
+
+Displays airport departure and arrival flights, using data from [AeroDataBox](https://www.aerodatabox.com/). Useful if you live near an airport and often wonder where the flight overhead is going to. Hover over a row for more flight data.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`airport`** | `string` | Required | The airport to show flight data from. Should be specified as a 4-character ICAO-code, a full list of which can be found [here](https://en.wikipedia.org/wiki/ICAO_airport_code) (example: `KBJC` or `EGKK`)
+**`apiKey`** | `string` | Required | A valid [RapidAPI](https://rapidapi.com/) Key, with [AeroDataBox](https://rapidapi.com/aerodatabox/api/aerodatabox/) enabled (check in your [Subscription Dashboard](https://rapidapi.com/developer/billing/subscriptions-and-usage)). This API is free to sign up for and use
+**`limit`** | `number` | _Optional_ | For busy airports, you may wish to limit the number of results visible
+**`direction`** | `string` | _Optional_ | By default, both departure and arrival flights will be fetched, if you would like to only show flights in one direction, set this to wither `departure` or `arrival`
+
+##### Example
+
+```yaml
+- type: flight-data
+ options:
+ airport: EGLC
+ apiKey: XXXXX
+ limit: 12
+ direction: all
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan (upto 150 requests / month)
+- **Host**: Managed Instance Only
+- **Privacy**: _See [AeroDataBox](https://www.aerodatabox.com/#h.p_CXtIYZWF_WQd) and [RapidAPI Policy](https://rapidapi.com/privacy/)_
+
+---
+
+### Astronomy Picture of the Day
+
+Show the NASA Astronomy Pictore of the Day. Data is fetched from [APOD](https://apod.nasa.gov/apod/) using [PawelPleskaczynski/apod_api](https://github.com/PawelPleskaczynski/apod_api).
+
+
+
+##### Options
+
+_No config options._
+
+##### Example
+
+```yaml
+- type: apod
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [PawelPleskaczynski/apod_api](https://github.com/PawelPleskaczynski/apod_api))
+- **Privacy**: _See [NASA's Privacy Policy](https://www.nasa.gov/about/highlights/HP_Privacy.html)_
+
+---
+
+### GitHub Trending
+
+Displays currently trending projects on GitHub. Optionally specify a language and time-frame. Data is fetched from [Lissy93/gh-trending-no-cors](https://github.com/Lissy93/gh-trending-no-cors) using the GitHub API. All fields are optional.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`lang`** | `string` | _Optional_ | A programming language to fetch trending repos from that category. E.g. `javascript` or `go`
+**`since`** | `string` | _Optional_ | The timeframe to use when calculating trends. Can be either `daily`, `weekly` or `monthly`. Defaults to `daily`
+**`limit`** | `number` | _Optional_ | Optionally limit the number of results. Max `25`, default is `10`
+
+##### Example
+
+```yaml
+- type: github-trending-repos
+ options:
+ limit: 8
+ since: weekly
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [Lissy93/gh-trending-no-cors](https://github.com/Lissy93/gh-trending-no-cors))
+- **Privacy**: _See [GitHub's Privacy Policy](https://docs.github.com/en/github/site-policy/github-privacy-statement)_
+
+---
+
+### GitHub Profile Stats
+
+Display stats from your GitHub profile, using embedded cards from [anuraghazra/github-readme-stats](https://github.com/anuraghazra/github-readme-stats)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`username`** | `string` | Required | The GitHub username to fetch info for. E.g. `lissy93`. (Not required if `hideProfileCard` and `hideLanguagesCard` are both set to `true`)
+**`hideProfileCard`** | `boolean` | _Optional_ | If set to `true`, the users profile card will not be shown. Defaults to `false`
+**`hideLanguagesCard`** | `boolean` | _Optional_ | If set to `true`, the users top languages card will not be shown. Defaults to `false`
+**`repos`** | `array` | _Optional_ | If you'd like to also display stats for some GitHub reposotories, then add an array or repo names here. Specified as `[username]/[repo-name]`, e.g. `lissy93/dashy`
+
+
+##### Example
+
+
+```yaml
+- type: github-profile-stats
+ options:
+ username: Lissy93
+ hideLanguagesCard: true
+ repos:
+ - lissy93/dashy
+ - lissy93/personal-security-checklist
+ - lissy93/twitter-sentiment-visualisation
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Managed Instance or Self-Hosted (see [anuraghazra/github-readme-stats](https://github.com/anuraghazra/github-readme-stats))
+- **Privacy**: _See [GitHub's Privacy Policy](https://docs.github.com/en/github/site-policy/github-privacy-statement)_
+
+---
+
+## Self-Hosted Services Widgets
+
+
+### System Info
+
+Displays info about the server which Dashy is hosted on. Includes user + host, operating system, uptime and basic memory & load data.
+
+
+
+##### Options
+
+_No config options._
+
+##### Example
+
+```yaml
+- type: system-info
+```
+
+##### Info
+No external data requests made
+
+---
+
+### Cron Monitoring (Health Checks)
+
+Cron job monitoring using [Health Checks](https://github.com/healthchecks/healthchecks). Both managed and self-hosted instances are supported.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`apiKey`** | `string` | Required | A read-only API key for the project to monitor. You can generate this by selecting a Project --> Settings --> API Access. Note that you must generate a separate key for each project
+**`host`** | `string` | _Optional_ | If you're self-hosting, or using any instance other than the official (healthchecks.io), you will need to specify the host address. E.g. `https://healthchecks.example.com` or `http://cron-monitoing.local`
+
+##### Example
+
+```yaml
+- type: health-checks
+ options:
+ apiKey: XXXXXXXXX
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đ Free plan (upto 20 services, or self-host for unlimited)
+- **Host**: Managed Instance or Self-Hosted (see [GitHub - HealthChecks](https://github.com/healthchecks/healthchecks))
+- **Privacy**: _See [Health-Checks Privacy Policy](https://healthchecks.io/privacy/)_
+
+---
+
+### CPU History (NetData)
+
+Pull recent CPU usage history from NetData.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`host`** | `string` | Required | The URL to your NetData instance
+**`chartHeight`** | `number` | _Optional_ | The height of rendered chart in px. Defaults to `300`
+**`chartColor`** / **`chartColors`** | `string` / `array`| _Optional_ | Color of the chart value(s) as hex codes. `chartColor` is a single value (defaults to `--widget-text-color`), whereas `chartColors` is an array of colors
+
+##### Example
+
+```yaml
+- type: nd-cpu-history
+ options:
+ host: http://192.168.1.1:19999
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - NetData](https://github.com/netdata/netdata))
+- **Privacy**: _See [NetData Privacy Policy](https://www.netdata.cloud/data-privacy/)_
+
+---
+
+
+### Memory History (NetData)
+
+Pull recent system RAM usage from NetData, and show as a breakdown of different categories.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`host`** | `string` | Required | The URL to your NetData instance
+**`chartHeight`** | `number` | _Optional_ | The height of rendered chart in px. Defaults to `300`
+**`chartColor`** / **`chartColors`** | `string` / `array`| _Optional_ | Color of the chart value(s) as hex codes. `chartColor` is a single value (defaults to `--widget-text-color`), whereas `chartColors` is an array of colors
+
+##### Example
+
+```yaml
+- type: nd-ram-history
+ options:
+ host: http://192.168.1.1:19999
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - NetData](https://github.com/netdata/netdata))
+- **Privacy**: _See [NetData Privacy Policy](https://www.netdata.cloud/data-privacy/)_
+
+---
+
+### Load History (NetData)
+
+Pull recent load usage in 1, 5 and 15 minute intervals, from NetData.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`host`** | `string` | Required | The URL to your NetData instance
+**`chartHeight`** | `number` | _Optional_ | The height of rendered chart in px. Defaults to `300`
+**`chartColor`** / **`chartColors`** | `string` / `array`| _Optional_ | Color of the chart value(s) as hex codes. `chartColor` is a single value (defaults to `--widget-text-color`), whereas `chartColors` is an array of colors
+
+##### Example
+
+```yaml
+- type: nd-load-history
+ options:
+ host: http://192.168.1.1:19999
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - NetData](https://github.com/netdata/netdata))
+- **Privacy**: _See [NetData Privacy Policy](https://www.netdata.cloud/data-privacy/)_
+
+---
+
+### Pi Hole Stats
+
+Displays the number of queries blocked by [Pi-Hole](https://pi-hole.net/).
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`hostname`** | `string` | Required | The URL to your Pi-Hole instance
+**`hideStatus`** / **`hideChart`** / **`hideInfo`** | `boolean` | _Optional_ | Optionally hide any of the three parts of the widget
+
+##### Example
+
+```yaml
+- type: pi-hole-stats
+ options:
+ hostname: http://192.168.130.1
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - Pi-hole](https://github.com/pi-hole/pi-hole))
+- **Privacy**: _See [Pi-Hole Privacy Guide](https://pi-hole.net/privacy/)_
+
+---
+
+### Pi Hole Queries
+
+Shows top queries that were blocked and allowed by [Pi-Hole](https://pi-hole.net/).
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`hostname`** | `string` | Required | The URL to your Pi-Hole instance
+**`apiKey`** | `string` | Required | Your Pi-Hole web password. It is **NOT** your pi-hole admin interface or server password. It can be found in `/etc/pihole/setupVars.conf`, and is a 64-character located on the line that starts with `WEBPASSWORD`
+**`count`** | `number` | _Optional_ | The number of queries to display. Defaults to `10`
+
+##### Example
+
+```yaml
+- type: pi-hole-top-queries
+ options:
+ hostname: https://pi-hole.local
+ apiKey: xxxxxxxxxxxxxxxxxxxxxxx
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ´ Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - Pi-hole](https://github.com/pi-hole/pi-hole))
+- **Privacy**: _See [Pi-Hole Privacy Guide](https://pi-hole.net/privacy/)_
+
+---
+
+### Recent Traffic
+
+Shows number of recent traffic, using allowed and blocked queries from [Pi-Hole](https://pi-hole.net/)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`hostname`** | `string` | Required | The URL to your Pi-Hole instance
+
+##### Example
+
+```yaml
+- type: pi-hole-traffic
+ options:
+ hostname: https://pi-hole.local
+```
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - Pi-hole](https://github.com/pi-hole/pi-hole))
+- **Privacy**: _See [Pi-Hole Privacy Guide](https://pi-hole.net/privacy/)_
+
+---
+
+### Stat Ping Statuses
+
+Displays the current and recent uptime of your running services, via a self-hosted instance of [StatPing](https://github.com/statping/statping)
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`hostname`** | `string` | Required | The URL to your StatPing instance, without a trailing slash
+
+##### Example
+
+```yaml
+- type: stat-ping
+ options:
+ hostname: http://192.168.130.1:8080
+```
+
+##### Info
+- **CORS**: đ Proxied
+- **Auth**: đĸ Not Required
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - StatPing](https://github.com/statping/statping))
+- **Privacy**: _See [StatPing Docs](https://docs.statping.com/)_
+
+---
+
+## System Resource Monitoring
+
+The easiest method for displaying system info and resource usage in Dashy is with [Glances](https://nicolargo.github.io/glances/).
+
+Glances is a cross-platform monitoring tool developed by [@nicolargo](https://github.com/nicolargo). It's similar to top/htop but with a [Rest API](https://glances.readthedocs.io/en/latest/api.html) and many [data exporters](https://glances.readthedocs.io/en/latest/gw/index.html) available. Under the hood, it uses [psutil](https://github.com/giampaolo/psutil) for retrieving system info.
+
+If you don't already have it installed, either follow the [Installation Guide](https://github.com/nicolargo/glances/blob/master/README.rst) for your system, or setup [with Docker](https://glances.readthedocs.io/en/latest/docker.html), or use the one-line install script: `curl -L https://bit.ly/glances | /bin/bash`.
+
+Glances can be launched with the `glances` command. You'll need to run it in web server mode, using the `-w` option for the API to be reachable. If you don't plan on using the Web UI, then you can disable it using `--disable-webui`. See the [command reference docs](https://glances.readthedocs.io/en/latest/cmds.html) for more info.
+
+
+##### Options
+
+All Glance's based widgets require a `hostname`. All other parameters are optional.
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`hostname`** | `string` | Required | The URL or IP + port to your Glances instance (without a trailing slash)
+**`username`** | `string` | _Optional_ | If you have setup basic auth on Glances, specify username here (defaults to `glances`)
+**`password`** | `string` | _Optional_ | If you have setup basic auth on Glances, specify password here. **Note**: since this password is in plaintext, it is important not to reuse it anywhere else
+**`apiVersion`** | `string` | _Optional_ | Specify an API version, defaults to V `3`. Note that support for older versions is limited
+**`limit`** | `number` | _Optional_ | For widgets that show a time-series chart, optionally limit the number of data points returned. A higher number will show more historical results, but will take longer to load. A value between 300 - 800 is usually optimal
+
+##### Info
+- **CORS**: đĸ Enabled
+- **Auth**: đ Optional
+- **Price**: đĸ Free
+- **Host**: Self-Hosted (see [GitHub - Nicolargo/Glances](https://github.com/nicolargo/glances))
+- **Privacy**: âĢ No Policy Available
+
+##### Screenshot
+[![example-screenshot](https://i.ibb.co/xfK6BGb/system-monitor-board.png)](https://ibb.co/pR6dMZT)
+
+---
+
+### Current CPU Usage
+
+Live-updating current CPU usage, as a combined average across alll cores
+
+
+
+##### Example
+
+```yaml
+- type: gl-current-cpu
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### CPU Usage Per Core
+
+Live-updating CPU usage breakdown per core
+
+
+
+##### Example
+
+```yaml
+- type: gl-current-cores
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### CPU Usage History
+
+Recent CPU usage history, across all cores, and displayed by user and system
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`limit`** | `number` | _Optional_ | Limit the number of results returned, rendering more data points will take longer to load. Defaults to `100`
+
+##### Example
+
+```yaml
+- type: gl-cpu-history
+ options:
+ hostname: http://192.168.130.2:61208
+ limit: 60
+```
+
+---
+
+### Current Memory Usage
+
+Real-time memory usage gauge, with more info visible on click
+
+
+
+##### Example
+
+```yaml
+- type: gl-current-mem
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### Memory Usage History
+
+Recent memory usage chart
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`limit`** | `number` | _Optional_ | Limit the number of results returned, rendering more data points will take longer to load. Defaults to `100`
+
+
+##### Example
+
+```yaml
+- type: gl-mem-history
+ options:
+ hostname: http://localhost:61208
+ limit: 80
+```
+
+---
+
+### Disk Space
+
+List connected disks, showing free / used space and other info (file system, mount point and space available)
+
+
+
+##### Example
+
+```yaml
+- type: gl-disk-space
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### Disk IO
+
+Shows real-time read and write speeds and operations per sec for each disk
+
+
+
+##### Example
+
+```yaml
+- type: gl-disk-io
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### System Load
+
+Shows the number of processes waiting in the run-queue, averaged across all cores. Displays for past 5, 10 and 15 minutes
+
+
+
+##### Example
+
+```yaml
+- type: gl-system-load
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### System Load History
+
+Shows recent historical system load, calculated from the number of processes waiting in the run-queue, in 1, 5 and 15 minute intervals, and averaged across all cores. Optionally specify `limit` to set number of results returned, defaults to `500`, max `100000`, but the higher the number the longer the load and render times will be.
+
+
+
+##### Example
+
+```yaml
+- type: gl-load-history
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### Network Interfaces
+
+Lists visible network interfaces, including real-time upload/ download stats
+
+
+
+##### Example
+
+```yaml
+- type: gl-network-interfaces
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+### Network Traffic
+
+Shows amount of data recently uploaded/ downloaded across all network interfaces. Optionally set the `limit` option to specify number historical of data points to return
+
+
+
+##### Example
+
+```yaml
+- type: gl-network-traffic
+ options:
+ hostname: http://192.168.130.2:61208
+ limit: 500
+```
+
+---
+
+### Resource Usage Alerts
+
+Lists recent high resource usage alerts (e.g. CPU, mem, IO, load, temp)
+
+
+
+##### Example
+
+```yaml
+- type: gl-alerts
+ options:
+ hostname: http://192.168.130.2:61208
+```
+
+---
+
+## Dynamic Widgets
+
+### Iframe Widget
+
+Embed any webpage into your dashboard as a widget.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`url`** | `string` | Required | The URL to the webpage to embed
+**`frameHeight`** | `number` | _Optional_ | If needed, specify height of iframe in `px`. E.g. `400`, defaults to auto
+
+##### Example
+
+```yaml
+- type: iframe
+ options:
+ url: https://fiatleak.com/
+```
+
+---
+
+### HTML Embedded Widget
+
+Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents.
+
+â ī¸ **NOTE:** Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences.
+
+
+
+##### Options
+
+**Field** | **Type** | **Required** | **Description**
+--- | --- | --- | ---
+**`html`** | `string` | _Optional_ | HTML contents to render in the widget
+**`script`** | `string` | _Optional_ | Raw JavaScript code to execute (caution)
+**`scriptSrc`** | `string` | _Optional_ | A URL to JavaScript content (caution)
+**`css`** | `string` | _Optional_ | Any stylings for widget contents
+
+##### Example
+
+```yaml
+- type: embed
+ options:
+ scriptSrc: https://cdn.speedcheck.org/basic/scbjs.min.js
+ html: |
+
+```
+
+Or
+
+```yaml
+- type: embed
+ options:
+ css: '.coinmarketcap-currency-widget { color: var(--widget-text-color); }'
+ html: '
'
+ scriptSrc: 'https://files.coinmarketcap.com/static/widget/currency.js'
+```
+
+---
+
+### API Response
+
+Directly output plain-text response from any API-enabled service.
+
+// Coming soon...
+
+---
+
+### Prometheus Data
+
+Display data from any service with a Prometheus exporter.
+
+// Coming soon...
+
+---
+
+### Data Feed
+
+Show live data from an RSS-enabled service. The only required parameter is `rssUrl`, which is the URL to the ATOM feed. See [RSS Widget](#rss-feed) for full list of available options.
+
+
+
+##### Example
+
+```yaml
+- type: rss-feed
+ options:
+ rssUrl: https://notes.aliciasykes.com/feed
+```
+
+---
+
+## Usage & Customizations
+
+### Widget Usage Guide
+
+Like items, widgets are placed under sections. You may have one or more widgets per section.
+
+In your YAML config file, this will look something like:
+
+```yaml
+sections:
+- name: Today
+ icon: far fa-calendar-day
+ widgets:
+ - type: clock
+ options:
+ format: en-GB
+ - type: weather
+ options:
+ apiKey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ city: London
+ units: metric
+```
+
+> In this example, there is a single section, named "Today", using a Calendar icon from Font-Awesome. It has 2 widgets, a clock and the current weather.
+
+---
+
+### Continuous Updates
+
+By default, a widget which displays dynamic data from an external source, will only fetch results on page load. If you would like to keep data updated at all times, you can enable **Continuous Updates**. This is done by setting a time value in the `updateInterval` field.
+
+The value of `updateInterval` is optional, and is specified and seconds. It must be more than `10` and less than `7200`.
+
+For example, the following widget displaying stats from Pi-Hole will update ever 20 seconds.
+
+```yaml
+widgets:
+- type: pi-hole-stats
+ updateInterval: 20
+ options:
+ hostname: http://192.168.130.2
+```
+
+Note that if you have many widgets, and set them to continuously update frequently, you will notice a hit to performance. A widget that relies on data from an external API, will also consume your usage quota faster, if set to keep updating.
+
+---
+
+### Proxying Requests
+
+If a widget fails to make a data request, and the console shows a CORS error, this means the server is blocking client-side requests.
+
+Dashy has a built-in CORS proxy ([`services/cors-proxy.js`](https://github.com/Lissy93/dashy/blob/master/services/cors-proxy.js)), which will be used automatically by some widgets, or can be forced to use by other by setting the `useProxy` option.
+
+For example:
+
+```yaml
+widgets:
+- type: pi-hole-stats
+ useProxy: true
+ options:
+ hostname: http://pi-hole.local
+```
+
+Alternativley, and more securley, you can set the auth headers on your service to accept requests from Dashy. For example:
+
+```
+Access-Control-Allow-Origin: https://location-of-dashy/
+Vary: Origin
+```
+
+---
+
+### Widget Styling
+
+Like elsewhere in Dashy, all colours can be easily modified with CSS variables.
+
+Widgets use the following color variables, which can be overridden if desired:
+- `--widget-text-color` - Text color, defaults to `--primary`
+- `--widget-background-color` - Background color, defaults to `--background-darker`
+- `--widget-accent-color` - Accent color, defaults to `--background`
+
+For more info on how to apply custom variables, see the [Theming Docs](/docs/theming#setting-custom-css-in-the-ui)
+
+---
+
+### Customizing Charts
+
+For widgets that contain charts, you can set an array of colors under `chartColors`.
+To specify the chart height, set `chartHeight` to an integer (in `px`), defaults to `300`.
+For example:
+
+```yaml
+- type: gl-load-history
+ options:
+ hostname: http://192.168.130.2:61208
+ chartColors: ['#9b5de5', '#f15bb5', '#00bbf9', '#00f5d4']
+ chartHeight: 450
+```
+
+---
+
+### Language Translations
+
+Since most of the content displayed within widgets is fetched from an external API, unless that API supports multiple languages, translating dynamic content is not possible.
+
+However, any hard-coded content is translatable, and all dates and times will display in your local format.
+
+For more info about multi-language support, see the [Internationalization Docs](/docs/multi-language-support).
+
+---
+
+### Widget UI Options
+
+Widgets can be opened in full-page view, by clicking the Arrow icon (top-right). The URL in your address bar will also update, and visiting that web address directly will take you straight to that widget.
+
+You can reload the data of any widget, by clicking the Refresh Data icon (also in top-right). This will only affect the widget where the action was triggered from.
+
+All [config options](/docs/configuring#section) that can be applied to sections, can also be applied to widget sections. For example, to make a widget section double the width, set `displayData.cols: 2` within the parent section. You can collapse a widget (by clicking the section title), and collapse state will be saved locally.
+
+Widgets cannot currently be edited through the UI. This feature is in development, and will be released soon. In the meantime, you can either use the JSON config editor, or use [VS Code Server](https://github.com/coder/code-server), or just SSH into your box and edit the conf.yml file directly.
+
+---
+
+### Build your own Widget
+
+Widgets are built in a modular fashion, making it easy for anyone to create their own custom components.
+
+For a full tutorial on creating your own widget, you can follow [this guide](/docs/development-guides#building-a-widget), or take a look at [here](https://github.com/Lissy93/dashy/commit/3da76ce2999f57f76a97454c0276301e39957b8e) for a code example.
+
+Alternatively, for displaying simple data, you could also just use the either the [iframe](#iframe-widget), [embed](#html-embedded-widget), [data feed](#data-feed) or [API response](#api-response) widgets.
+
+---
+
+### Requesting a Widget
+
+Suggestions for widget ideas are welcome. But there is no guarantee that I will build your widget idea.
+
+You can suggest a widget [here](https://git.io/Jygo3), please star the repo before submitting a ticket.
+
+Please only request widgets for services that:
+- Have a publicly accessible API
+- Are CORS and HTTPS enabled
+- Are free to use, or have a free plan
+- Allow for use in their Terms of Service
+- Would be useful for other users
+
+For services that are not officially supported, it is likely still possible to display data using either the [iframe](#iframe-widget), [embed](#html-embedded-widget) or [API response](#api-response) widgets. For more advanced features, like charts and action buttons, you could also build your own widget, using [this tutorial](/docs/development-guides#building-a-widget), it's fairly straight forward, and you can use an [existing widget](https://github.com/Lissy93/dashy/tree/master/src/components/Widgets) (or [this example](https://git.io/JygKI)) as a template.