Задать вопрос
  • Как переписать скрипт чтоб без pgrep?

    @Quqas Автор вопроса
    ок. спасибо добрый человек. попробую (результат не сразу смогу огласить)

    возможно даже радикально слишком улучшено, аж все if fi ушли. (для моего уровня понимания лихо....)

    т.е. по сути первой строки с присвоением переменной достаточно? а остальное же можно оставить как было... но можно и по новому варику =результат типа 0 или 1 возврат, как мне "видится"
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    т.е. не указывая полный путь, просто по имени сервиса, ровно всё тоже самое
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    Rsa97, ок
    значит я и в первый раз, умозрительно был прав - вся "польза" от systemctl в "экономии" пути к service-файлу
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    Rsa97, дело не в папке\пути
    а в самом принципе
    что типа повторный вызов с аргументом - позволяет рулить
    для этого ессно нужно чтоб файл их понимал

    и казалось бы service или systemctl должны обходить необходимость чтоб "файл" это умел
    но это неточно..
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    Rsa97,
    не сталкивался чтоб банально exec и путь к "службе"
    это ж надо чтоб тот файл понимал аргументы и т.п.

    а если это понимание обязательное условие - то на кой тогда systemctl? всё тоже самое но экономия в написании пути?
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    каким то бесом непосредственно через сам скрипт

    exec(ROOT_DIR . "/etc/init.d/" . ****

    крайне затейливо. и пока ещё неясно до конца что там в *** прописывать
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    вот как это
    $response = nfqwsServiceAction($_POST['cmd']);
    интерпретировать?
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    нашёл таки php но не в браузере а как файл

    php

    <?php
    
    ini_set('memory_limit', '32M');
    
    define('ROOT_DIR', file_exists('/opt/etc/nfqws/nfqws.conf') ? '/opt' : '');
    define('SCRIPT_NAME', ROOT_DIR ? 'S51nfqws' : 'nfqws-keenetic');
    
    function normalizeString(string $s): string {
        // Convert all line-endings to UNIX format.
        $s = str_replace(array("\r\n", "\r", "\n"), "\n", $s);
    
        // Don't allow out-of-control blank lines.
        $s = preg_replace("/\n{3,}/", "\n\n", $s);
    
        $lastChar = substr($s, -1);
        if ($lastChar !== "\n" && !empty($s)) {
            $s .= "\n";
        }
    
        return $s;
    }
    
    function getFiles($path = ROOT_DIR . '/etc/nfqws'): array {
        // GLOB_BRACE is unsupported in openwrt
        $files = array_filter(glob($path . '/*'), function ($file) {
            return is_file($file) && preg_match('/\.(list|list-opkg|list-old|conf|conf-opkg|conf-old|apk-new)$/i', $file);
        });
        $logfile = ROOT_DIR . '/var/log/nfqws.log';
        $basenames = array_map(fn($file) => basename($file), $files);
        if (file_exists($logfile)) {
            array_push($basenames, basename($logfile));
        }
    
        $priority = ['nfqws.conf' => -5, 'user.list' => -4, 'exclude.list' => -3, 'auto.list' => -2, 'nfqws.log' => -1];
        usort($basenames, fn($a, $b) => ($priority[$a] ?? 1) - ($priority[$b] ?? -1));
    
        return $basenames;
    }
    
    function getFileContent(string $filename, $path = ROOT_DIR . '/etc/nfqws'): string {
        return file_get_contents($path . '/' . basename($filename));
    }
    
    function getLogContent(string $filename, $path = ROOT_DIR . '/var/log'): string {
        $file = file($path . '/' . basename($filename));
        $file = array_reverse($file);
        return implode("", $file);
    }
    
    function saveFile(string $filename, string $content, $path = ROOT_DIR . '/etc/nfqws') {
        $filename = basename($filename);
        $file = $path . '/' . $filename;
        return file_exists($file) && file_put_contents($file, normalizeString($content)) !== false;
    }
    
    function saveLog(string $filename, string $content, $path = ROOT_DIR . '/var/log') {
        return saveFile($filename, $content, $path);
    }
    
    function removeFile(string $filename, $path = ROOT_DIR . '/etc/nfqws') {
        $filename = basename($filename);
        $file = $path . '/' . $filename;
        if (file_exists($file)) {
            return unlink($file);
        } else {
            return false;
        }
    }
    
    function nfqwsServiceStatus() {
        $output = null;
        exec(ROOT_DIR . "/etc/init.d/" . SCRIPT_NAME . " status", $output);
        return str_contains($output[0] ?? '', 'is running');
    }
    
    function nfqwsServiceAction(string $action) {
        $output = null;
        $retval = null;
        exec(ROOT_DIR . "/etc/init.d/" . SCRIPT_NAME . " $action", $output, $retval);
        return array('output' => $output, 'status' => $retval);
    }
    
    function opkgUpgradeAction() {
        $output = null;
        $retval = null;
        exec("opkg update && opkg upgrade nfqws-keenetic nfqws-keenetic-web", $output, $retval);
        if (empty($output)) {
            $output[] = 'Nothing to update';
        }
        return array('output' => $output, 'status' => $retval);
    }
    
    function apkUpgradeAction() {
        $output = null;
        $retval = null;
        exec("apk --update-cache add nfqws-keenetic nfqws-keenetic-web", $output, $retval);
        if (empty($output)) {
            $output[] = 'Nothing to update';
        }
        return array('output' => $output, 'status' => $retval);
    }
    
    function upgradeAction() {
        return file_exists('/usr/bin/apk') ? apkUpgradeAction() : opkgUpgradeAction();
    }
    
    function authenticate($username, $password) {
        $passwdFile = ROOT_DIR . '/etc/passwd';
        $shadowFile = ROOT_DIR . '/etc/shadow';
    
        $users = file(file_exists($shadowFile) ? $shadowFile : $passwdFile);
        $user = preg_grep("/^$username/", $users);
    
        if ($user) {
            list(, $passwdInDB) = explode(':', array_pop($user));
            if (empty($passwdInDB)) {
                return empty($password);
            }
            if (crypt($password, $passwdInDB) == $passwdInDB) {
                return true;
            }
        }
    
        return false;
    }
    
    function main() {
        if (!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'POST') {
            http_response_code(302);
            header('Location: index.html');
            exit();
        }
    
        session_start();
        if (!isset($_SESSION['auth']) || !$_SESSION['auth']) {
            if ($_POST['cmd'] !== 'login' || !isset($_POST['user']) || !isset($_POST['password']) || !authenticate($_POST['user'], $_POST['password'])) {
                http_response_code(401);
                exit();
            } else {
                $_SESSION['auth'] = true;
            }
        }
    
        switch ($_POST['cmd']) {
            case 'filenames':
                $files = getFiles();
                $response = array('status' => 0, 'files' => $files, 'service' => nfqwsServiceStatus());
                break;
    
            case 'filecontent':
                if (str_ends_with($_POST['filename'], '.log')) {
                    $content = getLogContent($_POST['filename']);
                } else {
                    $content = getFileContent($_POST['filename']);
                }
                $response = array('status' => 0, 'content' => $content, 'filename' => $_POST['filename']);
                break;
    
            case 'filesave':
                if (str_ends_with($_POST['filename'], '.log')) {
                    $result = saveLog($_POST['filename'], $_POST['content']);
                } else {
                    $result = saveFile($_POST['filename'], $_POST['content']);
                }
                $response = array('status' => $result ? 0 : 1, 'filename' => $_POST['filename']);
                break;
    
            case 'fileremove':
                $result = removeFile($_POST['filename']);
                $response = array('status' => $result ? 0 : 1, 'filename' => $_POST['filename']);
                break;
    
            case 'reload':
            case 'restart':
            case 'stop':
            case 'start':
                $response = nfqwsServiceAction($_POST['cmd']);
                break;
    
            case 'upgrade':
                $response = upgradeAction();
                break;
    
            case 'login':
                $response = array('status' => 0);
                break;
    
            case 'logout':
                $_SESSION['auth'] = false;
                $response = array('status' => 0);
                break;
    
            default:
                http_response_code(405);
                exit();
        }
    
        header('Content-Type: application/json; charset=utf-8');
        http_response_code(200);
        echo json_encode($response);
        exit();
    }
    
    main();

    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    и ещё скриптик короткий
    const TLN={eventList:{},update_line_numbers:function(e,t){let n=e.value.split("\n").length-t.children.length;if(n>0){const e=document.createDocumentFragment();for(;n>0;){const t=document.createElement("span");t.className="tln-line",e.appendChild(t),n--}t.appendChild(e)}for(;n<0;)t.removeChild(t.lastChild),n++},append_line_numbers:function(e){const t=document.getElementById(e);if(null==t)return console.warn("[tln.js] Couldn't find textarea of id '"+e+"'");if(-1!=t.className.indexOf("tln-active"))return console.warn("[tln.js] textarea of id '"+e+"' is already numbered");t.classList.add("tln-active"),t.style={};const n=document.createElement("div");n.className="tln-wrapper",t.parentNode.insertBefore(n,t),TLN.update_line_numbers(t,n),TLN.eventList[e]=[];const l=["propertychange","input","keydown","keyup"],o=function(e,t){return function(n){(10!=+e.scrollLeft||37!=n.keyCode&&37!=n.which&&"ArrowLeft"!=n.code&&"ArrowLeft"!=n.key)&&36!=n.keyCode&&36!=n.which&&"Home"!=n.code&&"Home"!=n.key&&13!=n.keyCode&&13!=n.which&&"Enter"!=n.code&&"Enter"!=n.key&&"NumpadEnter"!=n.code||(e.scrollLeft=0),TLN.update_line_numbers(e,t)}}(t,n);for(let n=l.length-1;n>=0;n--)t.addEventListener(l[n],o),TLN.eventList[e].push({evt:l[n],hdlr:o});const r=["change","mousewheel","scroll"],s=function(e,t){return function(){t.scrollTop=e.scrollTop}}(t,n);for(let n=r.length-1;n>=0;n--)t.addEventListener(r[n],s),TLN.eventList[e].push({evt:r[n],hdlr:s})},remove_line_numbers:function(e){const t=document.getElementById(e);if(null==t)return console.warn("[tln.js] Couldn't find textarea of id '"+e+"'");if(-1==t.className.indexOf("tln-active"))return console.warn("[tln.js] textarea of id '"+e+"' isn't numbered");t.classList.remove("tln-active");const n=t.previousSibling;if("tln-wrapper"==n.className&&n.remove(),TLN.eventList[e]){for(let n=TLN.eventList[e].length-1;n>=0;n--){const l=TLN.eventList[e][n];t.removeEventListener(l.evt,l.hdlr)}delete TLN.eventList[e]}}};
    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    php якобы нету
    тока html(f12+sources)
    index

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>nfqws-keenetic</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
        <link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
        <link rel="apple-touch-icon" href="icon.png">
        <link rel="icon" href="icon.png" sizes="192x192">
        <link rel="manifest" href="manifest.json">
        <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
        <meta http-equiv="Pragma" content="no-cache" />
        <meta http-equiv="Expires" content="0" />
    
        <meta name="MobileOptimized" content="320">
        <meta name="HandheldFriendly" content="true">
        <meta name="theme-color" media="(prefers-color-scheme: light)" content="#fff">
        <meta name="theme-color" media="(prefers-color-scheme: dark)" content="#1b2434">
        <meta name="color-scheme" content="light dark">
    
        <script defer src="tln.min.js?v=v2.8.4"></script>
        <script defer src="script.js?v=v2.8.4" type="module"></script>
    
        <link rel="stylesheet" href="tln.min.css?v=v2.8.4">
        <link rel="stylesheet" href="style.css?v=v2.8.4">
    </head>
    <body class="disabled unknown">
    <script>
        const theme = localStorage.getItem('theme');
        if (theme) {
            const root = document.querySelector(':root');
            root.dataset.theme = theme;
        }
    </script>
    
    <header>
        <h1 class="logo">nfqws-keenetic <span id="status"></span></h1>
        <button class="button red" id="save">Save</button>
        <button class="button" id="restart">Restart</button>
        <button class="button" id="dropdown"></button>
        <ul id="dropdown-menu" class="hidden">
            <li class="dropdown-item" id="reload">Reload</li>
            <li class="dropdown-item" id="stop">Stop</li>
            <li class="dropdown-item" id="start">Start</li>
            <li class="dropdown-item" id="upgrade">Update</li>
        </ul>
    </header>
    
    <nav></nav>
    
    <article>
        <div class="textarea-container">
            <textarea id="config" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" autofocus></textarea>
        </div>
    </article>
    
    <footer>
        <a class="footer-tab" href="https://github.com/Anonym-tsk/nfqws-keenetic/" target="_blank">GitHub</a>
        <a class="footer-tab" href="https://anonym-tsk.github.io/nfqws-keenetic/" target="_blank">Repository</a>
        <span id="theme" class="footer-tab" title="Change theme"></span>
        <span id="logout" class="footer-tab" title="Logout"></span>
        <span id="version">v2.8.4</span>
    </footer>
    
    <div id="overlay"></div>
    
    <div id="alert" class="popup hidden">
        <pre class="popup-content"></pre>
        <div class="popup-footer">
            <button class="popup-yes">Yes</button>
            <button class="popup-no">No</button>
            <button class="popup-close">Close</button>
        </div>
    </div>
    
    <div id="login-form" class="popup hidden">
        <div class="popup-content">
            <input type="text" class="login-input" id="login" autocomplete="false" autofocus placeholder="Login" />
            <input type="password" class="login-input" id="password" placeholder="Password" />
        </div>
        <div class="popup-footer">
            <button class="popup-yes">Login</button>
        </div>
    </div>
    
    </body>
    </html>

    Написано
  • Как js может управлять службой на хосте?

    @Quqas Автор вопроса
    начало скрипта

    class UI {
        constructor() {
            TLN.append_line_numbers('config');
    
            this.$tabs = document.querySelector('nav');
    
            this.buttons = this._initButtons();
            this.tabs = this._initTabs();
            this.textarea = this._initTextarea();
            this.version = this._initVersion();
            this.popup = this._initPopups();
            this.login = this._initLoginForm();
        }
    
        _initTabs() {
            const tabs = {};
            let currentFile = '';
    
            const add = (filename) => {
                const tab = document.createElement('div');
                tab.classList.add('nav-tab');
                tab.textContent = filename;
    
                const isConf = filename.endsWith('.conf');
                const isList = filename.endsWith('.list');
                const isLog = filename.endsWith('.log');
    
                if (isLog) {
                    const clear = document.createElement('div');
                    clear.classList.add('nav-clear');
                    clear.setAttribute('title', 'Clear log');
    
                    clear.addEventListener('click', async (e) => {
                        e.preventDefault();
                        e.stopPropagation();
    
                        const yesno = await this.popup.confirm('Clear log?');
                        if (!yesno) {
                            return;
                        }
    
                        const result = await saveFile(filename, '');
                        if (!result.status) {
                            if (filename === currentFile) {
                                this.textarea.value = '';
                            }
                        } else {
                            this.popup.alert(`clear ${filename}`, `Error: ${result.status}`);
                        }
                    });
    
                    tab.appendChild(clear);
                } else if (!isConf && !isList) {
                    tab.classList.add('secondary');
                    const trash = document.createElement('div');
                    trash.classList.add('nav-trash');
                    trash.setAttribute('title', 'Delete file');
    
                    trash.addEventListener('click', async (e) => {
                        e.preventDefault();
                        e.stopPropagation();
    
                        const yesno = await this.popup.confirm('Delete file?');
                        if (!yesno) {
                            return;
                        }
    
                        const result = await removeFile(filename);
                        if (!result.status) {
                            remove(filename);
                        } else {
                            this.popup.alert(`remove ${filename}`, `Error: ${result.status}`);
                        }
                    });
    
                    tab.appendChild(trash);
                }
    
                tab.addEventListener('click', async () => this.loadFile(filename));
    
                this.$tabs.appendChild(tab);
                tabs[filename] = tab;
            };
    
            const remove = (filename) => {
                for (const [key, tab] of Object.entries(tabs)) {
                    if (key === filename) {
                        tab.parentNode.removeChild(tab);
                        delete tabs[key];
    
                        if (filename === currentFile) {
                            this.textarea.save();
                            activateFirst();
                        }
                        break;
                    }
                }
            };
    
            const activate = (filename) => {
                for (const [key, tab] of Object.entries(tabs)) {
                    tab.classList.toggle('active', filename === key);
                    if (filename === key) {
                        currentFile = filename;
                    }
                }
            };
    
            const activateFirst = () => {
                Object.values(tabs)[0].click();
            };
    
            return {
                add,
                remove,
                activate,
                activateFirst,
                get currentFileName() {
                    return currentFile;
                }
            };
        }
    
        _initTextarea() {
            const element = document.getElementById('config');
            let originalText = element.value;
            let textChanged = false;
    
            const save = () => {
                originalText = element.value;
                textChanged = false;
                this.setChanged(false);
            };
    
            element.addEventListener('input', _debounce(() => {
                textChanged = element.value !== originalText;
                this.setChanged(textChanged);
            }, 300));
    
            element.addEventListener('keydown', (e) => {
                if ((e.ctrlKey || e.metaKey) && e.key === 's') {
                    e.preventDefault();
                    this.buttons.click();
                }
            });
    
            return {
                get value() {
                    return element.value;
                },
                set value(text) {
                    element.value = text;
                    save();
                    // Update line numbers
                    const event = new Event('input');
                    element.dispatchEvent(event);
                },
                get changed() {
                    return textChanged;
                },
                save,
                disabled(status) {
                    if (status) {
                        element.setAttribute('disabled', 'disabled');
                    } else {
                        element.removeAttribute('disabled');
                    }
                },
                readonly(status) {
                    if (status) {
                        element.setAttribute('readonly', 'readonly');
                    } else {
                        element.removeAttribute('readonly');
                    }
                },
            };
        }
    
        _initVersion() {
            const element = document.getElementById('version');
            const match = element.textContent.match(/^v([0-9]+)\.([0-9]+)\.([0-9]+)$/);
    
            const value = () => {
                return match ? [match[1], match[2], match[3]] : null;
            };
    
            const checkUpdate = async () => {
                if (!value()) {
                    return;
                }
    
                const latest = await getLatestVersion();
                if (!latest) {
                    return;
                }
    
                const updateAvailable = compareVersions(value(), latest);
                if (updateAvailable) {
                    const link = document.createElement('a');
                    const tag = `v${latest[0]}.${latest[1]}.${latest[2]}`;
                    link.textContent = `(${tag})`;
                    link.href = `https://github.com/Anonym-tsk/nfqws-keenetic/releases/tag/${tag}`;
                    link.target = '_blank';
                    element.appendChild(link);
                }
            };
    
            return {
                get value() {
                    return value();
                },
                checkUpdate,
            }
        }
    
        _initPopups() {
            const element = document.getElementById('alert');
            const alertContent = element.querySelector('.popup-content');
            const buttonClose = element.querySelector('.popup-close');
            const buttonYes = element.querySelector('.popup-yes');
            const buttonNo = element.querySelector('.popup-no');
    
            const alert = (...text) => {
                this.disableUI();
                alertContent.textContent = `> ${text.join("\n")}`;
                element.classList.add('alert');
                element.classList.remove('hidden', 'confirm', 'locked');
            };
    
            const hide = () => {
                element.classList.add('hidden');
                element.classList.remove('locked');
                this.enableUI();
            }
    
            const confirm = async (text) => {
                this.disableUI();
                alertContent.textContent = text;
                element.classList.add('confirm');
                element.classList.remove('hidden', 'alert', 'locked');
    
                return new Promise((resolve) => {
                    buttonYes.addEventListener('click', function ok() {
                        buttonYes.removeEventListener('click', ok);
                        resolve(true);
                    });
                    buttonNo.addEventListener('click', function fail() {
                        buttonNo.removeEventListener('click', fail);
                        resolve(false);
                    });
                });
            };
    
            const process = async (text, fn, ...args) => {
                this.disableUI();
                alertContent.textContent = `> ${text}\n`;
                element.classList.add('alert', 'locked');
                element.classList.remove('hidden', 'confirm');
                let status = true;
    
                const result = await fn(...args);
                if (!result.status) {
                    alertContent.textContent += Array.from(result.output).join("\n");
                } else {
                    alertContent.textContent += `Error: ${result.status}`;
                    status = false;
                }
                element.classList.remove('locked');
    
                return new Promise((resolve) => {
                    buttonClose.addEventListener('click', function close() {
                        buttonYes.removeEventListener('click', close);
                        resolve(status);
                    });
                });
            };
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0,
    Хотите - в HTTP-запросе представляйтесь веб браузером, не хотите - не представляйтесь...

    ну так именно этот момент и неясен. как это варьировать?
    в s_client кроме [-connect host:port] [-servername name]
    другие параметры не использовал и ихнее влияние неясно
    [-connect host:port] в случае извне
    могу два варианта. как домен 3го или 4го уровня - порт полюбасу 443 -- попадает извне на прокси
    а [-servername name] задаёт sni строго 4го уровня. именно по этому sni прокси переправлять и должен на внутренний ip\порт s_server. и с браузером работает (см.выше)

    но получается принудительно расшифровывается по пути?
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0, ну так а что именно не так? какбы вы написали труЪ команду для s_client ?
    и как быть с тем что посередине между client и server стоит https reverse proxy?
    браузер тоже например не тот серт использует при подключении извне(но до server таки долазит и кажет именно его страницу, но серт в свойствах от прокси). а изнутри таки серт от openssl s_server
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    ValdikSS,
    самого web-интерфейса роутера

    это-то вполне.
    любой внутренний и даже не очень ip(типа момеда который какбы "вовне" по отношению к роутеру)
    не пропустит не-web-трафик

    а вот это да. но начиналось то всё (в гугле) что ssh в этот самый web можно завернуть. но оказывается нельзя или нетольколишьвсе варианты tls заворачиваются
    но как-то труЪ https браузеров идёт, а остальное уже не очень. хотя обещали(в гугле) с три короба
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    ответить то ответили - но я не могу поставить рекомендованные "усложнения" nginx

    а s_client такое впечатление не может сквозь nginx прокси пролезть - и "руки-жмёт" с ним а не s_server (который тоже вовнутри сети)

    осталось только в этом на 146% убедится

    или совет как заставить таки "пробится" вовнутрь
    и тогда уже вовнутре ssl пойдёт ssh (но это да уже обсудили)
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    в случае браузера серт не сервака, а прокси становится (в самом браузере) но показывает именно страницу сервера
    может и s_client на первом попавшемся tls пытается соединится?
    хотя мысль что должен проходить через прокси внутрь до сервака.
    Написано
  • Как отдебажить почему openssl s_client не устанавливает туннель?

    @Quqas Автор вопроса
    AUser0, даже излишне много
    а понимания дошло до сервера или нет - не добавляет
    что именно в выводе надо искать?
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    но где такое в
    location / {
    proxy_pass http://127.0.0.1:22;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    }
    ?
    за вычетом того что у меня не localhost а другой ip
    https://dev.to/udara_dananjaya/how-to-access-ssh-o...
    тут некий стрим правда
    https://iyzico.engineering/proxy-ssh-using-tls-sni...
    но это на мой "ngnix " не поставить - можно лишь как в вопросе
    внутренний ip/порт и выбор https|http

    в обоих случаях с sshd ничего не делают
    и всё равно не понимаю как ssh сервер понимает https ? или из прокси он уже чистым ssh выходит? но назад обратно в https заворачивается?
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    нигде в советах про ковыряние на стороне ssh сервера ни слова
    Написано
  • SSH +reverse https proxy, при чём тут openSSL(VPN)?

    @Quqas Автор вопроса
    Т.е. чтобы приведённый пример работал, нужно чтобы на целевом сервере на 443 порту крутился какой-то реверс-прокси (точнее, TLS termination proxy), который распакует трафик из туннеля и пробросит его на порт, который слушает SSH-сервер. Имхо, SSH-сервер про эти фокусы вообще ничего не знает.

    это выполняется
    reverse proxy настроен
    слушает 443 и направляет на 222

    но вот на счёт что "распаковывает" не уверен и наоборот имхо вредно, либо ещё один прокси нужен? помимо внешнего ещё и внутренний?

    советы(читал и больше)
    https://dev.to/udara_dananjaya/how-to-access-ssh-o...

    https://iyzico.engineering/proxy-ssh-using-tls-sni...
    Написано