feat(auth): Implement conditional authentication middleware for services in docker-compose.yml
Some checks failed
/ validate-docker-compose (push) Has been cancelled

This commit is contained in:
Jose Daniel G. Percy 2025-04-26 01:58:42 +08:00
parent 2fadb08c72
commit a0e63e2e2b
2 changed files with 98 additions and 25 deletions

View File

@ -25,8 +25,10 @@ The core idea is to manage media libraries (movies, TV shows, music), automate d
- [(Optional) VPN Configuration](#optional-vpn-configuration) - [(Optional) VPN Configuration](#optional-vpn-configuration)
- [(Optional) Traefik DNS Challenge](#optional-traefik-dns-challenge) - [(Optional) Traefik DNS Challenge](#optional-traefik-dns-challenge)
- [Service Access](#service-access) - [Service Access](#service-access)
- [Configuring Authentication Per Service](#configuring-authentication-per-service)
- [Optional Services](#optional-services) - [Optional Services](#optional-services)
- [Troubleshooting](#troubleshooting) - [Troubleshooting](#troubleshooting)
- [Middleware Not Found Errors](#middleware-not-found-errors)
- [SELinux Socket Permissions (Docker)](#selinux-socket-permissions-docker) - [SELinux Socket Permissions (Docker)](#selinux-socket-permissions-docker)
- [Authelia v4.38+ Configuration](#authelia-v438-configuration) - [Authelia v4.38+ Configuration](#authelia-v438-configuration)
- [Tailscale Issues](#tailscale-issues) - [Tailscale Issues](#tailscale-issues)
@ -39,7 +41,7 @@ This stack uses a combination of key services for routing, access, and security:
* **[Tailscale](https://tailscale.com):** Provides a secure overlay network (WireGuard-based VPN) connecting your devices. It allows access to the NAS services from anywhere without opening firewall ports and handles HTTPS termination via its built-in `tailscale serve` or `tailscale funnel` features. All other services run within Tailscale's network namespace. * **[Tailscale](https://tailscale.com):** Provides a secure overlay network (WireGuard-based VPN) connecting your devices. It allows access to the NAS services from anywhere without opening firewall ports and handles HTTPS termination via its built-in `tailscale serve` or `tailscale funnel` features. All other services run within Tailscale's network namespace.
* **[Traefik](https://traefik.io):** Acts as a reverse proxy *within* the Tailscale network. It discovers services via Docker labels and routes incoming requests (from Tailscale) to the appropriate container based on paths (e.g., `/sonarr`, `/radarr`). * **[Traefik](https://traefik.io):** Acts as a reverse proxy *within* the Tailscale network. It discovers services via Docker labels and routes incoming requests (from Tailscale) to the appropriate container based on paths (e.g., `/sonarr`, `/radarr`).
* **[Authelia](https://www.authelia.com):** Serves as the authentication gateway. Traefik forwards requests to Authelia for verification. If a user isn't logged in, they are redirected to the Authelia portal (`/`). Once authenticated, Authelia sets a session cookie (stored in Redis), and Traefik allows access to the requested service. * **[Authelia](https://www.authelia.com):** Serves as the authentication gateway. Traefik forwards requests to Authelia for verification. If a user isn't logged in, they are redirected to the Authelia portal (`/`). Once authenticated, Authelia sets a session cookie (stored in Redis), and Traefik allows access to the requested service. You can configure which services require authentication via environment variables.
## Features ## Features
@ -126,6 +128,14 @@ These steps are **mandatory** for a working installation. Without properly compl
``` ```
- Replace the example hash in `authelia/users_database.yml` with your generated hash - Replace the example hash in `authelia/users_database.yml` with your generated hash
6. **⚠️ Optional: Authentication Configuration**
- Choose which services require authentication by setting the corresponding variables in your `.env` file:
```
AUTH_JELLYFIN=false # Example: Allow Jellyfin access without authentication
AUTH_SONARR=true # Example: Require authentication for Sonarr
```
- By default, all services require authentication if not specified otherwise
## Quick Start Guide ## Quick Start Guide
After completing all [Required Setup Steps](#required-setup-steps) above, follow these steps to get up and running: After completing all [Required Setup Steps](#required-setup-steps) above, follow these steps to get up and running:
@ -216,8 +226,20 @@ This file controls essential settings. Copy `.env.example` to `.env` and modify
| **`AUTHELIA_SESSION_SECRET`** | **Required.** Random secret for session cookies. **Generate your own!** | *(None - Example in file)* | | **`AUTHELIA_SESSION_SECRET`** | **Required.** Random secret for session cookies. **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_STORAGE_ENCRYPTION_KEY`** | **Required.** Random secret for encrypting data at rest (e.g., SQLite DB). **Generate your own!** | *(None - Example in file)* | | **`AUTHELIA_STORAGE_ENCRYPTION_KEY`** | **Required.** Random secret for encrypting data at rest (e.g., SQLite DB). **Generate your own!** | *(None - Example in file)* |
| **`AUTHELIA_REDIS_PASSWORD`** | **Required.** Password for the Redis database (used for session storage). **Generate your own!** | *(None - Example in file)* | | **`AUTHELIA_REDIS_PASSWORD`** | **Required.** Password for the Redis database (used for session storage). **Generate your own!** | *(None - Example in file)* |
| `AUTHELIA_SESSION_DOMAIN` | *Deprecated.* Domain for session cookies. Should match `APP_HOSTNAME`. (Handled within `authelia/configuration.yml` in v4.38+) | `${APP_HOSTNAME}` | | `AUTH_SONARR` | Control whether Sonarr requires authentication (`true`/`false`). | `true` |
| `AUTHELIA_DEFAULT_REDIRECT_URL` | *Deprecated.* Where users land after login. (Handled within `authelia/configuration.yml` in v4.38+) | `https://${APP_HOSTNAME}/home` | | `AUTH_RADARR` | Control whether Radarr requires authentication (`true`/`false`). | `true` |
| `AUTH_BAZARR` | Control whether Bazarr requires authentication (`true`/`false`). | `true` |
| `AUTH_PROWLARR` | Control whether Prowlarr requires authentication (`true`/`false`). | `true` |
| `AUTH_JELLYSEERR` | Control whether Jellyseerr requires authentication (`true`/`false`). | `true` |
| `AUTH_QBITTORRENT` | Control whether qBittorrent requires authentication (`true`/`false`). | `true` |
| `AUTH_LIDARR` | Control whether Lidarr requires authentication (`true`/`false`). | `true` |
| `AUTH_JELLYFIN` | Control whether Jellyfin requires authentication (`true`/`false`). | `false` |
| `AUTH_HOMEPAGE` | Control whether Homepage requires authentication (`true`/`false`). | `true` |
| `AUTH_FLARESOLVERR` | Control whether FlareSolverr requires authentication (`true`/`false`). | `true` |
| `AUTH_SABNZBD` | Control whether SABnzbd requires authentication (`true`/`false`). | `true` |
| `AUTH_CALIBRE` | Control whether Calibre-Web requires authentication (`true`/`false`). | `true` |
> **Note:** Authentication variables were introduced to give you fine-grained control over which services require login. Set to `false` for services you want to access without authentication.
#### Service Credentials #### Service Credentials
@ -340,20 +362,35 @@ Authelia uses the `authelia/users_database.yml` file to manage users.
## Service Access ## Service Access
With the default Tailscale setup and Authelia enabled, services are securely accessible via HTTPS using your Tailscale node's name or IP. Access requires authentication via Authelia. With the default Tailscale setup and Authelia enabled, services are securely accessible via HTTPS using your Tailscale node's name or IP. Authentication is controlled by the `AUTH_*` environment variables.
* **Login Portal:** `https://<TAILSCALE_NODE>/` (Redirects unauthenticated users here) * **Login Portal:** `https://<TAILSCALE_NODE>/` (Redirects unauthenticated users here for secured services)
* **Homepage Dashboard:** `https://<TAILSCALE_NODE>/home` (Accessible after login) * **Homepage Dashboard:** `https://<TAILSCALE_NODE>/home` (Requires login if `AUTH_HOMEPAGE=true`)
* **Sonarr:** `https://<TAILSCALE_NODE>/sonarr` (Requires login) * **Sonarr:** `https://<TAILSCALE_NODE>/sonarr` (Requires login if `AUTH_SONARR=true`)
* **Radarr:** `https://<TAILSCALE_NODE>/radarr` (Requires login) * **Radarr:** `https://<TAILSCALE_NODE>/radarr` (Requires login if `AUTH_RADARR=true`)
* **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent` * **qBittorrent:** `https://<TAILSCALE_NODE>/qbittorrent` (Requires login if `AUTH_QBITTORRENT=true`)
* **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin` * **Jellyfin:** `https://<TAILSCALE_NODE>/jellyfin` (Requires login if `AUTH_JELLYFIN=true`, default is `false`)
* ...and so on. * ...and so on.
Replace `<TAILSCALE_NODE>` with your Tailscale device name (e.g., `tailscale-nas.your-tailnet.ts.net`) or its Tailscale IP address. Replace `<TAILSCALE_NODE>` with your Tailscale device name (e.g., `tailscale-nas.your-tailnet.ts.net`) or its Tailscale IP address.
If you configure DNS for your `APP_HOSTNAME` variable to point to the Tailscale IP, you can use `https://<APP_HOSTNAME>/<service_path>`. If you configure DNS for your `APP_HOSTNAME` variable to point to the Tailscale IP, you can use `https://<APP_HOSTNAME>/<service_path>`.
### Configuring Authentication Per Service
You can control which services require authentication by setting the appropriate variables in your `.env` file:
```bash
# Example: Allow Jellyfin and qBittorrent without authentication, require it for others
AUTH_JELLYFIN=false
AUTH_QBITTORRENT=false
AUTH_SONARR=true
AUTH_RADARR=true
# ...and so on
```
If a variable is not explicitly set, authentication defaults to `true` for that service (except for Jellyfin, which defaults to `false`).
## Optional Services ## Optional Services
Several services are included but disabled by default. Enable them by adding their profile name to the `COMPOSE_PROFILES` variable in your `.env` file (separate multiple profiles with commas). Several services are included but disabled by default. Enable them by adding their profile name to the `COMPOSE_PROFILES` variable in your `.env` file (separate multiple profiles with commas).
@ -377,6 +414,20 @@ Available Profiles:
## Troubleshooting ## Troubleshooting
### Middleware Not Found Errors
If you see error messages like `middleware "authelia-auth@docker" does not exist` in the Traefik logs, it could be due to one of these issues:
1. **Docker Network Issue:** The Traefik configuration has been updated to fix network discovery issues when running in Tailscale's network namespace. If you're still seeing this error, try restarting the stack with:
```bash
docker compose down
docker compose up -d
```
2. **Authentication Variable Missing:** Ensure you have properly configured the `AUTH_*` variables in your `.env` file for the services you want to control. If not specified, most services default to requiring authentication.
3. **Docker Socket Permissions:** Make sure Traefik can access the Docker socket. See the [SELinux Socket Permissions](#selinux-socket-permissions-docker) section below for more details.
### SELinux Socket Permissions (Docker) ### SELinux Socket Permissions (Docker)
If you are running Docker on a host with SELinux enabled (like Fedora, CentOS, RHEL) and services like Traefik, Watchtower, or Autoheal fail with "permission denied" errors when trying to access `/var/run/docker.sock`: If you are running Docker on a host with SELinux enabled (like Fedora, CentOS, RHEL) and services like Traefik, Watchtower, or Autoheal fail with "permission denied" errors when trying to access `/var/run/docker.sock`:

View File

@ -1,4 +1,24 @@
services: services:
middlewares:
# This is a "no-op" service just to hold middleware definitions
image: traefik/whoami:latest
container_name: middlewares
restart: "no"
labels:
# Authentication middleware - used when AUTH_SERVICE=true
- traefik.http.middlewares.auth-required.forwardAuth.address=http://authelia:9091/api/verify?rd=https://${APP_HOSTNAME}/
- traefik.http.middlewares.auth-required.forwardAuth.trustForwardHeader=true
- traefik.http.middlewares.auth-required.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email
# No authentication middleware - used when AUTH_SERVICE=false
- traefik.http.middlewares.auth-bypass.headers.customResponseHeaders.X-Auth-Skip=true
# Map true/false to the actual middleware
- traefik.http.middlewares.true.chain.middlewares=auth-required
- traefik.http.middlewares.false.chain.middlewares=auth-bypass
profiles:
- disabled # This service never actually starts
traefik: traefik:
image: ghcr.io/traefik/traefik:3.3 image: ghcr.io/traefik/traefik:3.3
container_name: traefik container_name: traefik
@ -83,11 +103,13 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.sonarr.rule=PathPrefix(`/sonarr`) - traefik.http.routers.sonarr.rule=PathPrefix(`/sonarr`)
- traefik.http.routers.sonarr.entrypoints=web - traefik.http.routers.sonarr.entrypoints=web
- traefik.http.routers.sonarr.middlewares=${AUTH_SONARR:-true} - traefik.http.routers.sonarr.middlewares=${AUTH_SONARR:-true}@docker
- traefik.http.services.sonarr.loadbalancer.server.port=8989 - traefik.http.services.sonarr.loadbalancer.server.port=8989
# Add conditional middlewares # Define middleware chains for auth control - these are global definitions
- traefik.http.middlewares.true.chain.middlewares=authelia-auth@docker - traefik.http.middlewares.true.forwardAuth.address=http://authelia:9091/api/verify?rd=https://${APP_HOSTNAME}/
- traefik.http.middlewares.false.chain.middlewares= - traefik.http.middlewares.true.forwardAuth.trustForwardHeader=true
- traefik.http.middlewares.true.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email
- traefik.http.middlewares.false.headers.customResponseHeaders.X-Auth-Skip=true
- homepage.group=Media - homepage.group=Media
- homepage.name=Sonarr - homepage.name=Sonarr
- homepage.icon=sonarr.png - homepage.icon=sonarr.png
@ -116,7 +138,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.radarr.rule=PathPrefix(`/radarr`) - traefik.http.routers.radarr.rule=PathPrefix(`/radarr`)
- traefik.http.routers.radarr.entrypoints=web - traefik.http.routers.radarr.entrypoints=web
- traefik.http.routers.radarr.middlewares=${AUTH_RADARR:-true} - traefik.http.routers.radarr.middlewares=${AUTH_RADARR:-true}@docker
- traefik.http.services.radarr.loadbalancer.server.port=7878 - traefik.http.services.radarr.loadbalancer.server.port=7878
- homepage.group=Media - homepage.group=Media
- homepage.name=Radarr - homepage.name=Radarr
@ -146,7 +168,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.lidarr.rule=PathPrefix(`/lidarr`) - traefik.http.routers.lidarr.rule=PathPrefix(`/lidarr`)
- traefik.http.routers.lidarr.entrypoints=web - traefik.http.routers.lidarr.entrypoints=web
- traefik.http.routers.lidarr.middlewares=authelia-auth@docker - traefik.http.routers.lidarr.middlewares=${AUTH_LIDARR:-true}@docker
- traefik.http.services.lidarr.loadbalancer.server.port=8686 - traefik.http.services.lidarr.loadbalancer.server.port=8686
- homepage.group=Media - homepage.group=Media
- homepage.name=Lidarr - homepage.name=Lidarr
@ -178,7 +200,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.bazarr.rule=PathPrefix(`/bazarr`) - traefik.http.routers.bazarr.rule=PathPrefix(`/bazarr`)
- traefik.http.routers.bazarr.entrypoints=web - traefik.http.routers.bazarr.entrypoints=web
- traefik.http.routers.bazarr.middlewares=${AUTH_BAZARR:-true} - traefik.http.routers.bazarr.middlewares=${AUTH_BAZARR:-true}@docker
- traefik.http.services.bazarr.loadbalancer.server.port=6767 - traefik.http.services.bazarr.loadbalancer.server.port=6767
- homepage.group=Download - homepage.group=Download
- homepage.name=Bazarr - homepage.name=Bazarr
@ -214,7 +236,7 @@ services:
- traefik.http.routers.jellyseerr.rule=PathPrefix(`/jellyseerr`) - traefik.http.routers.jellyseerr.rule=PathPrefix(`/jellyseerr`)
- traefik.http.routers.jellyseerr.entrypoints=web - traefik.http.routers.jellyseerr.entrypoints=web
- traefik.http.services.jellyseerr.loadbalancer.server.port=5055 - traefik.http.services.jellyseerr.loadbalancer.server.port=5055
- traefik.http.routers.jellyseerr.middlewares=jellyseerr-stripprefix,jellyseerr-rewrite,jellyseerr-rewriteHeaders,authelia-auth@docker - traefik.http.routers.jellyseerr.middlewares=jellyseerr-stripprefix,jellyseerr-rewrite,jellyseerr-rewriteHeaders,${AUTH_JELLYSEERR:-true}@docker
- traefik.http.middlewares.jellyseerr-stripprefix.stripPrefix.prefixes=/jellyseerr - traefik.http.middlewares.jellyseerr-stripprefix.stripPrefix.prefixes=/jellyseerr
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].header=location - traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].header=location
- traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].regex=^/(.+)$ - traefik.http.middlewares.jellyseerr-rewriteHeaders.plugin.rewriteHeaders.rewrites[0].regex=^/(.+)$
@ -287,7 +309,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.prowlarr.rule=PathPrefix(`/prowlarr`) - traefik.http.routers.prowlarr.rule=PathPrefix(`/prowlarr`)
- traefik.http.routers.prowlarr.entrypoints=web - traefik.http.routers.prowlarr.entrypoints=web
- traefik.http.routers.prowlarr.middlewares=authelia-auth@docker - traefik.http.routers.prowlarr.middlewares=${AUTH_PROWLARR:-true}@docker
- traefik.http.services.prowlarr.loadbalancer.server.port=9696 - traefik.http.services.prowlarr.loadbalancer.server.port=9696
- homepage.group=Download - homepage.group=Download
- homepage.name=Prowlarr - homepage.name=Prowlarr
@ -311,7 +333,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.flaresolverr.rule=PathPrefix(`/flaresolverr`) - traefik.http.routers.flaresolverr.rule=PathPrefix(`/flaresolverr`)
- traefik.http.routers.flaresolverr.entrypoints=web - traefik.http.routers.flaresolverr.entrypoints=web
- traefik.http.routers.flaresolverr.middlewares=authelia-auth@docker - traefik.http.routers.flaresolverr.middlewares=${AUTH_FLARESOLVERR:-true}@docker
- traefik.http.services.flaresolverr.loadbalancer.server.port=8191 - traefik.http.services.flaresolverr.loadbalancer.server.port=8191
profiles: profiles:
- flaresolverr - flaresolverr
@ -338,7 +360,7 @@ services:
- traefik.http.routers.qbittorrent.rule=PathPrefix(`/qbittorrent`) - traefik.http.routers.qbittorrent.rule=PathPrefix(`/qbittorrent`)
- traefik.http.routers.qbittorrent.entrypoints=web - traefik.http.routers.qbittorrent.entrypoints=web
- traefik.http.services.qbittorrent.loadbalancer.server.port=8080 - traefik.http.services.qbittorrent.loadbalancer.server.port=8080
- traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix,authelia-auth@docker - traefik.http.routers.qbittorrent.middlewares=qbittorrent-strip-slash,qbittorrent-stripprefix,${AUTH_QBITTORRENT:-true}@docker
- traefik.http.middlewares.qbittorrent-stripprefix.stripPrefix.prefixes=/qbittorrent - traefik.http.middlewares.qbittorrent-stripprefix.stripPrefix.prefixes=/qbittorrent
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.regex=(^.*\/qbittorrent$$) - traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.regex=(^.*\/qbittorrent$$)
- traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/ - traefik.http.middlewares.qbittorrent-strip-slash.redirectregex.replacement=$$1/
@ -383,7 +405,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.sabnzbd.rule=PathPrefix(`/sabnzbd`) - traefik.http.routers.sabnzbd.rule=PathPrefix(`/sabnzbd`)
- traefik.http.routers.sabnzbd.entrypoints=web - traefik.http.routers.sabnzbd.entrypoints=web
- traefik.http.routers.sabnzbd.middlewares=authelia-auth@docker - traefik.http.routers.sabnzbd.middlewares=${AUTH_SABNZBD:-true}@docker
- traefik.http.services.sabnzbd.loadbalancer.server.port=8080 - traefik.http.services.sabnzbd.loadbalancer.server.port=8080
- homepage.group=Download - homepage.group=Download
- homepage.name=Sabnzbd - homepage.name=Sabnzbd
@ -419,7 +441,7 @@ services:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.jellyfin.rule=PathPrefix(`/jellyfin`) - traefik.http.routers.jellyfin.rule=PathPrefix(`/jellyfin`)
- traefik.http.routers.jellyfin.entrypoints=web - traefik.http.routers.jellyfin.entrypoints=web
- traefik.http.routers.jellyfin.middlewares=authelia-auth@docker - traefik.http.routers.jellyfin.middlewares=${AUTH_JELLYFIN:-false}@docker
- traefik.http.services.jellyfin.loadbalancer.server.port=8096 - traefik.http.services.jellyfin.loadbalancer.server.port=8096
- homepage.group=Media - homepage.group=Media
- homepage.name=Jellyfin - homepage.name=Jellyfin
@ -448,7 +470,7 @@ services:
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Scheme=https - traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Scheme=https
- traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Script-Name=/calibre - traefik.http.middlewares.calibre-headers.headers.customRequestHeaders.X-Script-Name=/calibre
- traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre - traefik.http.middlewares.calibre-stripprefixregex.stripPrefixRegex.regex=/calibre
- traefik.http.routers.calibre.middlewares=calibre-headers,calibre-stripprefixregex,authelia-auth@docker - traefik.http.routers.calibre.middlewares=calibre-headers,calibre-stripprefixregex,${AUTH_CALIBRE:-true}@docker
- traefik.http.routers.calibre.rule=PathPrefix(`/calibre`) - traefik.http.routers.calibre.rule=PathPrefix(`/calibre`)
- traefik.http.routers.calibre.entrypoints=web - traefik.http.routers.calibre.entrypoints=web
- traefik.http.services.calibre.loadbalancer.server.port=8083 - traefik.http.services.calibre.loadbalancer.server.port=8083
@ -526,7 +548,7 @@ services:
- traefik.http.routers.homepage.entrypoints=web - traefik.http.routers.homepage.entrypoints=web
- traefik.http.routers.homepage.priority=10 - traefik.http.routers.homepage.priority=10
- traefik.http.middlewares.homepage-stripprefix.stripPrefix.prefixes=/home - traefik.http.middlewares.homepage-stripprefix.stripPrefix.prefixes=/home
- traefik.http.routers.homepage.middlewares=homepage-stripprefix,authelia-auth@docker - traefik.http.routers.homepage.middlewares=homepage-stripprefix,${AUTH_HOMEPAGE:-true}@docker
- homepage.group=Dashboard - homepage.group=Dashboard
- homepage.name=Homepage - homepage.name=Homepage
- homepage.icon=homepage.png - homepage.icon=homepage.png