trying to setup dynamic nginx

This commit is contained in:
Gabriel Matte 2024-11-10 20:42:02 -05:00
parent 80115f050c
commit 678d1c2250
9 changed files with 236 additions and 48 deletions

View file

@ -34,7 +34,7 @@ const JoinRoom: React.FC = () => {
}, []);
const handleCreateSocket = () => {
const socket = webSocketService.connect("localhost:4500");
const socket = webSocketService.connect(`/api/room/${roomName}/socket`);
socket.on('join-success', () => {
setIsWaitingForTeacher(true);

View file

@ -79,9 +79,10 @@ const ManageRoom: React.FC = () => {
}
};
const createWebSocketRoom = () => {
const createWebSocketRoom = async() => {
setConnectingError('');
const socket = webSocketService.connect("localhost:4500");
const room = await(await fetch('/api/room',{method:'post'})).json();
const socket = webSocketService.connect(`/api/room/${room.id}/socket`);
socket.on('connect', () => {
webSocketService.createRoom();

View file

@ -1,3 +1,69 @@
FROM nginx
# Stage 1: Build stage
FROM nginx:1.27-alpine AS builder
COPY ./default.conf /etc/nginx/conf.d/default.conf
# Install required packages
RUN apk add --no-cache nginx-mod-http-js nginx-mod-http-keyval
# Stage 2: Final stage
FROM alpine:3.19
# Copy Nginx and NJS modules from builder
COPY --from=builder /usr/sbin/nginx /usr/sbin/
COPY --from=builder /usr/lib/nginx/modules/ /usr/lib/nginx/modules/
COPY --from=builder /etc/nginx/ /etc/nginx/
COPY --from=builder /usr/lib/nginx/ /usr/lib/nginx/
# Install required runtime dependencies
RUN apk add --no-cache \
pcre2 \
ca-certificates \
pcre \
libgcc \
libstdc++ \
zlib \
libxml2 \
libedit \
geoip \
libxslt \
&& mkdir -p /var/cache/nginx \
&& mkdir -p /var/log/nginx \
&& mkdir -p /etc/nginx/conf.d \
&& mkdir -p /etc/nginx/njs \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& addgroup -S nginx \
&& adduser -D -S -h /var/cache/nginx -s /sbin/nologin -G nginx nginx
# Copy necessary libraries from builder
COPY --from=builder /usr/lib/libxml2.so* /usr/lib/
COPY --from=builder /usr/lib/libexslt.so* /usr/lib/
COPY --from=builder /usr/lib/libgd.so* /usr/lib/
COPY --from=builder /usr/lib/libxslt.so* /usr/lib/
# Modify nginx.conf to load modules
RUN echo 'load_module modules/ngx_http_js_module.so;' > /tmp/nginx.conf && \
cat /etc/nginx/nginx.conf >> /tmp/nginx.conf && \
mv /tmp/nginx.conf /etc/nginx/nginx.conf
# Copy our configuration
COPY conf.d/default.conf /etc/nginx/conf.d/
COPY njs/main.js /etc/nginx/njs/
# Set proper permissions
RUN chown -R nginx:nginx /var/cache/nginx \
&& chown -R nginx:nginx /var/log/nginx \
&& chown -R nginx:nginx /etc/nginx/conf.d \
&& touch /var/run/nginx.pid \
&& chown -R nginx:nginx /var/run/nginx.pid
# Verify the configuration
# RUN nginx -t --dry-run
# Switch to non-root user
USER nginx
# Expose HTTP port
EXPOSE 80
# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

60
nginx/conf.d/default.conf Normal file
View file

@ -0,0 +1,60 @@
js_import njs/main.js;
js_set $quiz_room_host main.getQuizRoomHost;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Cache for room information
# keyval_zone zone=rooms:10m;
# keyval_zone zone=room_hosts:10m;
# keyval $room_id $room_info zone=rooms;
upstream frontend {
server frontend:5173;
}
upstream backend {
server backend:3000;
}
server {
listen 80;
location /api {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
}
location /socket.io {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_hide_header 'Access-Control-Allow-Origin';
}
location /quiz/([^/]+)/socket {
# Routing logic
set $room_id $1;
js_content main.routeWebSocket;
#Proxy headers
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
location / {
proxy_pass http://frontend;
}
}

60
nginx/conf.d/local.conf Normal file
View file

@ -0,0 +1,60 @@
js_import njs/main.js;
js_set $quiz_room_host main.getQuizRoomHost;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
# Cache for room information
# keyval_zone zone=rooms:10m;
# keyval_zone zone=room_hosts:10m;
# keyval $room_id $room_info zone=rooms;
upstream frontend {
server localhost:5173;
}
upstream backend {
server localhost:3000;
}
server {
listen 80;
location /api {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
}
location /socket.io {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_hide_header 'Access-Control-Allow-Origin';
}
location /quiz/([^/]+)/socket {
# Routing logic
set $room_id $1;
js_content main.routeWebSocket;
#Proxy headers
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_buffering off;
}
location / {
proxy_pass http://frontend;
}
}

View file

@ -1,31 +0,0 @@
upstream frontend {
server frontend:5173;
}
upstream backend {
server backend:3000;
}
server {
listen 80;
location /api {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
}
location /socket.io {
rewrite /backend/(.*) /$1 break;
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_hide_header 'Access-Control-Allow-Origin';
}
location / {
proxy_pass http://frontend;
}
}

43
nginx/njs/main.js Normal file
View file

@ -0,0 +1,43 @@
async function fetchRoomInfo(r) {
try {
// Make request to API to get room info
let res = await r.subrequest(`/api/room/${r.variables.room_id}`);
if (res.status !== 200) {
r.error(`Failed to fetch room info: ${res.status}`);
return null;
}
return JSON.parse(res.responseText);
} catch (error) {
r.error(`Error fetching room info: ${error}`);
return null;
}
}
// Main routing function for WebSocket connections
async function routeWebSocket(r) {
try {
const roomInfo = await fetchRoomInfo(r);
if (!roomInfo || !roomInfo.host) {
r.return(404, 'Room not found or invalid');
return;
}
// Route the WebSocket connection to the room's host
r.internalRedirect(`@quiz_room_${roomInfo.host}`);
} catch (error) {
r.error(`WebSocket routing error: ${error}`);
r.return(500, 'Internal routing error');
}
}
// Helper function to get room host for dynamic upstream
function getQuizRoomHost(r) {
const roomInfo = JSON.parse(r.variables.room_info);
return roomInfo.host || '';
}
export default { routeWebSocket, getQuizRoomHost };

View file

@ -1,5 +1,5 @@
# Use the Node base image
FROM node:18 as quizroom
FROM node:18 AS quizroom
# Create a working directory
WORKDIR /usr/src/app

View file

@ -45,20 +45,9 @@ router.get("/:id", async (req, res) => {
try {
const data = await roomsController.getRoomStatus();
res.json(data);
} catch (error) {
res.status(500).json({ error: "Failed to join rooms" });
}
});
router.get("/:id/status", async (req, res) => {
try {
const data = await roomsController.getRoomStatus(req.params.id);
res.json(data);
} catch (error) {
res.status(500).json({ error: "Failed to list room infos" });
}
});
module.exports = router;