Table of Contents

Dockerize Plotly Dash (Flask Dash) App

Find an example here - https://gitea.isolo.org/public/StockChartingDash

Install Docker Desktop

Follow instructions on - https://docs.docker.com/desktop/install/windows-install/

Develop Your App

I use VSCode and Python virtual environment.

Create Dockerfile

Example:

FROM python:alpine3.19
WORKDIR /app
COPY . /app
RUN pip install -U pip && pip install -r requirements.txt
EXPOSE 8050
CMD ["python", "./indicators.py"]

Tip: use .gitignore and .dockerignore file to exclude files you don't need

Build, Test and Push

Run the following CLI commands in VS Code terminal.

Build

docker build -t georgewayne188/stock_dashboard:latest .

Run, Test

docker container run -d -p 8050:8050 georgewayne188/stock_dashboard:latest

Push to Dockerhub

docker image push georgewayne188/sock_dashboard

Transfer Image without Pushing to Repository

Reasons not to use a repository, especially public repository is that the code may have sensitive information in plain text. You will need to save the Docker image as a tar file:

docker save -o <path for generated tar file> <image name>

Then copy your image to a new system with regular file transfer tools such as cp, scp, or rsync (preferred for big files). After that you will have to load the image into Docker:

docker load -i <path to image tar file>

You should add filename (not just directory) with -o, your image syntax may need the repository prefix (:latest tag is default). For example,

docker save -o C:\path\to\file.tar repository/imagename
docker save -o C:\Users\cpan\Tools\Git\repos\stock_dashboard.tar georgewayne188/stock_dashboard:latest

PS: You may need to sudo all commands.

Synology Container Manager

To import images:

Click Action > Import and choose to add from a URL or a file:

To export images:

Reverse Proxy for Secure Internet Access

By default, you can access the Dash app from http://localhost:8050. To be able to access from internet with https, use Synology reverse proxy.

See https://isolo.org/dokuwiki/knowledge_base/home_it/synology/matomo?s[]=reverse&s[]=proxy#create_reverse_proxy_for_https_access for creating reverse proxy.

Add OIDC Authorization for Dash App

Dash App Code

from dash_auth import OIDCAuth
app = Dash(__name__)
auth = OIDCAuth(app, secret_key=os.environ['SECRET_KEY'])
auth.register_provider(
    "stock",
    token_endpoint_auth_method="client_secret_post",
    client_id=os.environ['APP_ID'],
    client_secret=os.environ['APP_SECRET'],
    server_metadata_url=os.environ['SERVER_URL'],
)

Note: OIDCAuth requires Authlib python package (import OIDCAuth would fail without it)

Customize OIDCAuth

The following example will be able to get and remember the username who was authorized.

class OIDCAuthCustom(OIDCAuth): # overide OIDCAuth to get logged in user info

    def __init__(self, *args, **kwargs):
        self.username = None
        super().__init__(*args, **kwargs)

    def callback(self, idp: str):
        return_value = super().callback(idp)

        client = self.get_oauth_client(idp)
        self.username = client.userinfo().get("username")
        # ...

        return return_value

Setup OIDC Server on Synology

Synology package: SSO Server

How to debug: Look at SSO Server Log for hints.

Tips for Hosting Docker Image on Synology

Import Docker Image Tarball

After building the docker image and save as tarball, it can be imported to Synology docker using GUI or CLI's import function. To check the docker image is properly imported, use the following command to check

docker image ls

Running Image with Docker Compose YML

The method described here does NOT work. Reason being javascript based (Dash, Flask are all javascript based) programs are run on the client side. The SSO server thus must be accessible on the internet.

The important thing here is extra_hosts. We're running everything locally so we need to take care of several things:

version: "3"

services:
  server:
    container_name: stockdash
    image: georgewayne188/stock_dashboard:latest
    extra_hosts:
      - www.isolo.org:192.168.11.23
    environment:
      - USER_UID=1000
      - USER_GID=1000
    ports:
      - "8058:8050"
    restart: unless-stopped

In developing phase while working on a Windows machine, had to add a local DNS entry in my Pihole DNS server for the URL to point to local server IP address. The entire project is here