martynka commited on
Commit
daa52a6
·
verified ·
1 Parent(s): a08bc08

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +60 -28
Dockerfile CHANGED
@@ -8,15 +8,18 @@ RUN apk update && apk add --no-cache \
8
  python3 \
9
  py3-pip \
10
  sqlite \
11
- && pip3 install flask werkzeug --break-system-packages
12
-
13
- # Setup directories within /app
14
- RUN mkdir -p /app/admin/{templates,static} \
 
15
  && mkdir -p /app/data \
 
 
16
  && chmod -R 777 /app/client/public/images \
17
  && chmod -R 777 /app/api/logs
18
 
19
- # ===== Integrated Admin Panel =====
20
  COPY <<"EOF" /app/admin/app.py
21
  from flask import Flask, request, jsonify, render_template
22
  import os
@@ -27,9 +30,16 @@ from pathlib import Path
27
  app = Flask(__name__,
28
  template_folder=str(Path(__file__).parent/'templates'),
29
  static_folder=str(Path(__file__).parent/'static'))
 
 
 
 
 
 
 
30
  app.secret_key = os.getenv("FLASK_SECRET")
31
 
32
- # SQLite in /app/data (ephemeral in free HF Spaces)
33
  DB_PATH = '/app/data/admin.db'
34
 
35
  def get_db():
@@ -79,6 +89,19 @@ def list_users():
79
  return jsonify([
80
  {"username": row[0]} for row in db.execute("SELECT username FROM users")
81
  ])
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  EOF
83
 
84
  # Admin templates
@@ -163,7 +186,6 @@ button {
163
  }
164
  EOF
165
 
166
- # Properly escaped JavaScript
167
  COPY <<"EOF" /app/admin/static/admin.js
168
  async function loadUsers() {
169
  const response = await fetch('/sudo/list_users', {
@@ -212,47 +234,53 @@ document.getElementById('addUserForm').addEventListener('submit', async (e) => {
212
  });
213
 
214
  document.addEventListener('DOMContentLoaded', () => {
215
- if (!localStorage.getItem('sudo_token') && !window.location.pathname.includes('login')) {
 
216
  window.location.href = '/sudo';
 
 
217
  }
218
- loadUsers();
219
  });
220
  EOF
221
 
222
- # Add delete endpoint to app.py
223
- RUN echo '@app.route("/sudo/remove_user", methods=["POST"])' >> /app/admin/app.py
224
- RUN echo 'def remove_user():' >> /app/admin/app.py
225
- RUN echo ' if request.headers.get("X-Sudo-Secret") != os.getenv("SUDO_SECRET"):' >> /app/admin/app.py
226
- RUN echo ' return jsonify({"error": "Unauthorized"}), 403' >> /app/admin/app.py
227
- RUN echo ' db = get_db()' >> /app/admin/app.py
228
- RUN echo ' db.execute("DELETE FROM users WHERE username=?", [request.json["username"]])' >> /app/admin/app.py
229
- RUN echo ' db.commit()' >> /app/admin/app.py
230
- RUN echo ' return jsonify({"status": "User removed"})' >> /app/admin/app.py
231
-
232
  # NGINX Configuration
233
  COPY <<"EOF" /etc/nginx/nginx.conf
234
- events { worker_connections 1024; }
 
 
 
 
 
 
235
  http {
 
 
 
 
 
 
236
  server {
237
  listen 7860;
238
-
239
- # LibreChat API
240
  location / {
241
  proxy_pass http://localhost:3080;
242
  proxy_set_header Host \$host;
243
  proxy_set_header X-Real-IP \$remote_addr;
 
244
  }
245
-
246
- # Admin Panel
247
  location /sudo {
248
  proxy_pass http://localhost:5000;
249
  proxy_set_header X-Sudo-Secret \$http_x_sudo_secret;
250
  }
251
-
252
- # Static files
253
  location /static {
254
  alias /app/admin/static;
255
  }
 
 
 
256
  }
257
  }
258
  EOF
@@ -260,8 +288,12 @@ EOF
260
  # Startup script
261
  COPY <<"EOF" /start.sh
262
  #!/bin/sh
263
- # Start LibreChat
264
- cd /app/api && npm run backend &
 
 
 
 
265
 
266
  # Start Admin Panel
267
  cd /app/admin && python3 app.py &
 
8
  python3 \
9
  py3-pip \
10
  sqlite \
11
+ && pip3 install flask werkzeug \
12
+ && mkdir -p /var/lib/nginx/tmp \
13
+ && chown -R nginx:nginx /var/lib/nginx \
14
+ && chmod -R 770 /var/lib/nginx \
15
+ && mkdir -p /app/admin/{templates,static} \
16
  && mkdir -p /app/data \
17
+ && chown -R 1000:1000 /app \
18
+ && chmod -R 777 /app/uploads/temp \
19
  && chmod -R 777 /app/client/public/images \
20
  && chmod -R 777 /app/api/logs
21
 
22
+ # ===== Admin Panel =====
23
  COPY <<"EOF" /app/admin/app.py
24
  from flask import Flask, request, jsonify, render_template
25
  import os
 
30
  app = Flask(__name__,
31
  template_folder=str(Path(__file__).parent/'templates'),
32
  static_folder=str(Path(__file__).parent/'static'))
33
+
34
+ # Validate secrets
35
+ required_secrets = ['FLASK_SECRET', 'SUDO_SECRET']
36
+ for secret in required_secrets:
37
+ if not os.getenv(secret):
38
+ raise RuntimeError(f"Missing required secret: {secret}")
39
+
40
  app.secret_key = os.getenv("FLASK_SECRET")
41
 
42
+ # SQLite database
43
  DB_PATH = '/app/data/admin.db'
44
 
45
  def get_db():
 
89
  return jsonify([
90
  {"username": row[0]} for row in db.execute("SELECT username FROM users")
91
  ])
92
+
93
+ @app.route('/sudo/remove_user', methods=['POST'])
94
+ def remove_user():
95
+ if request.headers.get('X-Sudo-Secret') != os.getenv("SUDO_SECRET"):
96
+ return jsonify({"error": "Unauthorized"}), 403
97
+
98
+ db = get_db()
99
+ db.execute("DELETE FROM users WHERE username=?", [request.json["username"]])
100
+ db.commit()
101
+ return jsonify({"status": "User removed"})
102
+
103
+ if __name__ == "__main__":
104
+ app.run(host="0.0.0.0", port=5000)
105
  EOF
106
 
107
  # Admin templates
 
186
  }
187
  EOF
188
 
 
189
  COPY <<"EOF" /app/admin/static/admin.js
190
  async function loadUsers() {
191
  const response = await fetch('/sudo/list_users', {
 
234
  });
235
 
236
  document.addEventListener('DOMContentLoaded', () => {
237
+ const token = localStorage.getItem('sudo_token');
238
+ if (!token && !window.location.pathname.includes('login')) {
239
  window.location.href = '/sudo';
240
+ } else if (token) {
241
+ loadUsers();
242
  }
 
243
  });
244
  EOF
245
 
 
 
 
 
 
 
 
 
 
 
246
  # NGINX Configuration
247
  COPY <<"EOF" /etc/nginx/nginx.conf
248
+ user nginx;
249
+ worker_processes auto;
250
+
251
+ events {
252
+ worker_connections 1024;
253
+ }
254
+
255
  http {
256
+ include /etc/nginx/mime.types;
257
+ default_type application/octet-stream;
258
+ sendfile on;
259
+ keepalive_timeout 65;
260
+ client_max_body_size 20M;
261
+
262
  server {
263
  listen 7860;
264
+ server_name localhost;
265
+
266
  location / {
267
  proxy_pass http://localhost:3080;
268
  proxy_set_header Host \$host;
269
  proxy_set_header X-Real-IP \$remote_addr;
270
+ proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
271
  }
272
+
 
273
  location /sudo {
274
  proxy_pass http://localhost:5000;
275
  proxy_set_header X-Sudo-Secret \$http_x_sudo_secret;
276
  }
277
+
 
278
  location /static {
279
  alias /app/admin/static;
280
  }
281
+
282
+ access_log /dev/stdout;
283
+ error_log /dev/stderr;
284
  }
285
  }
286
  EOF
 
288
  # Startup script
289
  COPY <<"EOF" /start.sh
290
  #!/bin/sh
291
+ # Fix permissions
292
+ chown -R nginx:nginx /var/lib/nginx
293
+ chmod -R 770 /var/lib/nginx
294
+
295
+ # Start LibreChat (using the correct command)
296
+ cd /app && npm run start:backend &
297
 
298
  # Start Admin Panel
299
  cd /app/admin && python3 app.py &