Skip to content

Not able to deploy to a cloud VM behind a firewall #1024

Closed
@icejean

Description

@icejean

Hi,all,
I just try to deploy Neo4j Knowledge Graph Builder to a public cloud VM behind a firewall for a demo & research purpose, but I'm not able to work out a solution yet, here's the problem details.
As shown in the following network graph, the backend is serving at 172.18.0.2:4000, the frontend is serving at 172.18.0.3:4040, they are running with docker on a Ubuntu 22 host with a list of IPs,the IP 172.18.0.1 is for connetion with docker networks, the IP 172.17.0.1 is for accessing Ubuntu host services from the backend and frontend container, and the IP 10.60.136.78 is for public service to Windows ReAct Client, it's mapped to IP 117.50.174.65 by firewall to the public.

Image

As the CORS rule of browser requires that ReAct Javascript client need to request backend within the same domain, I need to deploy a Nginx server and setup reverse proxy for frontend and backend. But the Nginx server can only access backend service at 172.17.0.1:4000, not at 172.18.0.2:4000, frontend is the same also:

(base) root@10-60-136-78:~# curl http://172.18.0.2:4000
(base) root@10-60-136-78:~# curl http://172.17.0.1:4000
{"detail":"Not Found"}(base)
 root@10-60-136-78:~# 
(base) root@10-60-136-78:~# curl http://172.18.0.3:4040
(base) root@10-60-136-78:~# curl http://172.17.0.1:4040
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="icon" type="image/png" sizes="32x32" href="/kgbuilder/favicons/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="194x194" href="/kgbuilder/favicons/favicon-194x194.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/kgbuilder/favicons/favicon-16x16.png">
    <link rel="shortcut icon" href="/kgbuilder/favicons/favicon.ico">
    <title>Neo4j graph builder</title>
    <script type="module" crossorigin src="/kgbuilder/assets/index-1f639c8d.js"></script>
    <link rel="stylesheet" href="/kgbuilder/assets/index-03e5dd9e.css">
  </head>
  <body>
    <div id="root"></div>
    
  </body>
</html>

So I config Nginx reverse proxy as follow to put frontend and backend into the same domain:

# frontend
location /kgbuilder/ {
    rewrite ^/kgbuilder/(.*)$ /$1 break;

    proxy_pass http://172.17.0.1:4040;  
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    sub_filter 'href="/assets/' 'href="/kgbuilder/assets/';
    sub_filter 'src="/assets/' 'src="/kgbuilder/assets/';
    sub_filter 'url("/assets/' 'url("/kgbuilder/assets/';
    sub_filter_once off;

    # WebSocket 
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 20d;

    proxy_buffering off;
}

# backend
location /kgbuilderapi/ {
    rewrite ^/kgbuilderapi/(.*)$ /$1 break;

    proxy_pass http://172.17.0.1:4000;  
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    sub_filter_once off;

    # WebSocket 
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_read_timeout 20d;

    proxy_buffering off;
}

I add an environment variable to .env to tell the frontend base and point the backend URI to the reverse proxy public URI :

# Optional Backend

# Added by Jean 2025/01/20
LANGUAGE="chinese"

EMBEDDING_MODEL="all-MiniLM-L6-v2"
IS_EMBEDDING="true"
KNN_MIN_SCORE="0.94"
# Enable Gemini (default is False) | Can be False or True
GEMINI_ENABLED=False
# LLM_MODEL_CONFIG_ollama_llama3="llama3,http://host.docker.internal:11434"

# Added by Jean 2024/11/17
LLM_MODEL_CONFIG_openai_gpt_4o="gpt-4o,sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
LLM_MODEL_CONFIG_openai_gpt_4o_mini="gpt-4o-mini,sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
LLM_MODEL_CONFIG_openai_gpt_3_5="gpt-3.5-turbo,sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
HTTP_PROXY="http://172.17.0.1:7890"
HTTPS_PROXY="http://172.17.0.1:7890"

# Enable Google Cloud logs (default is False) | Can be False or True
GCP_LOG_METRICS_ENABLED=False
NUMBER_OF_CHUNKS_TO_COMBINE=6
UPDATE_GRAPH_CHUNKS_PROCESSED=20

NEO4J_URI="bolt://host.docker.internal:7687"
NEO4J_USERNAME="neo4j"
NEO4J_PASSWORD="xxxxxxxxxxxx"

# Comment out by Jean, 2024/11/7
LANGCHAIN_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
LANGCHAIN_PROJECT=""
LANGCHAIN_TRACING_V2="false"
LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"

GCS_FILE_CACHE=False
ENTITY_EMBEDDING=True

# Optional Frontend
VITE_BACKEND_API_URL="http://117.50.174.65/kgbuilderapi"

# Added by Jean 2025/01/23
VITE_FRONTEND_BASE_PATH="/kgbuilder/"

VITE_BLOOM_URL="https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true"
VITE_REACT_APP_SOURCES="local,youtube,wiki,s3,web"
VITE_ENV="DEV"
VITE_TIME_PER_PAGE=50
VITE_CHUNK_SIZE=5242880
VITE_GOOGLE_CLIENT_ID=""
VITE_CHAT_MODES=""
VITE_BATCH_SIZE=2

#VITE_LLM_MODELS="diffbot,openai_gpt_3_5,openai_gpt_4o,openai_gpt_4o_mini" # ",ollama_llama3"
VITE_LLM_MODELS_PROD="openai_gpt_4o,openai_gpt_4o_mini,openai_gpt_3_5,diffbot"

And modify ~/frontend/vite.config.ts as follow to set a frontend base path:

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';

// see https://stackoverflow.com/questions/73834404/react-uncaught-referenceerror-process-is-not-defined
// otherwise use import.meta.env.VITE_BACKEND_API_URL and expose it as such with the VITE_ prefix
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), 'VITE_');
  const frontendBasePath = env.VITE_FRONTEND_BASE_PATH || '/';  // default root path
  return {
    base: frontendBasePath,  //  base
    define: {
      'process.env': env,
    },
    plugins: [react()],
    optimizeDeps: { esbuildOptions: { target: 'es2020' } },
  };
});

Then modify ~/frontend/Dockerfile to point the the backend to the reverse proxy URI too.

# ARG VITE_BACKEND_API_URL="http://172.18.0.2:4000"
ARG VITE_BACKEND_API_URL="http://117.50.174.65/kgbuilderapi"

And here is the file docker-compose.yml, export extra host to activate 171.17.0.1 and map frontend to 4040, backend to 4000:

version: "3"

services:
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile
    volumes:
      - ./backend:/code
    environment:
      - NEO4J_URI=${NEO4J_URI-neo4j://database:7687}
      - NEO4J_PASSWORD=${NEO4J_PASSWORD-password}
      - NEO4J_USERNAME=${NEO4J_USERNAME-neo4j}
      - OPENAI_API_KEY=${OPENAI_API_KEY-}
      - DIFFBOT_API_KEY=${DIFFBOT_API_KEY-}
      - EMBEDDING_MODEL=${EMBEDDING_MODEL-all-MiniLM-L6-v2}
      - LANGCHAIN_ENDPOINT=${LANGCHAIN_ENDPOINT-}
      - LANGCHAIN_TRACING_V2=${LANGCHAIN_TRACING_V2-}
      - LANGCHAIN_PROJECT=${LANGCHAIN_PROJECT-}
      - LANGCHAIN_API_KEY=${LANGCHAIN_API_KEY-}
      - KNN_MIN_SCORE=${KNN_MIN_SCORE-0.94}
      - IS_EMBEDDING=${IS_EMBEDDING-true}
      - GEMINI_ENABLED=${GEMINI_ENABLED-False}
      - GCP_LOG_METRICS_ENABLED=${GCP_LOG_METRICS_ENABLED-False}
      - UPDATE_GRAPH_CHUNKS_PROCESSED=${UPDATE_GRAPH_CHUNKS_PROCESSED-20}
      - NUMBER_OF_CHUNKS_TO_COMBINE=${NUMBER_OF_CHUNKS_TO_COMBINE-6}
      - ENTITY_EMBEDDING=${ENTITY_EMBEDDING-False}
      - GCS_FILE_CACHE=${GCS_FILE_CACHE-False}
      # - LLM_MODEL_CONFIG_ollama_llama3=${LLM_MODEL_CONFIG_ollama_llama3-}
      # Added by Jean, 2024/11/7
      - LLM_MODEL_CONFIG_openai_gpt_4o=${LLM_MODEL_CONFIG_openai_gpt_4o-}
      - LLM_MODEL_CONFIG_openai_gpt_4o_mini=${LLM_MODEL_CONFIG_openai_gpt_4o_mini-}
      - LLM_MODEL_CONFIG_openai_gpt_3_5=${LLM_MODEL_CONFIG_openai_gpt_3_5-}
      - HTTP_PROXY=${HTTP_PROXY}
      - HTTPS_PROXY=${HTTPS_PROXY}
      - http_proxy=${HTTP_PROXY}
      - https_proxy=${HTTPS_PROXY}
      # Added by Jean 2025/1/20
      - LANGUAGE=${LANGUAGE-english}

    # env_file:
    #   - ./backend/.env
    container_name: backend
    extra_hosts:
      - host.docker.internal:host-gateway
    ports:
      - "4000:8000"
    networks:
      - net

  frontend:
    depends_on:
      - backend
    build:
      context: ./frontend
      dockerfile: Dockerfile
      args:
        - VITE_BACKEND_API_URL=${VITE_BACKEND_API_URL-http://localhost:8000}
        - VITE_REACT_APP_SOURCES=${VITE_REACT_APP_SOURCES-local,wiki,s3}
        - VITE_GOOGLE_CLIENT_ID=${VITE_GOOGLE_CLIENT_ID-}
        - VITE_BLOOM_URL=${VITE_BLOOM_URL-https://workspace-preview.neo4j.io/workspace/explore?connectURL={CONNECT_URL}&search=Show+me+a+graph&featureGenAISuggestions=true&featureGenAISuggestionsInternal=true}
        - VITE_TIME_PER_PAGE=${VITE_TIME_PER_PAGE-50}
        - VITE_CHUNK_SIZE=${VITE_CHUNK_SIZE-5242880}
        - VITE_LARGE_FILE_SIZE=${VITE_LARGE_FILE_SIZE-5242880}
        - VITE_ENV=${VITE_ENV-DEV}
        - VITE_CHAT_MODES=${VITE_CHAT_MODES-}
        - VITE_BATCH_SIZE=${VITE_BATCH_SIZE-2}
        - VITE_LLM_MODELS=${VITE_LLM_MODELS-}
        - VITE_LLM_MODELS_PROD=${VITE_LLM_MODELS_PROD-openai_gpt_4o,openai_gpt_4o_mini,diffbot,gemini_1.5_flash}
        - DEPLOYMENT_ENV=local

        - HTTP_PROXY=${HTTP_PROXY}
        - HTTPS_PROXY=${HTTPS_PROXY}
        - http_proxy=${HTTP_PROXY}
        - https_proxy=${HTTPS_PROXY}


    volumes:
      - ./frontend:/app
      - /app/node_modules

    # Added by Jean, 2024/11/7
    environment:
      - HTTP_PROXY=${HTTP_PROXY}
      - HTTPS_PROXY=${HTTPS_PROXY}
      - http_proxy=${HTTP_PROXY}
      - https_proxy=${HTTPS_PROXY}

    env_file:
      - ./frontend/.env
    container_name: frontend
    extra_hosts:
      - host.docker.internal:host-gateway      
    ports:
      - "4040:8080"
    networks:
      - net

networks:
  net:

The running result is:

Unexpected Application Error!
404 Not Found

Image

The source of index.html seems to be O.K..

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="icon" type="image/png" sizes="32x32" href="/kgbuilder/favicons/favicon-32x32.png">
    <link rel="icon" type="image/png" sizes="194x194" href="/kgbuilder/favicons/favicon-194x194.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/kgbuilder/favicons/favicon-16x16.png">
    <link rel="shortcut icon" href="/kgbuilder/favicons/favicon.ico">
    <title>Neo4j graph builder</title>
    <script type="module" crossorigin src="/kgbuilder/assets/index-1f639c8d.js"></script>
    <link rel="stylesheet" href="/kgbuilder/assets/index-03e5dd9e.css">
  </head>
  <body>
    <div id="root"></div>
    
  </body>
</html>

Frontend logs:

frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:11 +0000] "GET / HTTP/1.1" 200 785 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:11 +0000] "GET /assets/index-1f639c8d.js HTTP/1.1" 200 3602835 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:11 +0000] "GET /assets/index-03e5dd9e.css HTTP/1.1" 200 3572661 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:29 +0000] "GET /favicons/favicon-16x16.png HTTP/1.1" 200 545 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:29 +0000] "GET /favicons/favicon-194x194.png HTTP/1.1" 200 3352 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:29 +0000] "GET /assets/public-sans-700-bold-normal-39dc2fce.woff2 HTTP/1.1" 200 14752 "http://117.50.174.65/kgbuilder/assets/index-03e5dd9e.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"
frontend  | 172.18.0.1 - - [23/Jan/2025:19:52:29 +0000] "GET /assets/syne-neo-500-medium-normal-5d4117ae.woff2 HTTP/1.1" 200 25580 "http://117.50.174.65/kgbuilder/assets/index-03e5dd9e.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0" "14.26.197.74"

Nginx logs:

14.26.197.74 - - [24/Jan/2025:03:52:11 +0800] "GET /kgbuilder/ HTTP/1.1" 200 388 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:14 +0800] "GET /kgbuilder/assets/index-1f639c8d.js HTTP/1.1" 200 3602835 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:28 +0800] "GET /kgbuilder/assets/index-03e5dd9e.css HTTP/1.1" 200 3572661 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:29 +0800] "GET /kgbuilder/favicons/favicon-16x16.png HTTP/1.1" 200 545 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:29 +0800] "GET /kgbuilder/favicons/favicon-194x194.png HTTP/1.1" 200 3352 "http://117.50.174.65/kgbuilder/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:29 +0800] "GET /kgbuilder/assets/public-sans-700-bold-normal-39dc2fce.woff2 HTTP/1.1" 200 14752 "http://117.50.174.65/kgbuilder/assets/index-03e5dd9e.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"
14.26.197.74 - - [24/Jan/2025:03:52:29 +0800] "GET /kgbuilder/assets/syne-neo-500-medium-normal-5d4117ae.woff2 HTTP/1.1" 200 25580 "http://117.50.174.65/kgbuilder/assets/index-03e5dd9e.css" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0"

No Nginx error log is there, so the error must happens in the ReAct client side with those Javascript, maybe with a wrong URL that hasn't been properly dealed with reverse proxy, but I just can't figure it out.

Suggest supporting this feature to deploy it to a cloud VM behind a firewall.

Best regards
Jean

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions