opex792 commited on
Commit
7a2f0ce
·
verified ·
1 Parent(s): a212b95

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +37 -0
  2. package.js +13 -0
  3. server.js +109 -0
Dockerfile ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Используем официальный образ Node.js. LTS (Long Term Support) версия рекомендуется.
2
+ # slim-версия меньше по размеру.
3
+ FROM node:20-slim
4
+
5
+ # Установка ssh-клиента, необходимого для localhost.run
6
+ # и других полезных утилит, если они понадобятся.
7
+ # Выполняем от имени root перед сменой пользователя.
8
+ RUN apt-get update && apt-get install -y openssh-client curl && \
9
+ rm -rf /var/lib/apt/lists/*
10
+
11
+ # Создаем пользователя и группу appuser для запуска приложения (лучшая практика)
12
+ RUN groupadd -r appgroup && useradd -r -g appgroup -m -s /bin/bash appuser
13
+ RUN mkdir -p /home/appuser/app && chown -R appuser:appgroup /home/appuser/app
14
+
15
+ # Устанавливаем пользователя appuser
16
+ USER appuser
17
+
18
+ # Устанавливаем рабочую директорию внутри контейнера
19
+ WORKDIR /home/appuser/app
20
+
21
+ # Копируем package.json и package-lock.json (если есть)
22
+ # --chown гарантирует, что файлы принадлежат appuser
23
+ COPY --chown=appuser:appgroup package*.json ./
24
+
25
+ # Устанавливаем зависимости приложения
26
+ # Используем --omit=dev, если есть devDependencies, которые не нужны в production
27
+ RUN npm install --omit=dev
28
+
29
+ # Копируем остальной код приложения в рабочую директорию
30
+ COPY --chown=appuser:appgroup . .
31
+
32
+ # Открываем порты. 7860 - для Hugging Face, 3000 - для внутреннего Express-сервера
33
+ EXPOSE 7860
34
+ EXPOSE 3000
35
+
36
+ # Команда для запуска приложения при старте контейнера
37
+ CMD ["node", "server.js"]
package.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "docker-tunnel-hf-space",
3
+ "version": "1.0.0",
4
+ "description": "Node.js Express app with localhost.run tunnel and a second server for Hugging Face.",
5
+ "main": "server.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "start": "node server.js"
9
+ },
10
+ "dependencies": {
11
+ "express": "^4.19.2"
12
+ }
13
+ }
server.js ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ import http from 'http';
3
+ import { spawn } from 'child_process';
4
+ import url from 'url';
5
+
6
+ const EXPRESS_PORT = 3000; // Внутренний порт для Express-приложения (для туннеля)
7
+ const HF_PORT = 7860; // Порт для Hugging Face
8
+
9
+ // Функция для форматирования информации о запросе
10
+ function formatRequestInfo(req, isExpress = true) {
11
+ let info = 'ИНФОРМАЦИЯ О ЗАПРОСЕ:\n\n';
12
+
13
+ // Основная информация
14
+ info += `Метод запроса: ${req.method}\n`;
15
+ info += `URL: ${isExpress ? req.originalUrl : req.url}\n`;
16
+ info += `IP клиента: ${isExpress ? req.ip : req.socket.remoteAddress}\n\n`;
17
+
18
+ // Query параметры
19
+ const queryParams = isExpress ? req.query : url.parse(req.url, true).query;
20
+ info += 'QUERY ПАРАМЕТРЫ:\n';
21
+ if (Object.keys(queryParams).length === 0) {
22
+ info += '(нет параметров)\n';
23
+ } else {
24
+ for (const [key, value] of Object.entries(queryParams)) {
25
+ info += `${key}: ${value}\n`;
26
+ }
27
+ }
28
+ info += '\n';
29
+
30
+ // Заголовки запроса
31
+ info += 'ЗАГОЛОВКИ ЗАПРОСА:\n';
32
+ const headers = req.headers;
33
+ for (const [key, value] of Object.entries(headers)) {
34
+ info += `${key}: ${value}\n`;
35
+ }
36
+
37
+ // User-Agent (информация о браузере)
38
+ info += '\nИНФОРМАЦИЯ О БРАУЗЕРЕ:\n';
39
+ info += headers['user-agent'] || 'Информация недоступна';
40
+
41
+ return info;
42
+ }
43
+
44
+ // --- Сервер 1: Express-приложение для localhost.run ---
45
+ const app = express();
46
+
47
+ app.get('*', (req, res) => {
48
+ const requestInfo = formatRequestInfo(req);
49
+ res.setHeader('Content-Type', 'text/plain; charset=utf-8');
50
+ res.send(requestInfo);
51
+ });
52
+
53
+ app.listen(EXPRESS_PORT, () => {
54
+ console.log(`Express server (для туннеля) слушает порт ${EXPRESS_PORT}`);
55
+
56
+ // Запускаем туннель localhost.run ПОСЛЕ того, как Express-сервер стартовал
57
+ console.log(`Попытка запустить туннель localhost.run для порта ${EXPRESS_PORT}...`);
58
+ const tunnel = spawn('ssh', [
59
+ '-R', `80:localhost:${EXPRESS_PORT}`, // Туннелируем порт 80 публичного URL на наш localhost:EXPRESS_PORT
60
+ '-o', 'StrictHostKeyChecking=no', // Отключаем проверку ключа хоста для автоматизации
61
+ '-o', 'UserKnownHostsFile=/dev/null', // Не сохраняем ключи хостов
62
+ '-o', 'ServerAliveInterval=60', // Поддерживать соединение активным
63
+ '-o', 'ExitOnForwardFailure=yes', // Выйти, если форвардинг не удался
64
+ 'nokey@localhost.run'
65
+ ]);
66
+
67
+ tunnel.stdout.on('data', (data) => {
68
+ const output = data.toString();
69
+ console.log(`localhost.run stdout: ${output}`);
70
+ // Попытка извлечь URL из вывода
71
+ const urlMatch = output.match(/https?:\/\/[a-zA-Z0-9-]+\.lhr\.life/);
72
+ if (urlMatch) {
73
+ console.log(`>>> Туннель активен: ${urlMatch[0]}`);
74
+ }
75
+ });
76
+
77
+ tunnel.stderr.on('data', (data) => {
78
+ console.error(`localhost.run stderr: ${data}`);
79
+ });
80
+
81
+ tunnel.on('close', (code) => {
82
+ console.log(`Процесс localhost.run завершился с кодом ${code}`);
83
+ });
84
+
85
+ tunnel.on('error', (err) => {
86
+ console.error('Не удалось запустить процесс localhost.run:', err);
87
+ });
88
+ });
89
+
90
+ // --- Сервер 2: Простой HTTP-сервер для Hugging Face на порту 7860 ---
91
+ const server2 = http.createServer((req, res) => {
92
+ const requestInfo = formatRequestInfo(req, false);
93
+ res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
94
+ res.end(requestInfo);
95
+ });
96
+
97
+ server2.listen(HF_PORT, () => {
98
+ console.log(`Второй HTTP-сервер (для Hugging Face) слушает порт ${HF_PORT}`);
99
+ });
100
+
101
+ // Обработка сигналов для корректного завершения
102
+ process.on('SIGINT', () => {
103
+ console.log('Получен SIGINT. Завершение...');
104
+ process.exit(0);
105
+ });
106
+ process.on('SIGTERM', () => {
107
+ console.log('Получен SIGTERM. Завершение...');
108
+ process.exit(0);
109
+ });