diff --git a/README.md b/README.md
index 62052acc..69e2398a 100644
--- a/README.md
+++ b/README.md
@@ -29,8 +29,8 @@
- [Environment Variables](#environment-variables)
- [Mountable Volumes](#mountable-volumes)
- [Start Container](#start-container)
- - [Run Command](#run-command)
- - [docker-compose.yml](#docker-composeyml)
+ - [Docker Run](#docker-run)
+ - [Docker Compose](#docker-compose)
- [How It Works](#how-it-works)
- [Building `tvapp` Image](#building-tvapp-image)
- [How It Works](#how-it-works-1)
@@ -52,10 +52,21 @@
- [Platform Commands](#platform-commands)
- [Available Variables](#available-variables)
- [Using `tvapp` Image](#using-tvapp-image)
- - [docker run](#docker-run)
- - [docker-compose.yml](#docker-composeyml-1)
+ - [Docker Run](#docker-run-1)
+ - [Docker Compose](#docker-compose-1)
- [Environment Variables](#environment-variables-1)
- [Mountable Volumes](#mountable-volumes-1)
+- [Traefik Integration](#traefik-integration)
+ - [Labels](#labels)
+ - [Dynamic.yml](#dynamicyml)
+ - [Static.yml](#staticyml)
+ - [Providers](#providers)
+ - [certificatesResolvers](#certificatesresolvers)
+ - [entryPoints (Normal)](#entrypoints-normal)
+ - [entryPoints (Cloudflare)](#entrypoints-cloudflare)
+- [Authentik Integration](#authentik-integration)
+ - [Labels](#labels-1)
+ - [Dynamic.yml](#dynamicyml-1)
- [Troubleshooting](#troubleshooting)
- [Run Error: Error serving playlist: ENOENT: no such file or directory, open `/usr/src/app/xmltv.1.xml`](#run-error-error-serving-playlist-enoent-no-such-file-or-directory-open-usrsrcappxmltv1xml)
- [Build Error: s6-rc-compile: fatal: invalid /etc/s6-overlay/s6-rc.d/certsync/type: must be oneshot, longrun, or bundle](#build-error-s6-rc-compile-fatal-invalid-etcs6-overlays6-rcdcertsynctype-must-be-oneshot-longrun-or-bundle)
@@ -135,8 +146,8 @@ For the [environment variables](#environment-variables), you may specify these i
| `WEB_IP` | `0.0.0.0` | IP to use for webserver |
| `WEB_PORT` | `4124` | Port to use for webserver |
| `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. |
-| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built.
⚠️ This should not be used unless you know what you're doing |
-| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built
⚠️ This should not be used unless you know what you're doing |
+| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built.
⚠️ This should not be used unless you know what you're doing |
+| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built
⚠️ This should not be used unless you know what you're doing |
@@ -147,8 +158,8 @@ These paths can be mounted and shared between the TVApp2 docker container and yo
| Container Path | Description |
| --- | --- |
-| `/usr/bin/app` | Path where TVApp2 files will be placed once the app has been built. Includes `formatted.dat`, `xmltv.1.xml`, `urls.txt`, `node_modules`, and `package.json` |
-| `/config` | Where logs will be placed, as well as the web server generated SSH key and cert `cert.key` and `cert.crt` |
+| `/usr/bin/app` | Path where TVApp2 files will be placed once the app has been built. Includes `formatted.dat`, `xmltv.1.xml`, `urls.txt`, `node_modules`, and `package.json` |
+| `/config` | Where logs will be placed, as well as the web server generated SSH key and cert `cert.key` and `cert.crt` |
@@ -162,7 +173,7 @@ These are quick instructions on how to start the TVApp2 docker container once yo
-#### Run Command
+#### Docker Run
If you want to bring the container up using `docker run`; execute the following:
@@ -178,7 +189,7 @@ docker run -d --restart=unless-stopped \
-#### docker-compose.yml
+#### Docker Compose
If you want to use a `docker-compose.yml` to bring TVApp2 up; you may use the following example:
@@ -379,6 +390,7 @@ find ./ -type f -name 'run' | xargs dos2unix --
#### Set `+x / 0755` Permissions
+
The files contained within this repo **MUST** have `chmod 755` / `+x` executable permissions.
```shell
@@ -410,6 +422,7 @@ sudo chmod +x /root/etc/s6-overlay/s6-rc.d/svc-php-fpm/run
### Build `tvapp` Image
+
After completing the items above, you can now build the **[TheBinaryNinja/tvapp2](https://git.binaryninja.net/BinaryNinja/tvapp2)** image. You can now build the TvApp2 docker image. Pick your platform below and run the associated command. Most people will want to use [amd64](#amd64).
@@ -475,7 +488,7 @@ docker buildx create --driver docker-container --name container --bootstrap --us
-**Optional** If you have previously created this image and have not restarted your system, clean up the original container before you build again:
+**Optional** : If you have previously created this image and have not restarted your system, clean up the original container before you build again:
```shell ignore
docker buildx rm container
@@ -494,12 +507,14 @@ You are now ready to build the TVApp2 docker image. Two different options are pr
##### Build & Save Local Image
+
The command below will build your TVApp2 docker image, and save a local copy of your docker app, which can be immediately used, or seen using `docker ps`.
###### amd64
+
```shell ignore
# Build tvapp2 amd64
docker buildx build --no-cache --pull --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250224 -t tvapp2:latest -t tvapp2:1.0.0 --platform=linux/amd64 --output type=docker --output type=docker .
@@ -508,6 +523,7 @@ docker buildx build --no-cache --pull --build-arg VERSION=1.0.0 --build-arg BUIL
###### arm64 / aarch64
+
```shell ignore
# Build tvapp2 arm64
docker buildx build --no-cache --pull --build-arg VERSION=1.0.0 --build-arg BUILDDATE=20250224 -t tvapp2:latest -t tvapp2:1.0.0 --platform=linux/arm64 --output type=docker --output type=docker .
@@ -571,6 +587,7 @@ docker info | grep Username
You should see your name:
+
```console
Username: Aetherinox
```
@@ -628,6 +645,7 @@ The following is a list of the available commands you can pick from depending on
##### Available Variables
+
The run command above has several variables you must specify:
| Variable | Description |
@@ -643,11 +661,13 @@ The run command above has several variables you must specify:
## Using `tvapp` Image
+
To use the new TVApp2 image, you can either call it with the `docker run` command, or create a new `docker-compose.yml` and specify the image:
-### docker run
+### Docker Run
+
If you want to use the tvapp docker image in the `docker run` command, execute the following:
```shell ignore
@@ -661,7 +681,8 @@ docker run -d --restart=unless-stopped \
-### docker-compose.yml
+### Docker Compose
+
If you'd much rather use a `docker-compose.yml` file and call the tvapp image that way, create a new folder somewhere:
```shell ignore
@@ -671,6 +692,7 @@ mkdir -p /home/docker/tvapp2
Then create a new `docker-compose.yml` file and add the following:
+
```shell ignore
sudo nano /home/docker/tvapp2/docker-compose.yml
```
@@ -728,8 +750,8 @@ This docker container contains the following env variables:
| `WEB_IP` | `0.0.0.0` | IP to use for webserver |
| `WEB_PORT` | `4124` | Port to use for webserver |
| `URL_REPO` | `https://git.binaryninja.net/BinaryNinja/` | Determines where the data files will be downloaded from. Do not change this or you will be unable to get M3U and EPG data. |
-| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built.
⚠️ This should not be used unless you know what you're doing |
-| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built
⚠️ This should not be used unless you know what you're doing |
+| `DIR_BUILD` | `/usr/src/app` | Path inside container where TVApp2 will be built.
⚠️ This should not be used unless you know what you're doing |
+| `DIR_RUN` | `/usr/bin/app` | Path inside container where TVApp2 will be placed after it is built
⚠️ This should not be used unless you know what you're doing |
@@ -740,8 +762,8 @@ These paths can be mounted and shared between the TVApp2 docker container and yo
| Container Path | Description |
| --- | --- |
-| `/usr/bin/app` | Path where TVApp2 files will be placed once the app has been built. Includes `formatted.dat`, `xmltv.1.xml`, `urls.txt`, `node_modules`, and `package.json` |
-| `/config` | Where logs will be placed, as well as the web server generated SSH key and cert `cert.key` and `cert.crt` |
+| `/usr/bin/app` | Path where TVApp2 files will be placed once the app has been built. Includes `formatted.dat`, `xmltv.1.xml`, `urls.txt`, `node_modules`, and `package.json` |
+| `/config` | Where logs will be placed, as well as the web server generated SSH key and cert `cert.key` and `cert.crt` |
@@ -749,6 +771,534 @@ These paths can be mounted and shared between the TVApp2 docker container and yo
+## Traefik Integration
+
+> [!NOTE]
+> These steps are **optional**.
+>
+> If you do not use Traefik, you can skip this section of steps. This is only for users who wish to put the TVApp2 container behind Traefik.
+
+
+
+Our first step is to tell Traefik about our TVApp2 container. We highly recommend you utilize a Traefik **[dynamic file](#dynamicyml)**, instead of **[labels](#labels)**. Using a dynamic file allows for automatic refreshing without the need to restart Traefik when a change is made.
+
+If you decide to use **[labels](#labels)** instead of a **[dynamic file](#dynamicyml)**, any changes you want to make to your labels will require a restart of Traefik.
+
+
+
+We will be setting up the following:
+
+- A `middleware` to re-direct http to https
+- A `route` to access TVApp2 via http (optional)
+- A `route` to access TVApp2 via https (secure)
+- A `service` to tell Traefik how to access your TVApp2 container
+- A `resolver` so that Traefik can generate and apply a wildcard SSL certificate
+
+
+
+### Labels
+
+To add TVApp2 to Traefik, you will need to open your `📄 docker-compose.yml` and apply the following labels to your TVApp2 container. Ensure you change `domain.lan` to your actual domain name.
+
+```yml ignore
+services:
+ tvapp2:
+ container_name: tvapp2
+ image: ghcr.io/thebinaryninja/tvapp2:latest # Image: Github
+ # image: thebinaryninja/tvapp2:latest # Image: Dockerhub
+ # image: git.binaryninja.net/binaryninja/tvapp2:latest # Image: Gitea
+ restart: unless-stopped
+ volumes:
+ - /etc/timezone:/etc/timezone:ro
+ - /etc/localtime:/etc/localtime:ro
+ - /var/run/docker.sock:/var/run/docker.sock
+ - ./config:/config
+ - ./app:/usr/bin/app
+ environment:
+ - TZ=Etc/UTC
+ - DIR_RUN=/usr/bin/app
+ labels:
+
+ # General
+ - traefik.enable=true
+
+ # Router > http
+ - traefik.http.routers.tvapp2-http.rule=Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)
+ - traefik.http.routers.tvapp2-http.service=tvapp2
+ - traefik.http.routers.tvapp2-http.entrypoints=http
+ - traefik.http.routers.tvapp2-http.middlewares=https-redirect@file
+
+ # Router > https
+ - traefik.http.routers.tvapp2-https.rule=Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)
+ - traefik.http.routers.tvapp2-https.service=tvapp2
+ - traefik.http.routers.tvapp2-https.entrypoints=https
+ - traefik.http.routers.tvapp2-https.tls=true
+ - traefik.http.routers.tvapp2-https.tls.certresolver=cloudflare
+ - traefik.http.routers.tvapp2-https.tls.domains[0].main=domain.lan
+ - traefik.http.routers.tvapp2-https.tls.domains[0].sans=*.domain.lan
+
+ # Load Balancer
+ - traefik.http.services.tvapp2.loadbalancer.server.port=4124
+ - traefik.http.services.tvapp2.loadbalancer.server.scheme=http
+```
+
+
+
+
+After you've added the labels above, skip the [dynamic.yml](#dynamicyml) section and go straight to the **[static.yml](#staticyml)** section.
+
+
+
+
+### Dynamic.yml
+
+If you decide to not use **[labels](#labels)** and want to use a dynamic file, you will first need to create your dynamic file. the Traefik dynamic file is usually named `dynamic.yml`. We need to add a new `middleware`, `router`, and `service` to our Traefik dynamic file so that it knows about our new TVApp2 container and where it is.
+
+```yml
+http:
+ middlewares:
+ https-redirect:
+ redirectScheme:
+ scheme: "https"
+ permanent: true
+
+ routers:
+ tvapp2-http:
+ service: tvapp2
+ rule: Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)
+ entryPoints:
+ - http
+ middlewares:
+ - https-redirect@file
+
+ tvapp2-https:
+ service: tvapp2
+ rule: Host(`tvapp2.localhost`) || Host(`tvapp2.domain.lan`)
+ entryPoints:
+ - https
+ tls:
+ certResolver: cloudflare
+ domains:
+ - main: "domain.lan"
+ sans:
+ - "*.domain.lan"
+
+ services:
+ tvapp2:
+ loadBalancer:
+ servers:
+ - url: "https://tvapp2:4124"
+```
+
+
+
+### Static.yml
+
+These entries will go in your Traefik `static.yml` file. Any changes made to this file requires that you restart Traefik afterward.
+
+
+
+#### Providers
+
+> [!NOTE]
+> This step is only for users who opted to use the **[dynamic file](#dynamicyml)** method.
+>
+> Users who opted to use [labels](#labels) can skip to the section **[certificatesResolvers](#certificatesresolvers)**
+
+
+
+Ensure you add the following new section to your `static.yml`:
+
+
+
+```yml
+providers:
+ docker:
+ endpoint: "unix:///var/run/docker.sock"
+ exposedByDefault: false
+ network: traefik
+ watch: true
+ file:
+ filename: "/etc/traefik/dynamic.yml"
+ watch: true
+```
+
+
+
+The code above is what enables the use of a **[dynamic file](#dynamicyml)** instead of labels. Change `/etc/traefik/dynamic.yml` if you are placing your dynamic file in a different location. This path is relative to inside the container, not your host machine mounted volume path. Traefik keeps most files in the `/etc/traefik/` folder.
+
+
+
+After you add the above, open your Traefik's `📄 docker-compose.yml` file and mount a new volume so that Traefik knows where your new dynamic file is:
+
+```yml
+services:
+ traefik:
+ container_name: traefik
+ image: traefik:latest
+ restart: unless-stopped
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock:ro
+ - /etc/localtime:/etc/localtime:ro
+ - ./config/traefik.yml:/etc/traefik/traefik.yml:ro
+ - ./config/dynamic.yml:/etc/traefik/dynamic.yml:ro
+```
+
+
+
+You must ensure you add a new volume like shown above:
+
+- `/config/dynamic.yml:/etc/traefik/dynamic.yml:ro`
+
+
+
+On your host machine, make sure you place the `dynamic.yml` file in a sub-folder called **config**, which should be inside the same folder where your Traefik's `📄 docker-compose.yml` file is. If you want to change this location, ensure you change the mounted volume path above.
+
+
+
+After you have completed this, proceed to the section **[certificatesResolvers](#certificatesresolvers)**.
+
+
+
+#### certificatesResolvers
+
+> [!NOTE]
+> This step is required no matter which option you picked above, both for **[dynamic file](#dynamicyml)** setups, as well as people using **[labels](#labels)**.
+
+
+
+Open your Traefik `static.yml` file. We need to define the `certResolver` that we added above either in your dynamic file, or label. To define the `certResolver`, we will be adding a new section labeled `certificatesResolvers`. We are going to use Cloudflare in this example, you can use whatever from the list at:
+
+- https://doc.traefik.io/traefik/https/acme/#providers
+
+
+
+```yml
+certificatesResolvers:
+ cloudflare:
+ acme:
+ email: youremail@address.com
+ storage: /cloudflare/acme.json
+ keyType: EC256
+ preferredChain: 'ISRG Root X1'
+ dnsChallenge:
+ provider: cloudflare
+ delayBeforeCheck: 15
+ resolvers:
+ - "1.1.1.1:53"
+ - "1.0.0.1:53"
+ disablePropagationCheck: true
+```
+
+
+
+Once you pick the DNS / SSL provider you want to use from the code above, you need to see if that provider has any special environment variables that must be set. The **[Providers Page](https://doc.traefik.io/traefik/https/acme/#providers)** lists all providers and also what env variables need set for each one.
+
+
+
+In our example, since we are using **Cloudflare** for `dnsChallenge` -> `provider`, we must set the following environment variables:
+
+- `CF_API_EMAIL`
+- `CF_API_KEY`
+
+
+
+Create a `.env` environment file in the same folder where your Traefik `📄 docker-compose.yml` file is located, and add the following:
+
+```yml
+CF_API_EMAIL=yourcloudflare@email.com
+CF_API_KEY=Your-Cloudflare-API-Key
+```
+
+
+
+Save the `.env` file and exit. For these environment variables to be detected by Traefik, you must give your Traefik container a restart. Until you restart Traefik, it will not be able to generate your new SSL certificates.
+
+You can wait and restart in a moment after you finish editing the `static.yml` file, as there are more items to add below.
+
+
+
+#### entryPoints (Normal)
+
+Finally, inside the Traefik `static.yml`, we need to make sure we have our `entryPoints` configured. Add the following to the Traefik `static.yml` file only if you **DON'T** have entry points set yet:
+
+```yml
+entryPoints:
+ http:
+ address: :80
+ http:
+ redirections:
+ entryPoint:
+ to: https
+ scheme: https
+
+ https:
+ address: :443
+ http3: {}
+ http:
+ tls:
+ options: default
+ certResolver: cloudflare
+ domains:
+ - main: domain.lan
+ sans:
+ - '*.domain.lan'
+```
+
+
+
+#### entryPoints (Cloudflare)
+
+If your website is behind Cloudflare's proxy service, you need to modify your `entryPoints` above so that you can automatically allow Cloudflare's IP addresses through. This means your entry points will look a bit different.
+
+
+
+In the example below, we will add `forwardedHeaders` -> `trustedIPs` and add all of Cloudflare's IPs to the list which are available here:
+
+- https://cloudflare.com/ips/
+
+```yml
+entryPoints:
+ http:
+ address: :80
+ forwardedHeaders:
+ trustedIPs: &trustedIps
+ - 103.21.244.0/22
+ - 103.22.200.0/22
+ - 103.31.4.0/22
+ - 104.16.0.0/13
+ - 104.24.0.0/14
+ - 108.162.192.0/18
+ - 131.0.72.0/22
+ - 141.101.64.0/18
+ - 162.158.0.0/15
+ - 172.64.0.0/13
+ - 173.245.48.0/20
+ - 188.114.96.0/20
+ - 190.93.240.0/20
+ - 197.234.240.0/22
+ - 198.41.128.0/17
+ - 2400:cb00::/32
+ - 2606:4700::/32
+ - 2803:f800::/32
+ - 2405:b500::/32
+ - 2405:8100::/32
+ - 2a06:98c0::/29
+ - 2c0f:f248::/32
+ http:
+ redirections:
+ entryPoint:
+ to: https
+ scheme: https
+
+ https:
+ address: :443
+ http3: {}
+ forwardedHeaders:
+ trustedIPs: *trustedIps
+ http:
+ tls:
+ options: default
+ certResolver: cloudflare
+ domains:
+ - main: domain.lan
+ sans:
+ - '*.domain.lan'
+```
+
+
+
+Save the files and then give Traefik and your TVApp2 container a restart. After the restart is complete; you should be able to access TVApp2 in your browser by going to
+
+```console
+https://tvapp2.domain.lan
+```
+
+
+
+---
+
+
+
+## Authentik Integration
+
+This section will not explain how to install and set up [Authentik](https://goauthentik.io/). We are only going to cover adding TVApp2 integration to Authentik.
+
+
+
+Sign into the Authentik admin panel, go to the left-side navigation, select **Applications** -> **Providers**. Then at the top of the new page, click **Create**.
+
+
+
+

Authentik: Select Applications › Providers

Authentik: Select Create

Authentik: Select desired provider type, or select Proxy Provider

Authentik: Create new Provider

Authentik: Select Applications › Applications

Authentik: Select Create

Authentik: Create Application

Authentik: Select Applications › Outposts

Authentik: Edit outpost

Authentik: Assign application to outpost