diff --git a/.gitignore b/.gitignore index 1eefaf7..0146427 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ node_modules/ .github_pat .env +.venv backups/* caddy @@ -17,3 +18,11 @@ mosquitto/data/* postgres/data/* config.json spa + +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions \ No newline at end of file diff --git a/Caddyfile.dev b/Caddyfile.dev index a05dadd..95311ea 100644 --- a/Caddyfile.dev +++ b/Caddyfile.dev @@ -9,9 +9,7 @@ localhost { reverse_proxy meshinfo:9000 } handle_path /next/* { - root * /srv/next - try_files {path} /index.html - file_server + reverse_proxy frontend:80 } handle /* { root * /srv diff --git a/Caddyfile.sample b/Caddyfile.sample index f476359..4507089 100644 --- a/Caddyfile.sample +++ b/Caddyfile.sample @@ -14,6 +14,6 @@ YOUR_FQDN_OR_HOSTNAME { reverse_proxy meshinfo:9000 } handle_path /next/* { - reverse_proxy meshinfo-spa:8000 + reverse_proxy frontend:80 } } diff --git a/Dockerfile.spa b/Dockerfile.spa index a794385..aa1cece 100644 --- a/Dockerfile.spa +++ b/Dockerfile.spa @@ -1,5 +1,5 @@ # trunk-ignore-all(checkov/CKV_DOCKER_3) -FROM node:20.11.1-alpine +FROM node:20.11.1-alpine AS build LABEL org.opencontainers.image.source="https://github.com/MeshAddicts/meshinfo" LABEL org.opencontainers.image.description="Realtime web UI to run against a Meshtastic regional or private mesh network." @@ -10,12 +10,14 @@ WORKDIR /frontend RUN corepack enable RUN yarn -RUN yarn build +RUN yarn build --base=/next/ -ENV API_BASE_URI="http://localhost:9000" +FROM nginx:alpine -HEALTHCHECK NONE +COPY --from=build /frontend/dist /usr/share/nginx/html/next -EXPOSE 8000 +COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf -CMD ["yarn", "run", "start"] +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/api/api.py b/api/api.py index 86cb637..40b3497 100644 --- a/api/api.py +++ b/api/api.py @@ -1,8 +1,10 @@ +import os from fastapi.encoders import jsonable_encoder import uvicorn from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse from fastapi.templating import Jinja2Templates +from fastapi.middleware.cors import CORSMiddleware from config import Config import utils @@ -176,6 +178,18 @@ async def stats(request: Request) -> JSONResponse: async def server_config(request: Request) -> JSONResponse: return jsonable_encoder({'config': Config.cleanse(self.config)}) + + allow_origins = os.getenv("ALLOW_ORIGINS", "").split(",") + print(f"Allowed origins: {allow_origins} {len(allow_origins)}") + + if(len(allow_origins) > 0): + app.add_middleware( + CORSMiddleware, + allow_origins=allow_origins, + allow_methods=["*"], + allow_headers=["*"] + ) + conf = uvicorn.Config(app=app, host="0.0.0.0", port=9000, loop=loop) server = uvicorn.Server(conf) print(f"Starting Uvicorn server bound at http://{conf.host}:{conf.port}") diff --git a/config.py b/config.py index 64f8227..400c572 100644 --- a/config.py +++ b/config.py @@ -27,7 +27,7 @@ def load_from_file(cls, path): @classmethod def cleanse(cls, config): - config_clean = config.deepcopy() + config_clean = config.copy() blacklist = { "config": { "broker": { diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index f14b1ee..8cef6ce 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -2,7 +2,7 @@ services: caddy: image: caddy:latest ports: - - 8000:80 + - 8001:80 - 8443:443 volumes: - ./caddy/data:/data/caddy @@ -32,6 +32,18 @@ services: - ./mosquitto/config:/mosquitto/config:rw restart: always + frontend: + build: + context: . + dockerfile: Dockerfile.spa + volumes: + - ./frontend/dist:/usr/share/nginx/html/next + ports: + - 8000:80 + environment: + - NODE_ENV=production + restart: always + meshinfo: build: context: . diff --git a/docker-compose.yml b/docker-compose.yml index 84d577e..1a9f74b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -38,17 +38,16 @@ services: frontend: image: ghcr.io/meshaddicts/meshinfo-spa:latest ports: - - 8000:3000 + - 8000:80 environment: - NODE_ENV=production - - API_BASE_URL=https://svm1.meshinfo.network/api restart: always caddy: image: caddy:latest ports: - 80:80 - - 443:443 + - 8443:443 volumes: - ./caddy/data:/data/caddy - ./Caddyfile:/etc/caddy/Caddyfile diff --git a/frontend/.env.sample b/frontend/.env.sample index d6d7ad3..089251f 100644 --- a/frontend/.env.sample +++ b/frontend/.env.sample @@ -1,3 +1 @@ -VITE_MESH_DESCRIPTION=Serving Meshtastic to the Central Valley and surrounding areas. -VITE_MESH_URL=https://sacvalleymesh.com -VITE_MESH_SERVER_NODE=!4355f528 \ No newline at end of file +VITE_API_BASE_URL=http://localhost:9000 \ No newline at end of file diff --git a/frontend/.yarn/install-state.gz b/frontend/.yarn/install-state.gz index 9b34f19..0578a7b 100644 Binary files a/frontend/.yarn/install-state.gz and b/frontend/.yarn/install-state.gz differ diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..25fa959 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,14 @@ +server { + listen 80; + + root /usr/share/nginx/html; + index index.html; + + location /api/ { + proxy_pass http://meshinfo:9000/; + } + + location / { + try_files $uri $uri/ /next/index.html; + } +} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 3e5acb6..4969406 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,8 +11,10 @@ }, "dependencies": { "@reduxjs/toolkit": "^2.2.5", + "@types/node": "^22.5.1", "autoprefixer": "^10.4.19", "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "ol": "^9.2.4", "postcss": "^8.4.38", "react": "^18.2.0", diff --git a/frontend/src/components/HardwareImg.tsx b/frontend/src/components/HardwareImg.tsx index 4073901..dfa1300 100644 --- a/frontend/src/components/HardwareImg.tsx +++ b/frontend/src/components/HardwareImg.tsx @@ -15,7 +15,7 @@ export const HardwareImg = ({ model }: { model: number }) => { return ( {