Blank page after docker-compose deployment

I'm having a problem using Metabase locally. I am trying to build a fork/custom version of Metabase where I built a Docker image, which I used for my docker-compose setup.

Everything looks like it started great, but when I head over to localhost:3000 (For me the port is forwarded to 5110), I only see a white screen and don't know what's going wrong. Does anybody have the same experience and know how to resolve this problem?

I've got a feeling it's got something to do with the frontend not being built properly.

In my console I do see an error saying:

app.js:56
Uncaught TypeError: Cannot read properties of undefined (reading 'replace')
at 64381 (app.js:56:38)
at c (runtime.708fdf58e52bc83e.js:1:161)
at 35227 (app-main.b05301e2e82eb293.js:252:41804)
at c (runtime.708fdf58e52bc83e.js:1:161)
at app-main.b05301e2e82eb293.js:446:196210
at c.O (runtime.708fdf58e52bc83e.js:1:2836)
at app-main.b05301e2e82eb293.js:446:196227
at i (runtime.708fdf58e52bc83e.js:1:4695)
at app-main.b05301e2e82eb293.js:1:43

And it's about this line:
const BASENAME = window.MetabaseRoot.replace(/\/+$/, "");
The error states Uncaught TypeError: Cannot read properties of undefined (reading 'replace')

It looks like MetabaseRoot is empty when I hover over it when there is a breakpoint on it.
Here are the rest of the logs from the console:

setup/:1
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https://maps.google.com https://accounts.google.com https://www.google-analytics.com 'sha256-xFjzoWeiSuCDXlYF1BvaIb/y6SFJT10pt2j/ieCoUso=' 'sha256-MGGpAn2Mxetox/Sal+tbUhcayclbC+s0KAqzn8ngLUI=' 'sha256-wv0jEprp1q4yOyA9QyVeEL8qcUqFmfzQq2tV9/0m1IY='". Either the 'unsafe-inline' keyword, a hash ('sha256-9uFLu5CG8mWlvx0LK6lgendCxUX57TuWk3wkgZpBeWU='), or a nonce ('nonce-...') is required to enable inline execution.

setup/:29
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https://maps.google.com https://accounts.google.com https://www.google-analytics.com 'sha256-xFjzoWeiSuCDXlYF1BvaIb/y6SFJT10pt2j/ieCoUso=' 'sha256-MGGpAn2Mxetox/Sal+tbUhcayclbC+s0KAqzn8ngLUI=' 'sha256-wv0jEprp1q4yOyA9QyVeEL8qcUqFmfzQq2tV9/0m1IY='". Either the 'unsafe-inline' keyword, a hash ('sha256-3N2Z+Nu++/yNMVHIl863JigVmt2Nr9gt2doEMJT2Wzk='), or a nonce ('nonce-...') is required to enable inline execution.

EDIT:
I built the standard Dockerfile in the root of the project.

###################
# STAGE 1: builder
###################

FROM node:22-bullseye AS builder

ARG MB_EDITION=oss
ARG VERSION

WORKDIR /home/node

RUN apt-get update && apt-get upgrade -y && apt-get install wget apt-transport-https gpg curl git -y \
    && wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg > /dev/null \
    && echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list \
    && apt-get update \
    && apt install temurin-21-jdk -y \
    && curl -O https://download.clojure.org/install/linux-install-1.12.0.1488.sh \
    && chmod +x linux-install-1.12.0.1488.sh \
    && ./linux-install-1.12.0.1488.sh

COPY . .

# version is pulled from git, but git doesn't trust the directory due to different owners
RUN git config --global --add safe.directory /home/node

# install frontend dependencies
RUN yarn --frozen-lockfile

RUN INTERACTIVE=false CI=true MB_EDITION=$MB_EDITION bin/build.sh :version ${VERSION}

# ###################
# # STAGE 2: runner
# ###################

## Remember that this runner image needs to be the same as bin/docker/Dockerfile with the exception that this one grabs the
## jar from the previous stage rather than the local build
## we're not yet there to provide an ARM runner till https://github.com/adoptium/adoptium/issues/96 is ready

FROM eclipse-temurin:21-jre-alpine AS runner

ENV FC_LANG=en-US LC_CTYPE=en_US.UTF-8

# dependencies
RUN apk add -U bash fontconfig curl font-noto font-noto-arabic font-noto-hebrew font-noto-cjk java-cacerts && \
    apk upgrade && \
    rm -rf /var/cache/apk/* && \
    mkdir -p /app/certs && \
    curl https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem -o /app/certs/rds-combined-ca-bundle.pem  && \
    /opt/java/openjdk/bin/keytool -noprompt -import -trustcacerts -alias aws-rds -file /app/certs/rds-combined-ca-bundle.pem -keystore /etc/ssl/certs/java/cacerts -keypass changeit -storepass changeit && \
    curl https://cacerts.digicert.com/DigiCertGlobalRootG2.crt.pem -o /app/certs/DigiCertGlobalRootG2.crt.pem  && \
    /opt/java/openjdk/bin/keytool -noprompt -import -trustcacerts -alias azure-cert -file /app/certs/DigiCertGlobalRootG2.crt.pem -keystore /etc/ssl/certs/java/cacerts -keypass changeit -storepass changeit && \
    mkdir -p /plugins && chmod a+rwx /plugins

# add Metabase script and uberjar
COPY --from=builder /home/node/target/uberjar/metabase.jar /app/
COPY bin/docker/run_metabase.sh /app/

# expose our default runtime port
EXPOSE 3000

# run it
ENTRYPOINT ["/app/run_metabase.sh"]

Using the command docker build -t local-metabase --build-arg VERSION=v0.54.4 .
And I'm trying to deploy this in Portainer using the following stack:

services:
  metabase:
    image: local-metabase
    container_name: local-metabase
    hostname: metabase-local
    restart: unless-stopped
    volumes:
      - volume_metabase:/dev/random:ro
    ports:
      - 5110:3000
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: ${PG_DB}
      MB_DB_PORT: 5432
      MB_DB_USER: ${PG_USER}
      MB_DB_PASS: ${PG_PASSWORD}
      MB_DB_HOST: postgres
    healthcheck:
      test: curl --fail -I http://localhost:3000/api/health || exit 1
      interval: 15s
      timeout: 5s
      retries: 5
    networks:
      - reverse-proxy
    labels:
      - "traefik.http.routers.metabase.rule=Host(`localhost`)"

  postgres:
    image: postgres:latest
    container_name: postgres
    hostname: postgres
    restart: unless-stopped
    tty: true
    stdin_open: true
    environment:
      POSTGRES_USER: ${PG_USER}
      POSTGRES_DB: ${PG_DB}
      POSTGRES_PASSWORD: ${PG_PASSWORD}
    volumes:
      - /home/devadmin/dockerdata/postgresql/data:/var/lib/postgresql/data:rw
    networks:
      - reverse-proxy

  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pgadmin
    restart: unless-stopped
    ports:
      - 5102:80
    volumes:
      - volume_pgadmin:/var/lib/pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGA_USER}
      PGADMIN_DEFAULT_PASSWORD: ${PGA_PASSWORD}
    depends_on:
      - postgres
    networks:
      - reverse-proxy
    labels:
      - "traefik.http.routers.pgadmin.rule=Host(`localhost`)"
      - "traefik.http.routers.pgadmin.entrypoints=web"

volumes:
  volume_pgadmin:
    name: volume_pgadmin_local
  volume_metabase:
    name: volume_metabase_local

networks:
  reverse-proxy:
    external: true

Also I have a Traefik stack running apart from this one.

Hello there,

The recommended way of running Metabase in Docker/Docker compose is by using the official image metabase/metabase instead of building it.

Are trying to build a fork/custom version of Metabase? If that's the case, please share the parts of the Dockerfile/build script where you build it so we can get more context.

Thanks!

Yes I am trying to build a fork/custom version. I built the standard Dockerfile in the root of the project.

###################
# STAGE 1: builder
###################

FROM node:22-bullseye AS builder

ARG MB_EDITION=oss
ARG VERSION

WORKDIR /home/node

RUN apt-get update && apt-get upgrade -y && apt-get install wget apt-transport-https gpg curl git -y \
    && wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg > /dev/null \
    && echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list \
    && apt-get update \
    && apt install temurin-21-jdk -y \
    && curl -O https://download.clojure.org/install/linux-install-1.12.0.1488.sh \
    && chmod +x linux-install-1.12.0.1488.sh \
    && ./linux-install-1.12.0.1488.sh

COPY . .

# version is pulled from git, but git doesn't trust the directory due to different owners
RUN git config --global --add safe.directory /home/node

# install frontend dependencies
RUN yarn --frozen-lockfile

RUN INTERACTIVE=false CI=true MB_EDITION=$MB_EDITION bin/build.sh :version ${VERSION}

# ###################
# # STAGE 2: runner
# ###################

## Remember that this runner image needs to be the same as bin/docker/Dockerfile with the exception that this one grabs the
## jar from the previous stage rather than the local build
## we're not yet there to provide an ARM runner till https://github.com/adoptium/adoptium/issues/96 is ready

FROM eclipse-temurin:21-jre-alpine AS runner

ENV FC_LANG=en-US LC_CTYPE=en_US.UTF-8

# dependencies
RUN apk add -U bash fontconfig curl font-noto font-noto-arabic font-noto-hebrew font-noto-cjk java-cacerts && \
    apk upgrade && \
    rm -rf /var/cache/apk/* && \
    mkdir -p /app/certs && \
    curl https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem -o /app/certs/rds-combined-ca-bundle.pem  && \
    /opt/java/openjdk/bin/keytool -noprompt -import -trustcacerts -alias aws-rds -file /app/certs/rds-combined-ca-bundle.pem -keystore /etc/ssl/certs/java/cacerts -keypass changeit -storepass changeit && \
    curl https://cacerts.digicert.com/DigiCertGlobalRootG2.crt.pem -o /app/certs/DigiCertGlobalRootG2.crt.pem  && \
    /opt/java/openjdk/bin/keytool -noprompt -import -trustcacerts -alias azure-cert -file /app/certs/DigiCertGlobalRootG2.crt.pem -keystore /etc/ssl/certs/java/cacerts -keypass changeit -storepass changeit && \
    mkdir -p /plugins && chmod a+rwx /plugins

# add Metabase script and uberjar
COPY --from=builder /home/node/target/uberjar/metabase.jar /app/
COPY bin/docker/run_metabase.sh /app/

# expose our default runtime port
EXPOSE 3000

# run it
ENTRYPOINT ["/app/run_metabase.sh"]

Using the command docker build -t local-metabase --build-arg VERSION=v0.54.4 .
And I'm trying to deploy this in Portainer using the following stack:

services:
  metabase:
    image: local-metabase
    container_name: local-metabase
    hostname: metabase-local
    restart: unless-stopped
    volumes:
      - volume_metabase:/dev/random:ro
    ports:
      - 5110:3000
    environment:
      MB_DB_TYPE: postgres
      MB_DB_DBNAME: ${PG_DB}
      MB_DB_PORT: 5432
      MB_DB_USER: ${PG_USER}
      MB_DB_PASS: ${PG_PASSWORD}
      MB_DB_HOST: postgres
    healthcheck:
      test: curl --fail -I http://localhost:3000/api/health || exit 1
      interval: 15s
      timeout: 5s
      retries: 5
    networks:
      - reverse-proxy
    labels:
      - "traefik.http.routers.metabase.rule=Host(`localhost`)"

  postgres:
    image: postgres:latest
    container_name: postgres
    hostname: postgres
    restart: unless-stopped
    tty: true
    stdin_open: true
    environment:
      POSTGRES_USER: ${PG_USER}
      POSTGRES_DB: ${PG_DB}
      POSTGRES_PASSWORD: ${PG_PASSWORD}
    volumes:
      - /home/devadmin/dockerdata/postgresql/data:/var/lib/postgresql/data:rw
    networks:
      - reverse-proxy

  pgadmin:
    image: dpage/pgadmin4:latest
    container_name: pgadmin
    restart: unless-stopped
    ports:
      - 5102:80
    volumes:
      - volume_pgadmin:/var/lib/pgadmin
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGA_USER}
      PGADMIN_DEFAULT_PASSWORD: ${PGA_PASSWORD}
    depends_on:
      - postgres
    networks:
      - reverse-proxy
    labels:
      - "traefik.http.routers.pgadmin.rule=Host(`localhost`)"
      - "traefik.http.routers.pgadmin.entrypoints=web"

volumes:
  volume_pgadmin:
    name: volume_pgadmin_local
  volume_metabase:
    name: volume_metabase_local

networks:
  reverse-proxy:
    external: true

Also I have a Traefik stack running apart from this one.
I hope this helps a bit more with understanding my problem.

I have another question to add to this.
Do I have to make a release build using the github workflows or is this not necessary for creating a production build from a fork?

You don't need to do anything from Github workflows, building it locally is completely fine.

I'd go about this in incremental checkpoints:

  • First, this is just a sanity check, using the official image, docker run -p 3000:3000 metabase/metabase should work fine if you enter localhost:3000
  • Then, you can start a container from the image you built, no compose or env: docker run -p 3000:3000 local-metabase. If this fails, try checking out a tag (instead of master), running something like git checkout v54.4.4 and build again + run again.
  • If that worked, you can put that image in a docker-compose as a single service, and again visit the page to see if it works. You can start adding configs on the metabase service and check if there are any issues.
  • After that, you can add the remaining components of your stack and see if anything breaks.

Try that out and let me know if you found anything else

I did everything you told me:

  • First I used the official image and it ran perfectly fine.
  • Then I went to the master branch without any changes where I tried to build an image but got an error about line endings so I changed all .sh files and .bash files to LF line endigs instead of CRLF. After this it built succesfully with the command docker build -t local-metabase --build-arg VERSION=oss . and started the container using the command docker run -p 3000:3000 local-metabase but again I got a blank screen.
  • After it didn't work on the master branch I checked out the tag v0.54.4 and executed the same steps I did with the master branch and again I got a blank screen.

Here's a screenshot of my browser when I started the container:

Here is the first error:

Here is the second error:

Here is the third error:

This is in Edge but the exact same happens if I'm on Chrome or Firefox

Looks like when you cloned the repo, git converted all line endings to CRLF because of the git setting core.autocrlf=true. It could be causing problems on how the CSP header is generated in Metabase vs. the actual JS file hashes on Windows when line endings are changed.
Can you try cloning it again but preserving the original LF line endings by setting git's core.autocrlf=false? Or even downloading the ZIP from Github should preserve the original line endings and build normally.

1 Like

Marcos you are the best!! This was exactly the problem now it works perfectly.

1 Like