asemxin commited on
Commit
6b10e4d
·
1 Parent(s): c3431ec

Use Python aiohttp for reverse proxy + static files

Browse files
Files changed (2) hide show
  1. Dockerfile +7 -43
  2. server.py +102 -0
Dockerfile CHANGED
@@ -12,55 +12,19 @@ RUN git clone https://github.com/ycvk/monica-proxy.git .
12
  RUN go mod download
13
  RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o monica-proxy main.go
14
 
15
- # Stage 2: Runtime with nginx
16
- FROM alpine:latest
17
 
18
- RUN apk --no-cache add ca-certificates tzdata nginx
19
 
20
  WORKDIR /app
21
 
22
  COPY --from=builder /app/monica-proxy .
23
- COPY index.html /usr/share/nginx/html/
 
24
 
25
- # nginx config
26
- RUN cat > /etc/nginx/http.d/default.conf << 'EOF'
27
- server {
28
- listen 7860;
29
-
30
- root /usr/share/nginx/html;
31
- index index.html;
32
-
33
- # Exact match for root path - highest priority
34
- location = / {
35
- default_type text/html;
36
- alias /usr/share/nginx/html/index.html;
37
- }
38
-
39
- # API endpoints - proxy to monica-proxy
40
- location /v1 {
41
- proxy_pass http://127.0.0.1:8080;
42
- proxy_http_version 1.1;
43
- proxy_set_header Host $host;
44
- proxy_set_header X-Real-IP $remote_addr;
45
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
46
- proxy_set_header X-Forwarded-Proto $scheme;
47
- proxy_buffering off;
48
- proxy_read_timeout 300s;
49
- }
50
- }
51
- EOF
52
-
53
- # Start script
54
- RUN cat > /app/start.sh << 'EOF'
55
- #!/bin/sh
56
- # Start monica-proxy in background on port 8080
57
- SERVER_PORT=8080 SERVER_HOST=0.0.0.0 ./monica-proxy &
58
- # Start nginx in foreground
59
- nginx -g 'daemon off;'
60
- EOF
61
-
62
- RUN chmod +x /app/start.sh
63
 
64
  EXPOSE 7860
65
 
66
- CMD ["/app/start.sh"]
 
12
  RUN go mod download
13
  RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o monica-proxy main.go
14
 
15
+ # Stage 2: Runtime with Python proxy
16
+ FROM python:3.11-alpine
17
 
18
+ RUN apk --no-cache add ca-certificates tzdata
19
 
20
  WORKDIR /app
21
 
22
  COPY --from=builder /app/monica-proxy .
23
+ COPY index.html .
24
+ COPY server.py .
25
 
26
+ RUN pip install --no-cache-dir aiohttp
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  EXPOSE 7860
29
 
30
+ CMD ["python", "server.py"]
server.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Simple reverse proxy + static file server for Monica Proxy
3
+ """
4
+ import asyncio
5
+ import subprocess
6
+ import os
7
+ from aiohttp import web, ClientSession, ClientTimeout
8
+
9
+ BACKEND_PORT = 8080
10
+ FRONTEND_PORT = 7860
11
+
12
+ async def proxy_handler(request: web.Request):
13
+ """Proxy requests to monica-proxy backend"""
14
+ backend_url = f"http://127.0.0.1:{BACKEND_PORT}{request.path_qs}"
15
+
16
+ async with ClientSession(timeout=ClientTimeout(total=300)) as session:
17
+ try:
18
+ headers = {k: v for k, v in request.headers.items()
19
+ if k.lower() not in ('host', 'content-length')}
20
+
21
+ body = await request.read() if request.can_read_body else None
22
+
23
+ async with session.request(
24
+ method=request.method,
25
+ url=backend_url,
26
+ headers=headers,
27
+ data=body,
28
+ ) as resp:
29
+ response_body = await resp.read()
30
+ return web.Response(
31
+ status=resp.status,
32
+ headers={k: v for k, v in resp.headers.items()
33
+ if k.lower() not in ('content-encoding', 'transfer-encoding', 'content-length')},
34
+ body=response_body
35
+ )
36
+ except Exception as e:
37
+ return web.json_response(
38
+ {"error": str(e), "message": "Backend connection failed"},
39
+ status=502
40
+ )
41
+
42
+ async def index_handler(request: web.Request):
43
+ """Serve the status page"""
44
+ return web.FileResponse('index.html')
45
+
46
+ async def start_backend():
47
+ """Start monica-proxy in background"""
48
+ env = os.environ.copy()
49
+ env['SERVER_PORT'] = str(BACKEND_PORT)
50
+ env['SERVER_HOST'] = '0.0.0.0'
51
+
52
+ process = await asyncio.create_subprocess_exec(
53
+ './monica-proxy',
54
+ env=env,
55
+ stdout=asyncio.subprocess.PIPE,
56
+ stderr=asyncio.subprocess.STDOUT
57
+ )
58
+
59
+ # Log backend output
60
+ async def log_output():
61
+ while True:
62
+ line = await process.stdout.readline()
63
+ if not line:
64
+ break
65
+ print(f"[backend] {line.decode().strip()}")
66
+
67
+ asyncio.create_task(log_output())
68
+ return process
69
+
70
+ async def main():
71
+ # Start backend
72
+ print(f"Starting monica-proxy on port {BACKEND_PORT}...")
73
+ backend = await start_backend()
74
+
75
+ # Give backend time to start
76
+ await asyncio.sleep(2)
77
+
78
+ # Setup web server
79
+ app = web.Application()
80
+ app.router.add_get('/', index_handler)
81
+ app.router.add_route('*', '/v1/{path:.*}', proxy_handler)
82
+ app.router.add_route('*', '/{path:.*}', proxy_handler)
83
+
84
+ runner = web.AppRunner(app)
85
+ await runner.setup()
86
+
87
+ site = web.TCPSite(runner, '0.0.0.0', FRONTEND_PORT)
88
+ print(f"Starting frontend on port {FRONTEND_PORT}...")
89
+ await site.start()
90
+
91
+ print(f"Server ready!")
92
+ print(f" Status page: http://0.0.0.0:{FRONTEND_PORT}/")
93
+ print(f" API: http://0.0.0.0:{FRONTEND_PORT}/v1/...")
94
+
95
+ # Keep running
96
+ try:
97
+ await asyncio.Event().wait()
98
+ finally:
99
+ backend.terminate()
100
+
101
+ if __name__ == '__main__':
102
+ asyncio.run(main())