<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://wiki.ramba-art.ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Artem</id>
	<title>RAMBA Wiki - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.ramba-art.ru/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Artem"/>
	<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Artem"/>
	<updated>2026-10-22T03:13:20Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.43.9</generator>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Git_komand&amp;diff=166</id>
		<title>Git komand</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Git_komand&amp;diff=166"/>
		<updated>2026-09-30T13:12:45Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «&amp;#039;&amp;#039;&amp;#039;Git&amp;#039;&amp;#039;&amp;#039; — система контроля версий. Она позволяет сохранять историю изменений, работать с ветками и обмениваться кодом через удалённый репозиторий, например GitLab или GitHub.  На этой странице собраны команды из памятки &amp;#039;&amp;#039;Git_useful_commands.pdf&amp;#039;&amp;#039; с уточнёнными описаниям...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Git&#039;&#039;&#039; — система контроля версий. Она позволяет сохранять историю изменений, работать с ветками и обмениваться кодом через удалённый репозиторий, например GitLab или GitHub.&lt;br /&gt;
&lt;br /&gt;
На этой странице собраны команды из памятки &#039;&#039;Git_useful_commands.pdf&#039;&#039; с уточнёнными описаниями и практическими примерами.&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Как устроена работа с Git ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Понятие !! Что означает&lt;br /&gt;
|-&lt;br /&gt;
| Рабочая папка || Файлы проекта, которые вы редактируете.&lt;br /&gt;
|-&lt;br /&gt;
| Индекс (staging area) || Подготовленные изменения для следующего коммита. В индекс попадает состояние файла на момент выполнения &amp;lt;code&amp;gt;git add&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Коммит || Сохранённая версия подготовленных изменений в локальной истории Git.&lt;br /&gt;
|-&lt;br /&gt;
| Ветка || Отдельная линия разработки, например &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; или &amp;lt;code&amp;gt;feature/new-command&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Удалённый репозиторий || Репозиторий на другом компьютере или сервере. Обычно его короткое имя — &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Обычная последовательность: &#039;&#039;&#039;изменить файлы → проверить изменения → git add → git commit → git push&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; коммит сохраняет изменения локально. Чтобы отправить коммиты на сервер, нужна отдельная команда &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Проверка и создание репозитория ==&lt;br /&gt;
&lt;br /&gt;
=== git --version — версия Git ===&lt;br /&gt;
&lt;br /&gt;
Показывает установленную версию Git.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git --version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git init — создать локальный репозиторий ===&lt;br /&gt;
&lt;br /&gt;
Инициализирует репозиторий в текущей папке. Создаёт служебный каталог &amp;lt;code&amp;gt;.git&amp;lt;/code&amp;gt;, в котором Git хранит историю и настройки. Файлы проекта автоматически в коммит не попадают.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd my-project&lt;br /&gt;
git init&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Дополнительно: git clone — скачать существующий проект ===&lt;br /&gt;
&lt;br /&gt;
Создаёт локальную копию удалённого репозитория и обычно настраивает для него имя &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;. Замените адрес на URL своего проекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://gitlab.example.com/team/my-project.git&lt;br /&gt;
cd my-project&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После &amp;lt;code&amp;gt;git clone&amp;lt;/code&amp;gt; выполнять &amp;lt;code&amp;gt;git init&amp;lt;/code&amp;gt; не требуется.&lt;br /&gt;
&lt;br /&gt;
== Проверка изменений ==&lt;br /&gt;
&lt;br /&gt;
=== git status — состояние проекта ===&lt;br /&gt;
&lt;br /&gt;
Показывает текущую ветку, подготовленные изменения, изменения вне индекса и новые неотслеживаемые файлы. Игнорируемые файлы по умолчанию не выводятся.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Краткий вариант:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status -sb&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git diff — посмотреть изменения ===&lt;br /&gt;
&lt;br /&gt;
Показывает разницу между рабочей папкой и индексом: изменения в отслеживаемых файлах, которые ещё не подготовлены к коммиту.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть изменения, уже подготовленные к следующему коммиту:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff --staged&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть изменения конкретного файла вне индекса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff -- README.md&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Обратите внимание:&#039;&#039;&#039; обычный &amp;lt;code&amp;gt;git diff&amp;lt;/code&amp;gt; не показывает содержимое новых неотслеживаемых файлов. Если изменения уже добавлены через &amp;lt;code&amp;gt;git add&amp;lt;/code&amp;gt;, смотрите их через &amp;lt;code&amp;gt;git diff --staged&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Подготовка и сохранение изменений ==&lt;br /&gt;
&lt;br /&gt;
=== git add — подготовить изменения ===&lt;br /&gt;
&lt;br /&gt;
Добавляет в индекс новые файлы, изменения и удаления в указанной области.&lt;br /&gt;
&lt;br /&gt;
Все изменения в текущей папке и её подпапках, кроме игнорируемых неотслеживаемых файлов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add .&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Только выбранный файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add README.md&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Несколько файлов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add README.md bot/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если после &amp;lt;code&amp;gt;git add&amp;lt;/code&amp;gt; снова отредактировать файл, новые правки нужно добавить повторно. Перед массовым добавлением проверьте &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt;, чтобы в коммит не попали пароли, токены или ненужные файлы.&lt;br /&gt;
&lt;br /&gt;
=== git commit -m — сохранить коммит ===&lt;br /&gt;
&lt;br /&gt;
Создаёт локальный коммит из изменений в индексе. Параметр &amp;lt;code&amp;gt;-m&amp;lt;/code&amp;gt; задаёт сообщение с описанием изменений.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Добавлена команда просмотра статистики&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пишите, что именно изменилось. Например: &amp;lt;code&amp;gt;Исправлено переподключение к Telegram&amp;lt;/code&amp;gt; вместо &amp;lt;code&amp;gt;update&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Работа с удалённым репозиторием ==&lt;br /&gt;
&lt;br /&gt;
=== git remote — список подключений ===&lt;br /&gt;
&lt;br /&gt;
Показывает короткие имена настроенных удалённых репозиториев, например &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;upstream&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git remote -v — адреса репозиториев ===&lt;br /&gt;
&lt;br /&gt;
Показывает имена и URL для получения изменений (&amp;lt;code&amp;gt;fetch&amp;lt;/code&amp;gt;) и отправки (&amp;lt;code&amp;gt;push&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для нового проекта, созданного через &amp;lt;code&amp;gt;git init&amp;lt;/code&amp;gt;, подключение можно добавить отдельно. Репозиторий на сервере должен уже существовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git remote add origin https://gitlab.example.com/team/my-project.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git push — отправить коммиты на сервер ===&lt;br /&gt;
&lt;br /&gt;
Отправляет локальные коммиты и обновляет соответствующие ветки на сервере согласно параметрам команды и настройкам Git. Незакоммиченные правки не отправляются.&lt;br /&gt;
&lt;br /&gt;
Если для текущей ветки уже настроена связь с удалённой веткой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При первой отправке новой ветки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git push -u origin feature/new-command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; настраивает отслеживаемую удалённую ветку для последующих команд. Замените &amp;lt;code&amp;gt;feature/new-command&amp;lt;/code&amp;gt; на имя своей ветки.&lt;br /&gt;
&lt;br /&gt;
=== git pull — получить и включить изменения ===&lt;br /&gt;
&lt;br /&gt;
Получает изменения с сервера и включает их в текущую ветку. Способ включения зависит от параметров и настроек: слияние, rebase или только fast-forward.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git pull&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для обычного обновления без автоматического создания коммита слияния:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git pull --ff-only&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если локальная и удалённая истории разошлись, &amp;lt;code&amp;gt;--ff-only&amp;lt;/code&amp;gt; остановит обновление. Перед обновлением проверьте &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt; и сохраните текущую работу коммитом или через &amp;lt;code&amp;gt;git stash&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Просмотр истории ==&lt;br /&gt;
&lt;br /&gt;
=== git log — история коммитов ===&lt;br /&gt;
&lt;br /&gt;
Показывает коммиты, доступные из текущей точки истории: идентификатор, автора, дату и сообщение. Это не только ваши коммиты и не обязательно история всех веток.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git log&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последние десять коммитов в кратком виде:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git log --oneline -10&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Граф истории по всем локально известным веткам:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git log --oneline --graph --decorate --all&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вывод открылся в просмотрщике, для выхода обычно используется клавиша &#039;&#039;&#039;q&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Работа с ветками ==&lt;br /&gt;
&lt;br /&gt;
=== git branch — локальные ветки ===&lt;br /&gt;
&lt;br /&gt;
Показывает локальные ветки. Текущая ветка отмечена символом &amp;lt;code&amp;gt;*&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git branch -a — локальные и удалённые ветки ===&lt;br /&gt;
&lt;br /&gt;
Показывает локальные ветки и локально сохранённые ссылки на удалённые ветки. Команда сама не обращается к серверу.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch -a&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обновить сведения с &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt; и убрать устаревшие ссылки на удалённые ветки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git fetch origin --prune&lt;br /&gt;
git branch -a&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git branch NAME — создать ветку ===&lt;br /&gt;
&lt;br /&gt;
Создаёт новую ветку от текущего коммита, но не переключается на неё.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch feature/new-command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== git checkout NAME — переключиться на ветку ===&lt;br /&gt;
&lt;br /&gt;
Переключает текущую ветку и обновляет файлы рабочей папки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout feature/new-command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Альтернатива для переключения веток:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch feature/new-command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создать ветку и сразу переключиться на неё одной командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch -c feature/new-command&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Используйте либо создание через &amp;lt;code&amp;gt;git branch&amp;lt;/code&amp;gt; с последующим переключением, либо &amp;lt;code&amp;gt;git switch -c&amp;lt;/code&amp;gt;. Повторно создавать уже существующую ветку не нужно.&lt;br /&gt;
&lt;br /&gt;
=== git branch -D NAME — принудительно удалить ветку ===&lt;br /&gt;
&lt;br /&gt;
Удаляет локальную ветку без проверки того, что её коммиты уже включены в другую историю.&lt;br /&gt;
&lt;br /&gt;
Для обычного удаления сначала используйте вариант с проверкой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch -d feature/old-task&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Принудительный вариант из исходной памятки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch -D feature/old-task&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; &amp;lt;code&amp;gt;-D&amp;lt;/code&amp;gt; может удалить последнюю ветку, ссылающуюся на нужные коммиты. Используйте его только если содержимое ветки больше не требуется или сохранено в другом месте. Нельзя удалить ветку, которая сейчас используется в рабочем дереве; сначала переключитесь на другую. На сервере ветка этой командой не удаляется.&lt;br /&gt;
&lt;br /&gt;
== Временное сохранение работы ==&lt;br /&gt;
&lt;br /&gt;
=== git stash — отложить незакоммиченные изменения ===&lt;br /&gt;
&lt;br /&gt;
Временно сохраняет изменения отслеживаемых файлов, включая индекс, и возвращает эти файлы к состоянию текущего коммита.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git stash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить также новые неотслеживаемые файлы и добавить описание:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git stash push -u -m &amp;quot;Незавершённая работа над статистикой&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть список сохранений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git stash list&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вернуть последнее сохранение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git stash pop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После успешного применения &amp;lt;code&amp;gt;pop&amp;lt;/code&amp;gt; удаляет запись из stash. Если возник конфликт, запись сохраняется. Вариант &amp;lt;code&amp;gt;git stash apply&amp;lt;/code&amp;gt; применяет изменения, оставляя запись в списке.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Примечание:&#039;&#039;&#039; обычный &amp;lt;code&amp;gt;git stash&amp;lt;/code&amp;gt; не включает новые неотслеживаемые файлы; для них нужен &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt;. Игнорируемые файлы с &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; также не сохраняются. Stash хранится локально и не отправляется обычным &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Пример повседневной работы ==&lt;br /&gt;
&lt;br /&gt;
Пример для существующего репозитория и ветки с настроенным отслеживанием. Выполняйте команды последовательно, проверяя результат каждого шага. При ошибке или конфликте сначала разберитесь с ним.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Перейти в проект и проверить состояние:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd my-project&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. При чистой рабочей папке получить обновления:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git pull --ff-only&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Изменить файлы, затем проверить правки:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status&lt;br /&gt;
git diff&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Подготовить нужные файлы и проверить будущий коммит:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git add README.md&lt;br /&gt;
git diff --staged&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Замените &amp;lt;code&amp;gt;README.md&amp;lt;/code&amp;gt; на нужные файлы. Если нужны все изменения, можно выполнить &amp;lt;code&amp;gt;git add .&amp;lt;/code&amp;gt; из корня проекта.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Сохранить и отправить:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git commit -m &amp;quot;Обновлена документация проекта&amp;quot;&lt;br /&gt;
git push&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Частые вопросы ==&lt;br /&gt;
&lt;br /&gt;
; Почему после git add команда git diff ничего не показывает?&lt;br /&gt;
: Изменения уже находятся в индексе. Выполните &amp;lt;code&amp;gt;git diff --staged&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Почему изменения не появились в GitLab или GitHub после коммита?&lt;br /&gt;
: &amp;lt;code&amp;gt;git commit&amp;lt;/code&amp;gt; сохраняет изменения локально. Для отправки нужен успешный &amp;lt;code&amp;gt;git push&amp;lt;/code&amp;gt; в нужный удалённый репозиторий и ветку.&lt;br /&gt;
&lt;br /&gt;
; Почему новая ветка не стала текущей после git branch?&lt;br /&gt;
: Эта команда только создаёт ветку. Переключитесь через &amp;lt;code&amp;gt;git switch&amp;lt;/code&amp;gt; или &amp;lt;code&amp;gt;git checkout&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
; Почему push сообщает, что нет upstream-ветки?&lt;br /&gt;
: Для новой ветки настройте отслеживание командой &amp;lt;code&amp;gt;git push -u origin ИМЯ_ВЕТКИ&amp;lt;/code&amp;gt;, заменив имя на фактическое.&lt;br /&gt;
&lt;br /&gt;
; Почему push отклонён с сообщением non-fast-forward?&lt;br /&gt;
: На сервере есть история, которой нет в вашей отправляемой ветке. Получите изменения через &amp;lt;code&amp;gt;git fetch&amp;lt;/code&amp;gt;, изучите расхождение и согласуйте истории перед повторной отправкой.&lt;br /&gt;
&lt;br /&gt;
== Источник ==&lt;br /&gt;
&lt;br /&gt;
Подготовлено на основе памятки &#039;&#039;Git_useful_commands.pdf&#039;&#039;. Описания переведены и уточнены; дополнительные варианты команд, примеры и ответы на частые вопросы добавлены для практического использования.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Git]]&lt;br /&gt;
[[Категория:Полезные команды]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=165</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=165"/>
		<updated>2026-09-28T18:52:22Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Небольшие инструкции, полезные команды и практические приёмы администрирования Linux.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все IP-адреса, имена и идентификаторы приведены для примера. Заменяйте их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Подключение с Mac к LXC-контейнеру по SSH без ввода пароля root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox. Знать или создавать пароль root контейнера для этого не требуется.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение для примера&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Что необходимо ===&lt;br /&gt;
&lt;br /&gt;
* Административный доступ к консоли узла Proxmox.&lt;br /&gt;
* Запущенный LXC-контейнер с работающим SSH-сервером.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — через локальную сеть или VPN.&lt;br /&gt;
* Разрешённый на SSH-сервере вход root по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание ключа на Mac ===&lt;br /&gt;
&lt;br /&gt;
Открыть &#039;&#039;&#039;Терминал на Mac&#039;&#039;&#039; и выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
При создании нового ключа появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac. Его нельзя публиковать или передавать.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт ключ без парольной фразы. Получивший приватный ключ сможет использовать его для подключения к серверам, где разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Парольную фразу такого ключа можно сохранить в связке ключей macOS — порядок приведён ниже.&lt;br /&gt;
&lt;br /&gt;
=== 2. Копирование публичного ключа ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю выведенную строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Нужен именно публичный ключ:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Копировать строку целиком, без добавления переносов.&lt;br /&gt;
* Не копировать отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Не копировать графический рисунок ключа.&lt;br /&gt;
* Не передавать содержимое приватного файла &amp;lt;code&amp;gt;id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, но файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, восстановить публичный ключ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Вход в контейнер через Proxmox ===&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox открыть &#039;&#039;&#039;Shell узла, на котором запущен контейнер&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие команды выполняются &#039;&#039;&#039;внутри контейнера от имени root&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== 4. Добавление ключа в контейнер ===&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог и файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
touch /root/.ssh/authorized_keys&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; скопированной строкой с Mac, сохранив одинарные кавычки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;\n%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет запись в конец файла и сохраняет ранее добавленные ключи.&lt;br /&gt;
&lt;br /&gt;
Начальный перенос строки не позволяет новому ключу склеиться с предыдущей записью. Пустые строки в файле допустимы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 5. Проверка подлинности сервера ===&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение ключа сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с тем, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сравнивать нужно ключи одного типа&#039;&#039;&#039;: в этом примере ED25519.&lt;br /&gt;
&lt;br /&gt;
=== 6. Подключение с Mac ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить адрес на IP своего контейнера.&lt;br /&gt;
&lt;br /&gt;
Если появился запрос подтверждения ключа сервера и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения подключения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Сохранение парольной фразы ключа в macOS ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот шаг нужен только для ключа, защищённого парольной фразой.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; относится к приватному ключу на Mac, а не к паролю root контейнера.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для автоматического использования связки ключей добавить настройки из следующего раздела.&lt;br /&gt;
&lt;br /&gt;
=== 8. Короткая команда подключения ===&lt;br /&gt;
&lt;br /&gt;
Можно назначить подключению понятное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек SSH:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить блок, заменив адрес на нужный:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если блок &amp;lt;code&amp;gt;Host my-container&amp;lt;/code&amp;gt; уже существует, изменить его вместо создания дубликата. Если в файле есть общий блок &amp;lt;code&amp;gt;Host *&amp;lt;/code&amp;gt;, этот отдельный блок разместить перед ним.&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключение выполняется короткой командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Диагностика ===&lt;br /&gt;
&lt;br /&gt;
==== Запрашивается пароль root ====&lt;br /&gt;
&lt;br /&gt;
Авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить подключение с явным указанием ключа и подробным выводом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внутри контейнера через консоль Proxmox проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;700&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Проверить, что:&lt;br /&gt;
&lt;br /&gt;
* В файле находится публичный ключ с нужного Mac.&lt;br /&gt;
* Ключ записан одной строкой.&lt;br /&gt;
* Указаны правильные IP-адрес и пользователь.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
==== Connection refused ====&lt;br /&gt;
&lt;br /&gt;
Соединение отклонено.&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт подключения. Также причиной может быть правило межсетевого экрана, отклоняющее соединение.&lt;br /&gt;
&lt;br /&gt;
==== Connection timed out ====&lt;br /&gt;
&lt;br /&gt;
Сервер не ответил за отведённое время.&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его сеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
==== REMOTE HOST IDENTIFICATION HAS CHANGED ====&lt;br /&gt;
&lt;br /&gt;
Сохранённый на Mac ключ сервера отличается от текущего.&lt;br /&gt;
&lt;br /&gt;
Причиной может быть переустановка контейнера, замена ключей SSH или появление другого устройства по тому же адресу.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить новый отпечаток через доверенную консоль Proxmox. Не удалять старую запись без проверки причины изменения.&lt;br /&gt;
&lt;br /&gt;
=== Примечания ===&lt;br /&gt;
&lt;br /&gt;
* Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
* Для каждого дополнительного компьютера можно создать собственный ключ и добавить его публичную часть отдельной строкой в &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Чтобы отозвать доступ конкретного ключа, удалить соответствующую строку из &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;. Уже открытые SSH-сеансы при этом не завершаются.&lt;br /&gt;
* Добавление ключа само по себе не отключает парольную авторизацию SSH.&lt;br /&gt;
* Приватные ключи, пароли и другие секреты не должны попадать в публичную документацию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Следующую хитрость добавляйте ниже отдельным разделом:&lt;br /&gt;
== Название хитрости ==&lt;br /&gt;
Описание и команды.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Создание службы systemd: автозапуск и перезапуск программы ==&lt;br /&gt;
&lt;br /&gt;
=== Что такое юнит ===&lt;br /&gt;
&lt;br /&gt;
Юнит — объект, которым управляет systemd. Юнит с расширением &amp;lt;code&amp;gt;.service&amp;lt;/code&amp;gt; описывает службу: какую программу запустить, под каким пользователем и что делать при её завершении.&lt;br /&gt;
&lt;br /&gt;
Служба позволяет:&lt;br /&gt;
&lt;br /&gt;
* Запускать программу при загрузке системы.&lt;br /&gt;
* Продолжать работу после отключения от SSH.&lt;br /&gt;
* Автоматически перезапускать программу после сбоя.&lt;br /&gt;
* Просматривать состояние и журналы стандартными командами.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён рабочий учебный пример для Debian и Ubuntu с systemd. Служба будет записывать сообщение в журнал каждые 30 секунд.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются на том сервере или внутри того контейнера, где должна работать программа, от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание пользователя службы ===&lt;br /&gt;
&lt;br /&gt;
Для программы, которой не нужны административные права, создать отдельного системного пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
id demo-service &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || useradd \&lt;br /&gt;
  --system \&lt;br /&gt;
  --user-group \&lt;br /&gt;
  --home-dir /opt/demo-service \&lt;br /&gt;
  --no-create-home \&lt;br /&gt;
  --shell /usr/sbin/nologin \&lt;br /&gt;
  demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь предназначен для запуска службы, а не для интерактивного входа.&lt;br /&gt;
&lt;br /&gt;
Создать каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
install -d -o root -g root -m 755 /opt/demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Создание программы для проверки ===&lt;br /&gt;
&lt;br /&gt;
Открыть файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
    printf &#039;%s — служба работает\n&#039; &amp;quot;$(date --iso-8601=seconds)&amp;quot;&lt;br /&gt;
    sleep 30&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить: &amp;lt;code&amp;gt;Ctrl + O&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ctrl + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /opt/demo-service/run.sh&lt;br /&gt;
chmod 755 /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь службы сможет прочитать и запустить файл, но не изменить его.&lt;br /&gt;
&lt;br /&gt;
=== 3. Создание юнита ===&lt;br /&gt;
&lt;br /&gt;
Открыть новый файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Example background service&lt;br /&gt;
StartLimitIntervalSec=60&lt;br /&gt;
StartLimitBurst=5&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=exec&lt;br /&gt;
User=demo-service&lt;br /&gt;
Group=demo-service&lt;br /&gt;
WorkingDirectory=/opt/demo-service&lt;br /&gt;
ExecStart=/bin/bash /opt/demo-service/run.sh&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
StandardOutput=journal&lt;br /&gt;
StandardError=journal&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пояснение параметров ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Описание службы, зависимости и ограничения запуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Description&amp;lt;/code&amp;gt;&lt;br /&gt;
| Название, которое отображается в состоянии службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitIntervalSec=60&amp;lt;/code&amp;gt;&lt;br /&gt;
| Интервал учёта частых запусков — 60 секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitBurst=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Допускается до пяти запусков за указанный интервал. Ограничивает бесконечные попытки запуска при ошибке.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Service]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Параметры процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Type=exec&amp;lt;/code&amp;gt;&lt;br /&gt;
| systemd ожидает успешного запуска исполняемого файла. Это ещё не означает, что приложение полностью готово обслуживать запросы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;User&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;Group&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пользователь и группа процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WorkingDirectory&amp;lt;/code&amp;gt;&lt;br /&gt;
| Рабочий каталог программы. Должен существовать и быть доступен пользователю службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt;&lt;br /&gt;
| Команда запуска с абсолютными путями.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Restart=on-failure&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапуск после ошибки или аварийного завершения. Штатное завершение с кодом 0 не вызывает перезапуск.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RestartSec=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пауза перед перезапуском — пять секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardOutput=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Обычный вывод программы направляется в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardError=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ошибки программы направляются в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Install]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Настройки включения автозапуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WantedBy=multi-user.target&amp;lt;/code&amp;gt;&lt;br /&gt;
| Позволяет включить службу в обычный многопользовательский режим загрузки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка и запуск ===&lt;br /&gt;
&lt;br /&gt;
Проверить юнит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если обнаружены ошибки в созданном файле — исправить их до запуска.&lt;br /&gt;
&lt;br /&gt;
Перечитать юниты, включить автозапуск и сразу запустить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемое состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Просмотр журнала ===&lt;br /&gt;
&lt;br /&gt;
Последние 50 записей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение за новыми записями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нажатие &amp;lt;code&amp;gt;Ctrl + C&amp;lt;/code&amp;gt; завершает просмотр журнала, но не останавливает службу.&lt;br /&gt;
&lt;br /&gt;
=== Основные команды управления ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Команда !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl start demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl stop demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Остановить. Настройка Restart не отменяет ручную остановку.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Посмотреть состояние.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl enable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Включить автозапуск, не запуская службу немедленно.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск, не останавливая текущий процесс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable --now demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск и остановить службу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl cat demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Показать юнит и дополнительные настройки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Как адаптировать под свою программу ===&lt;br /&gt;
&lt;br /&gt;
Заменить имя службы, пользователя, рабочий каталог и команду запуска.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-приложения с виртуальным окружением:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
WorkingDirectory=/opt/my-app&lt;br /&gt;
ExecStart=/opt/my-app/.venv/bin/python -u /opt/my-app/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Виртуальное окружение и файл программы должны существовать. Активировать окружение командой &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; не требуется.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; отключает буферизацию стандартных потоков Python, чтобы сообщения быстрее попадали в журнал.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Особенности:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Программа должна работать на переднем плане: не добавляйте &amp;lt;code&amp;gt;&amp;amp;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nohup&amp;lt;/code&amp;gt; или собственный переход в фон.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt; не является обычной командной строкой оболочки: конструкции &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;&amp;amp;amp;&amp;amp;amp;&amp;lt;/code&amp;gt; не выполняются как в Bash.&lt;br /&gt;
* Сложную последовательность команд удобнее оформить отдельным скриптом.&lt;br /&gt;
* Пользователю службы нужны права чтения программы и записи только в необходимые каталоги данных.&lt;br /&gt;
* Переменные из интерактивного SSH-сеанса автоматически в службу не передаются.&lt;br /&gt;
&lt;br /&gt;
Для программы, которой при запуске нужна настроенная сеть, в секцию &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt; можно добавить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
After=network-online.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это не гарантирует доступность Интернета или внешнего API. Приложение должно самостоятельно повторять неудачные подключения.&lt;br /&gt;
&lt;br /&gt;
=== Применение изменений ===&lt;br /&gt;
&lt;br /&gt;
После изменения юнита:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart demo-service.service&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если изменён только код программы, обычно достаточно перезапуска службы.&lt;br /&gt;
&lt;br /&gt;
Если сработало ограничение частых запусков, сначала исправить причину по журналу, затем выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reset-failed demo-service.service&lt;br /&gt;
systemctl start demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Отключение парольного входа по SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Разрешить новые SSH-подключения только по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
Имя пользователя по-прежнему указывается, например &amp;lt;code&amp;gt;root@192.168.2.2&amp;lt;/code&amp;gt;. Меняется способ подтверждения доступа.&lt;br /&gt;
&lt;br /&gt;
Настройка не удаляет системные пароли и не меняет правила входа через локальную консоль или использования sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пример предназначен для Debian и Ubuntu с OpenSSH. Команды сервера выполняются от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка входа по ключу ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не закрывайте текущий сеанс до завершения всех проверок.&#039;&#039;&#039; Держите доступной консоль Proxmox или другую независимую консоль сервера.&lt;br /&gt;
&lt;br /&gt;
В новом терминале Mac проверить вход с запретом перехода к парольной авторизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PreferredAuthentications=publickey \&lt;br /&gt;
  -o PasswordAuthentication=no \&lt;br /&gt;
  -o KbdInteractiveAuthentication=no \&lt;br /&gt;
  -o IdentitiesOnly=yes \&lt;br /&gt;
  -i ~/.ssh/id_ed25519 \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вход не работает, сначала исправить авторизацию по ключу.&lt;br /&gt;
&lt;br /&gt;
Если сервером пользуются несколько администраторов, заранее настроить ключи для каждого.&lt;br /&gt;
&lt;br /&gt;
=== 2. Резервная копия конфигурации ===&lt;br /&gt;
&lt;br /&gt;
На сервере выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config \&lt;br /&gt;
  &amp;quot;/etc/ssh/sshd_config.backup-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Изменение настроек ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить в самое начало файла, перед директивами &amp;lt;code&amp;gt;Include&amp;lt;/code&amp;gt; и блоками &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
PubkeyAuthentication yes&lt;br /&gt;
PasswordAuthentication no&lt;br /&gt;
KbdInteractiveAuthentication no&lt;br /&gt;
AuthenticationMethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PubkeyAuthentication yes&amp;lt;/code&amp;gt;&lt;br /&gt;
| Разрешить авторизацию по публичному ключу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить обычную парольную авторизацию.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KbdInteractiveAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить интерактивную авторизацию, которая также может запрашивать пароль или одноразовый код.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AuthenticationMethods publickey&amp;lt;/code&amp;gt;&lt;br /&gt;
| Оставить только авторизацию по публичному ключу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот вариант также исключает другие способы входа и схемы «ключ плюс одноразовый код».&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для большинства параметров OpenSSH используется первое полученное значение. Блоки &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; могут задавать отдельные правила для пользователей и адресов, поэтому нужна проверка итоговой конфигурации.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;PermitRootLogin&amp;lt;/code&amp;gt; без необходимости не менять. Значение &amp;lt;code&amp;gt;no&amp;lt;/code&amp;gt; запрещает root любой SSH-вход; &amp;lt;code&amp;gt;prohibit-password&amp;lt;/code&amp;gt; допускает вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка перед применением ===&lt;br /&gt;
&lt;br /&gt;
Проверить синтаксис:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсутствие вывода при успешном завершении означает, что проверка пройдена. При ошибке конфигурацию не применять.&lt;br /&gt;
&lt;br /&gt;
Посмотреть общие итоговые параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
pubkeyauthentication yes&lt;br /&gt;
passwordauthentication no&lt;br /&gt;
kbdinteractiveauthentication no&lt;br /&gt;
authenticationmethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; дополнительно проверить конкретное подключение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T \&lt;br /&gt;
  -C user=root,addr=192.168.2.50,host=mac-client,laddr=192.168.2.2,lport=22 \&lt;br /&gt;
  | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|permitrootlogin) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В примере:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; — пользователь сервера.&lt;br /&gt;
* &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; — адрес клиента, видимый серверу.&lt;br /&gt;
* &amp;lt;code&amp;gt;host&amp;lt;/code&amp;gt; — имя клиента для правил Match Host.&lt;br /&gt;
* &amp;lt;code&amp;gt;laddr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lport&amp;lt;/code&amp;gt; — адрес и порт сервера.&lt;br /&gt;
&lt;br /&gt;
Подставить реальные параметры подключения. Проверить также другие учётные записи и адреса, для которых настроены отдельные правила.&lt;br /&gt;
&lt;br /&gt;
Если значения отличаются от ожидаемых, найти и исправить соответствующие настройки в основном файле, подключаемых файлах или блоках Match.&lt;br /&gt;
&lt;br /&gt;
=== 5. Применение ===&lt;br /&gt;
&lt;br /&gt;
Для стандартной службы SSH в Debian и Ubuntu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В системах, где служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload sshd.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выполняется только вариант с фактическим именем службы.&lt;br /&gt;
&lt;br /&gt;
Перечитывание конфигурации штатно сохраняет открытые сеансы.&lt;br /&gt;
&lt;br /&gt;
=== 6. Проверка нового подключения ===&lt;br /&gt;
&lt;br /&gt;
Не закрывая старый сеанс, в новом терминале Mac повторить команду проверки входа по ключу из первого шага.&lt;br /&gt;
&lt;br /&gt;
Затем проверить отказ для парольных способов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PubkeyAuthentication=no \&lt;br /&gt;
  -o PreferredAuthentications=password,keyboard-interactive \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат — отказ, обычно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Permission denied (publickey).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пароль учётной записи запрашиваться не должен.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Старый сеанс можно закрыть после успешного нового входа по ключу и проверки отказа для пароля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Восстановление при ошибке ===&lt;br /&gt;
&lt;br /&gt;
Использовать оставленный открытым сеанс или консоль Proxmox.&lt;br /&gt;
&lt;br /&gt;
Найти резервную копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lt /etc/ssh/sshd_config.backup-*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Восстановить нужную копию, указав её фактическое имя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config.backup-YYYYMMDD-HHMMSS /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить и применить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, заменить её имя в команде.&lt;br /&gt;
&lt;br /&gt;
=== Важно помнить ===&lt;br /&gt;
&lt;br /&gt;
* Парольная фраза приватного ключа на Mac может запрашиваться и после отключения паролей на сервере — это отдельная защита самого ключа.&lt;br /&gt;
* Настройка распространяется также на SFTP и SCP через этот SSH-сервер.&lt;br /&gt;
* Не удаляйте пароль пользователя и не блокируйте учётную запись ради отключения парольного SSH-входа: достаточно настроек SSH.&lt;br /&gt;
&lt;br /&gt;
== Проверка версии и обновление программы из GitLab ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Проверить, появились ли новые изменения в GitLab, сравнить их с установленным на сервере кодом и обновить программу.&lt;br /&gt;
&lt;br /&gt;
Инструкция предназначена для приложения, которое уже установлено из Git-репозитория и запускается через systemd.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все пути, имена и адреса приведены для примера.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Пример&lt;br /&gt;
|-&lt;br /&gt;
| Каталог программы || &amp;lt;code&amp;gt;/opt/my-app&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Репозиторий || &amp;lt;code&amp;gt;git@gitlab.example.com:team/my-app.git&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Удалённый репозиторий || &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Рабочая ветка || &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Служба || &amp;lt;code&amp;gt;my-app.service&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Команды Git выполнять от имени владельца рабочей копии. Для управления системной службой нужны права root или sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются поэтапно. При ошибке не переходить к следующему шагу.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Основные понятия ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Термин !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Коммит&lt;br /&gt;
| Зафиксированное состояние кода с уникальным идентификатором.&lt;br /&gt;
|-&lt;br /&gt;
| Ветка&lt;br /&gt;
| Последовательность разработки, например &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; или &amp;lt;code&amp;gt;stable&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| HEAD&lt;br /&gt;
| Текущий коммит рабочей копии.&lt;br /&gt;
|-&lt;br /&gt;
| origin&lt;br /&gt;
| Обычно так называется подключённый удалённый репозиторий.&lt;br /&gt;
|-&lt;br /&gt;
| origin/main&lt;br /&gt;
| Последнее полученное локально состояние ветки main из origin. До fetch сведения могут быть устаревшими.&lt;br /&gt;
|-&lt;br /&gt;
| Тег&lt;br /&gt;
| Именованная отметка версии, например &amp;lt;code&amp;gt;v1.4.0&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Release&lt;br /&gt;
| Опубликованный выпуск в GitLab, обычно связанный с тегом и описанием изменений.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Новый коммит в ветке не обязательно означает новый стабильный выпуск.&#039;&#039;&#039; Перед установкой проверить назначение ветки, описание выпуска и результаты CI в GitLab.&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка каталога и службы ===&lt;br /&gt;
&lt;br /&gt;
Перейти в каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/my-app&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Убедиться, что открыт нужный репозиторий:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pwd&lt;br /&gt;
git rev-parse --show-toplevel&lt;br /&gt;
git remote -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить, откуда systemd запускает программу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl show my-app.service --no-pager \&lt;br /&gt;
  -p WorkingDirectory \&lt;br /&gt;
  -p ExecStart \&lt;br /&gt;
  -p User&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пути должны соответствовать обновляемому приложению.&lt;br /&gt;
&lt;br /&gt;
Если служба запускает Docker-контейнер, установленный пакет или собранный файл из другого каталога, одного обновления исходников недостаточно. Нужна предусмотренная проектом сборка и установка.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не публикуйте вывод git remote -v, если в адрес репозитория встроен токен доступа.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. Определение текущей версии ===&lt;br /&gt;
&lt;br /&gt;
Выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --show-current&lt;br /&gt;
git log -1 --format=&#039;%h %ci %s&#039;&lt;br /&gt;
git rev-parse HEAD&lt;br /&gt;
git status --short --branch&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команды показывают:&lt;br /&gt;
&lt;br /&gt;
* Текущую ветку.&lt;br /&gt;
* Последний коммит, дату и описание.&lt;br /&gt;
* Полный идентификатор коммита.&lt;br /&gt;
* Состояние рабочей копии.&lt;br /&gt;
&lt;br /&gt;
Если имя ветки не выводится, репозиторий находится в состоянии detached HEAD — например, после установки определённого тега. Основной сценарий ниже рассчитан на ветку main.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Коммит в каталоге не доказывает, что запущенный процесс уже использует этот код.&#039;&#039;&#039; После обновления обычно требуется перезапуск или отдельный этап развёртывания.&lt;br /&gt;
&lt;br /&gt;
=== 3. Проверка локальных изменений ===&lt;br /&gt;
&lt;br /&gt;
Выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пустой вывод означает отсутствие отслеживаемых изменений и неотслеживаемых файлов. Игнорируемые файлы, например .env, эта команда не показывает.&lt;br /&gt;
&lt;br /&gt;
Типичные обозначения:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Обозначение !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;M&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл изменён.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
| Новый файл добавлен в индекс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл удалён.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл не отслеживается Git.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Если есть изменения, сначала выяснить их назначение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff&lt;br /&gt;
git diff --cached&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Не удалять локальные правки ради обновления. Сохранить нужный код отдельно или оформить его в согласованную ветку разработки.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не использовать git reset --hard или git clean -fd как универсальное исправление: они могут уничтожить нужные изменения и файлы.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 4. Получение сведений из GitLab ===&lt;br /&gt;
&lt;br /&gt;
Для примера с веткой main выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git fetch origin refs/heads/main:refs/remotes/origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда получает актуальное состояние нужной ветки. Файлы программы в рабочем каталоге не обновляются, служба продолжает работать.&lt;br /&gt;
&lt;br /&gt;
Если GitLab недоступен или авторизация завершилась ошибкой, остановиться: сравнение со старым origin/main не подтверждает актуальность сервера.&lt;br /&gt;
&lt;br /&gt;
Для приватного репозитория на сервере нужен доступ на чтение, например отдельный SSH Deploy Key. Ключ для входа с Mac на сервер сам по себе не предоставляет серверу доступ к GitLab.&lt;br /&gt;
&lt;br /&gt;
=== 5. Сравнение сервера с GitLab ===&lt;br /&gt;
&lt;br /&gt;
Показать количество уникальных коммитов с каждой стороны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git rev-list --left-right --count HEAD...origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Результат !! Значение !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0 0&amp;lt;/code&amp;gt;&lt;br /&gt;
| История совпадает.&lt;br /&gt;
| Обновление кода не требуется.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0 3&amp;lt;/code&amp;gt;&lt;br /&gt;
| В GitLab есть три новых коммита.&lt;br /&gt;
| Можно изучать обновление.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2 0&amp;lt;/code&amp;gt;&lt;br /&gt;
| На сервере есть два коммита, которых нет в origin/main.&lt;br /&gt;
| Выяснить происхождение локальных коммитов.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2 3&amp;lt;/code&amp;gt;&lt;br /&gt;
| Истории разошлись.&lt;br /&gt;
| Разобраться с ветками; обычное обновление не выполнять.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Первое число относится к HEAD сервера, второе — к origin/main.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Продолжать основной сценарий следует только при результате 0 N, где N больше нуля, и при текущей ветке main.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 6. Просмотр состава обновления ===&lt;br /&gt;
&lt;br /&gt;
Зафиксировать идентификатор проверяемой версии:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE_COMMIT=$(git rev-parse origin/main)&lt;br /&gt;
printf &#039;%s\n&#039; &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие шаги выполнять в том же терминале. После переподключения переменную нужно задать снова.&lt;br /&gt;
&lt;br /&gt;
Посмотреть новые коммиты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git --no-pager log --oneline HEAD..&amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть список и объём изменений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git --no-pager diff --stat HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
git --no-pager diff --name-status HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть изменения кода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для выхода из просмотра нажать &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Перед установкой проверить:&lt;br /&gt;
&lt;br /&gt;
* Изменения зависимостей и требования к версии языка.&lt;br /&gt;
* Новые настройки и переменные окружения.&lt;br /&gt;
* Изменения юнита systemd.&lt;br /&gt;
* Необходимость сборки.&lt;br /&gt;
* Миграции базы данных.&lt;br /&gt;
* Инструкцию обновления и совместимость со старой версией.&lt;br /&gt;
&lt;br /&gt;
Обновляться будем до сохранённого UPDATE_COMMIT — именно до просмотренной версии.&lt;br /&gt;
&lt;br /&gt;
=== 7. Подготовка отката ===&lt;br /&gt;
&lt;br /&gt;
Создать локальную ветку, сохраняющую текущий коммит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
BACKUP_BRANCH=&amp;quot;backup/before-update-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
git branch &amp;quot;$BACKUP_BRANCH&amp;quot; HEAD&lt;br /&gt;
printf &#039;Ветка для отката: %s\n&#039; &amp;quot;$BACKUP_BRANCH&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Записать её имя.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эта ветка сохраняет только версию кода в Git.&#039;&#039;&#039; Она не является резервной копией базы данных, загруженных файлов, .env или виртуального окружения.&lt;br /&gt;
&lt;br /&gt;
До обновления отдельно обеспечить восстановление:&lt;br /&gt;
&lt;br /&gt;
* Конфигурации и секретов.&lt;br /&gt;
* Базы данных штатными средствами используемой СУБД.&lt;br /&gt;
* Пользовательских файлов.&lt;br /&gt;
* Зависимостей приложения.&lt;br /&gt;
&lt;br /&gt;
При миграциях заранее определить, совместима ли новая структура базы со старым кодом. Копирование файлов работающей базы обычной командой cp не заменяет корректную резервную копию.&lt;br /&gt;
&lt;br /&gt;
=== 8. Остановка и обновление кода ===&lt;br /&gt;
&lt;br /&gt;
Этот способ предполагает короткий простой приложения.&lt;br /&gt;
&lt;br /&gt;
Ещё раз проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --show-current&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается ветка main и пустой вывод второй команды.&lt;br /&gt;
&lt;br /&gt;
Остановить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl stop my-app.service&lt;br /&gt;
sudo systemctl is-active my-app.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый ответ — &amp;lt;code&amp;gt;inactive&amp;lt;/code&amp;gt;. Для неактивной службы команда is-active возвращает ненулевой код, это нормально.&lt;br /&gt;
&lt;br /&gt;
Если приложение запускается также таймером, сокетом или внешним монитором, на время обновления приостановить и этот механизм.&lt;br /&gt;
&lt;br /&gt;
Обновить рабочую копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git merge --ff-only &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;--ff-only&amp;lt;/code&amp;gt; разрешает только прямое продвижение по истории без создания merge-коммита. При расхождении веток команда откажется выполнять слияние.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При ошибке не продолжать установку и не запускать непроверенную версию.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 9. Зависимости, сборка и проверки ===&lt;br /&gt;
&lt;br /&gt;
Выполнить шаги, предусмотренные документацией проекта. Универсальной команды установки для всех программ нет.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-проекта, использующего виртуальное окружение и requirements.txt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
.venv/bin/python -m pip install -r requirements.txt&lt;br /&gt;
.venv/bin/python -m pip check&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для проверки синтаксиса Python, если исходники находятся в каталоге app:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
.venv/bin/python -m compileall -q app&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить каталог app реальным каталогом исходников.&lt;br /&gt;
&lt;br /&gt;
Проверка синтаксиса не заменяет тестирование функций программы. Если проект использует lock-файл или другой менеджер зависимостей, применять его штатную процедуру.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При ошибке установки, сборки, тестов или миграции остановиться.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Миграции базы выполнять только по инструкции проекта и после резервного копирования.&lt;br /&gt;
&lt;br /&gt;
Если изменился установленный юнит systemd, проверить и применить его отдельно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemd-analyze verify /etc/systemd/system/my-app.service&lt;br /&gt;
sudo systemctl daemon-reload&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Изменение копии юнита в Git-репозитории само по себе не обновляет файл в /etc/systemd/system.&lt;br /&gt;
&lt;br /&gt;
=== 10. Запуск и проверка ===&lt;br /&gt;
&lt;br /&gt;
После успешного выполнения подготовительных шагов запустить приложение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl start my-app.service&lt;br /&gt;
sudo systemctl status my-app.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть свежие журналы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo journalctl -u my-app.service --since &amp;quot;5 minutes ago&amp;quot; --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить установленный коммит с выбранным:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git rev-parse HEAD&lt;br /&gt;
printf &#039;%s\n&#039; &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Идентификаторы должны совпасть.&lt;br /&gt;
&lt;br /&gt;
Проверить программу по назначению:&lt;br /&gt;
&lt;br /&gt;
* Для бота — отправить тестовую команду.&lt;br /&gt;
* Для сайта — открыть страницу и проверить основную операцию.&lt;br /&gt;
* Для API — выполнить предусмотренную проверку состояния.&lt;br /&gt;
* Для фоновой службы — убедиться, что она обрабатывает задания.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Состояние active (running) подтверждает наличие процесса, но не гарантирует работоспособность приложения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 11. Откат к предыдущему коду ===&lt;br /&gt;
&lt;br /&gt;
Откат выполнять только после оценки совместимости старого кода с текущей базой и зависимостями.&lt;br /&gt;
&lt;br /&gt;
Остановить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl stop my-app.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Найти сохранённую ветку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --list &#039;backup/before-update-*&#039;&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии новых локальных изменений сначала сохранить и изучить их.&lt;br /&gt;
&lt;br /&gt;
Переключиться на фактическую резервную ветку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch backup/before-update-YYYYMMDD-HHMMSS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подставить имя из списка. Команда меняет рабочие файлы на сохранённую версию, не переписывая ветку main.&lt;br /&gt;
&lt;br /&gt;
Затем:&lt;br /&gt;
&lt;br /&gt;
# Восстановить совместимые зависимости и конфигурацию.&lt;br /&gt;
# При необходимости выполнить предусмотренное восстановление базы.&lt;br /&gt;
# Проверить приложение.&lt;br /&gt;
# Запустить службу и посмотреть журнал.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl start my-app.service&lt;br /&gt;
sudo systemctl status my-app.service --no-pager -l&lt;br /&gt;
sudo journalctl -u my-app.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;После отката текущей становится резервная ветка.&#039;&#039;&#039; Перед следующим обновлением нужно осознанно выбрать дальнейшую ветку или выпуск.&lt;br /&gt;
&lt;br /&gt;
Повторная установка старого requirements.txt не гарантирует точное восстановление окружения: новые лишние пакеты могут остаться, а незакреплённые версии — измениться.&lt;br /&gt;
&lt;br /&gt;
=== Если новая версия опубликована тегом ===&lt;br /&gt;
&lt;br /&gt;
Если проект выпускает стабильные версии тегами, ориентироваться на указанный в GitLab Release тег, а не на последний коммит main.&lt;br /&gt;
&lt;br /&gt;
Получить теги:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git fetch origin --tags&lt;br /&gt;
git tag --list --sort=-version:refname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порядок списка не гарантирует, что первый тег — рекомендованный стабильный выпуск. Проверить описание релиза и отметку предварительной версии в GitLab.&lt;br /&gt;
&lt;br /&gt;
Для выбранного примера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git show --no-patch v1.4.0&lt;br /&gt;
git diff --stat HEAD v1.4.0&lt;br /&gt;
git log --oneline HEAD..v1.4.0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После просмотра, резервного копирования и остановки службы вместо обновления ветки можно установить конкретный тег:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch --detach v1.4.0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это отдельный вариант установки. После него выполнить зависимости, сборку и проверки согласно выпуску.&lt;br /&gt;
&lt;br /&gt;
Состояние detached HEAD здесь ожидаемо: сервер закреплён за конкретным коммитом версии.&lt;br /&gt;
&lt;br /&gt;
=== Частые ошибки ===&lt;br /&gt;
&lt;br /&gt;
==== not a git repository ====&lt;br /&gt;
&lt;br /&gt;
Команда выполнена не в каталоге репозитория:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/my-app&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Permission denied (publickey) при fetch ====&lt;br /&gt;
&lt;br /&gt;
GitLab не принял SSH-ключ сервера.&lt;br /&gt;
&lt;br /&gt;
Проверить адрес origin и доступ серверного ключа к нужному проекту. Не переносить приватный ключ с личного компьютера без необходимости.&lt;br /&gt;
&lt;br /&gt;
==== Your local changes would be overwritten ====&lt;br /&gt;
&lt;br /&gt;
На сервере есть изменения файлов, которым мешает обновление.&lt;br /&gt;
&lt;br /&gt;
Посмотреть git status и git diff. Не применять принудительный сброс без понимания, какие данные будут потеряны.&lt;br /&gt;
&lt;br /&gt;
==== Not possible to fast-forward ====&lt;br /&gt;
&lt;br /&gt;
Истории разошлись. Проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git log --oneline --graph --decorate --max-count=30 HEAD origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разобраться с локальными коммитами и изменениями ветки в GitLab до обновления.&lt;br /&gt;
&lt;br /&gt;
==== Код обновлён, поведение старое ====&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Был ли перезапущен нужный процесс.&lt;br /&gt;
* Из какого каталога запускается служба.&lt;br /&gt;
* Не требуется ли сборка.&lt;br /&gt;
* Не работает ли другая копия приложения.&lt;br /&gt;
* Не запускается ли приложение из Docker-образа или установленного пакета.&lt;br /&gt;
&lt;br /&gt;
=== Короткая проверка наличия обновлений ===&lt;br /&gt;
&lt;br /&gt;
Следующий блок только получает сведения и сравнивает версии. Он не обновляет рабочие файлы и не перезапускает программу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
(&lt;br /&gt;
  cd /opt/my-app || exit 1&lt;br /&gt;
&lt;br /&gt;
  git status --short --branch&lt;br /&gt;
  git log -1 --oneline&lt;br /&gt;
&lt;br /&gt;
  git fetch origin refs/heads/main:refs/remotes/origin/main || exit 1&lt;br /&gt;
&lt;br /&gt;
  git rev-list --left-right --count HEAD...origin/main&lt;br /&gt;
  git --no-pager log --oneline HEAD..origin/main&lt;br /&gt;
  git --no-pager diff --stat HEAD origin/main&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Автоматическое обновление программы из GitLab каждые 3 минуты ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Сервер периодически проверяет выбранную ветку GitLab и устанавливает новые коммиты.&lt;br /&gt;
&lt;br /&gt;
Если изменений нет, программа продолжает работать без перезапуска.&lt;br /&gt;
&lt;br /&gt;
При наличии обновления выполняются:&lt;br /&gt;
&lt;br /&gt;
# Проверка состояния репозитория.&lt;br /&gt;
# Проверка допустимости изменений.&lt;br /&gt;
# Сохранение предыдущего коммита.&lt;br /&gt;
# Остановка приложения.&lt;br /&gt;
# Обновление кода.&lt;br /&gt;
# Проверка синтаксиса Python.&lt;br /&gt;
# Запуск и проверка работоспособности.&lt;br /&gt;
# Попытка отката при ошибке.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пример предназначен для Debian и Ubuntu с systemd.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Область применения ===&lt;br /&gt;
&lt;br /&gt;
Этот вариант обновляет код Python-приложения в существующем каталоге. Во время установки будет короткий простой.&lt;br /&gt;
&lt;br /&gt;
Он не устанавливает зависимости, не выполняет миграции базы, не пересобирает Docker-образы и не меняет системные настройки.&lt;br /&gt;
&lt;br /&gt;
Изменения за пределами разрешённых файлов требуют ручного обновления.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Откат кода не отменяет изменения данных, которые успела сделать программа.&#039;&#039;&#039; Автоматизировать таким способом следует только совместимые обновления без изменения формата данных и обязательных миграций.&lt;br /&gt;
&lt;br /&gt;
=== Пример конфигурации ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Каталог приложения || &amp;lt;code&amp;gt;/opt/my-app&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Владелец репозитория || &amp;lt;code&amp;gt;myapp&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ветка для установки || &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Удалённый репозиторий || &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Служба приложения || &amp;lt;code&amp;gt;my-app.service&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Виртуальное окружение || &amp;lt;code&amp;gt;/opt/my-app/.venv&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Исходники Python || &amp;lt;code&amp;gt;app/&amp;lt;/code&amp;gt; и необязательный &amp;lt;code&amp;gt;main.py&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверка состояния || &amp;lt;code&amp;gt;http://127.0.0.1:8000/health&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Интервал || 3 минуты после завершения предыдущей проверки&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все значения условные. Пользователь myapp, репозиторий, виртуальное окружение и служба должны уже существовать.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ветка для автоматической установки должна содержать только одобренные изменения. В GitLab следует ограничить прямую запись в неё и настроить прохождение CI перед слиянием.&lt;br /&gt;
&lt;br /&gt;
Сам скрипт не проверяет статус pipeline GitLab: публикация коммита в выбранной ветке считается разрешением на установку.&lt;br /&gt;
&lt;br /&gt;
=== 1. Подготовка ===&lt;br /&gt;
&lt;br /&gt;
Команды настройки выполнять от имени root на сервере приложения.&lt;br /&gt;
&lt;br /&gt;
Установить необходимые инструменты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
apt install -y git curl util-linux&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl show my-app.service --no-pager \&lt;br /&gt;
  -p User \&lt;br /&gt;
  -p WorkingDirectory \&lt;br /&gt;
  -p ExecStart&lt;br /&gt;
&lt;br /&gt;
systemctl status my-app.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она должна запускать программу из обновляемого каталога. Само приложение желательно запускать под отдельным непривилегированным пользователем.&lt;br /&gt;
&lt;br /&gt;
Проверить репозиторий от имени его владельца:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
runuser -u myapp -- git -C /opt/my-app status --short --branch&lt;br /&gt;
runuser -u myapp -- git -C /opt/my-app branch --show-current&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается ветка main без локальных изменений и неотслеживаемых файлов.&lt;br /&gt;
&lt;br /&gt;
Логи, виртуальное окружение и локальные настройки должны находиться вне отслеживаемого кода либо быть корректно исключены через .gitignore.&lt;br /&gt;
&lt;br /&gt;
=== 2. Доступ сервера к GitLab ===&lt;br /&gt;
&lt;br /&gt;
У пользователя myapp должен быть настроен доступ на чтение репозитория.&lt;br /&gt;
&lt;br /&gt;
Для SSH можно использовать отдельный Deploy Key с правами только на чтение. Ключ сервера GitLab должен быть заранее проверен и сохранён в known_hosts этого пользователя.&lt;br /&gt;
&lt;br /&gt;
Проверить доступ без интерактивного запроса пароля:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
runuser -u myapp -- env \&lt;br /&gt;
  GIT_TERMINAL_PROMPT=0 \&lt;br /&gt;
  GIT_SSH_COMMAND=&amp;quot;ssh -o BatchMode=yes -o ConnectTimeout=10&amp;quot; \&lt;br /&gt;
  git -C /opt/my-app ls-remote --exit-code origin refs/heads/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда должна вывести идентификатор ветки и завершиться успешно.&lt;br /&gt;
&lt;br /&gt;
Не отключать проверку ключа SSH-сервера ради автоматизации.&lt;br /&gt;
&lt;br /&gt;
=== 3. Проверка состояния приложения ===&lt;br /&gt;
&lt;br /&gt;
В примере приложение предоставляет адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
http://127.0.0.1:8000/health&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl --noproxy &#039;*&#039; --max-time 5 \&lt;br /&gt;
  -sS -o /dev/null -w &#039;%{http_code}\n&#039; \&lt;br /&gt;
  http://127.0.0.1:8000/health&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается HTTP 200.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот endpoint должен существовать в приложении и отражать его готовность к работе.&#039;&#039;&#039; Не подставляйте произвольную страницу только потому, что она отвечает кодом 200.&lt;br /&gt;
&lt;br /&gt;
Для Telegram-бота без HTTP endpoint функцию проверки в скрипте нужно заменить реальной проверкой готовности бота. Одного состояния active недостаточно.&lt;br /&gt;
&lt;br /&gt;
=== 4. Создание скрипта обновления ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /usr/local/sbin/my-app-update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
set -Eeuo pipefail&lt;br /&gt;
&lt;br /&gt;
export PATH=/usr/sbin:/usr/bin:/sbin:/bin&lt;br /&gt;
&lt;br /&gt;
APP_DIR=&amp;quot;/opt/my-app&amp;quot;&lt;br /&gt;
APP_USER=&amp;quot;myapp&amp;quot;&lt;br /&gt;
APP_SERVICE=&amp;quot;my-app.service&amp;quot;&lt;br /&gt;
BRANCH=&amp;quot;main&amp;quot;&lt;br /&gt;
REMOTE=&amp;quot;origin&amp;quot;&lt;br /&gt;
HEALTH_URL=&amp;quot;http://127.0.0.1:8000/health&amp;quot;&lt;br /&gt;
&lt;br /&gt;
STATE_DIR=&amp;quot;/var/lib/my-app-updater&amp;quot;&lt;br /&gt;
PAUSE_FILE=&amp;quot;$STATE_DIR/PAUSED&amp;quot;&lt;br /&gt;
&lt;br /&gt;
old_commit=&amp;quot;&amp;quot;&lt;br /&gt;
new_commit=&amp;quot;&amp;quot;&lt;br /&gt;
deployment_started=0&lt;br /&gt;
&lt;br /&gt;
log() {&lt;br /&gt;
    printf &#039;%s %s\n&#039; &amp;quot;$(date --iso-8601=seconds)&amp;quot; &amp;quot;$*&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
as_app() {&lt;br /&gt;
    runuser -u &amp;quot;$APP_USER&amp;quot; -- &amp;quot;$@&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
git_app() {&lt;br /&gt;
    as_app env \&lt;br /&gt;
      GIT_TERMINAL_PROMPT=0 \&lt;br /&gt;
      GIT_SSH_COMMAND=&amp;quot;ssh -o BatchMode=yes -o ConnectTimeout=10&amp;quot; \&lt;br /&gt;
      git -C &amp;quot;$APP_DIR&amp;quot; &amp;quot;$@&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
health_once() {&lt;br /&gt;
    local http_code&lt;br /&gt;
&lt;br /&gt;
    systemctl is-active --quiet &amp;quot;$APP_SERVICE&amp;quot; || return 1&lt;br /&gt;
&lt;br /&gt;
    http_code=$(&lt;br /&gt;
        as_app curl --noproxy &#039;*&#039; \&lt;br /&gt;
          --connect-timeout 2 --max-time 5 \&lt;br /&gt;
          -sS -o /dev/null -w &#039;%{http_code}&#039; \&lt;br /&gt;
          &amp;quot;$HEALTH_URL&amp;quot;&lt;br /&gt;
    ) || return 1&lt;br /&gt;
&lt;br /&gt;
    [[ &amp;quot;$http_code&amp;quot; == &amp;quot;200&amp;quot; ]]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
wait_healthy() {&lt;br /&gt;
    local attempt&lt;br /&gt;
&lt;br /&gt;
    for attempt in {1..12}; do&lt;br /&gt;
        if health_once; then&lt;br /&gt;
            return 0&lt;br /&gt;
        fi&lt;br /&gt;
        sleep 5&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
    return 1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
finish() {&lt;br /&gt;
    local result=$?&lt;br /&gt;
    trap - EXIT&lt;br /&gt;
    set +e&lt;br /&gt;
&lt;br /&gt;
    if (( result != 0 &amp;amp;&amp;amp; deployment_started == 1 )); then&lt;br /&gt;
        log &amp;quot;Ошибка установки. Пытаемся вернуть $old_commit.&amp;quot;&lt;br /&gt;
        log &amp;quot;Автообновление останется на паузе.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        if systemctl stop &amp;quot;$APP_SERVICE&amp;quot;; then&lt;br /&gt;
            if git_app switch --no-overwrite-ignore \&lt;br /&gt;
                --detach &amp;quot;$old_commit&amp;quot;; then&lt;br /&gt;
&lt;br /&gt;
                if systemctl start &amp;quot;$APP_SERVICE&amp;quot; &amp;amp;&amp;amp; wait_healthy; then&lt;br /&gt;
                    log &amp;quot;Предыдущий код восстановлен, проверка пройдена.&amp;quot;&lt;br /&gt;
                else&lt;br /&gt;
                    log &amp;quot;КРИТИЧНО: после отката приложение не прошло проверку.&amp;quot;&lt;br /&gt;
                fi&lt;br /&gt;
            else&lt;br /&gt;
                log &amp;quot;КРИТИЧНО: вернуть код не удалось. Нужна ручная проверка.&amp;quot;&lt;br /&gt;
            fi&lt;br /&gt;
        else&lt;br /&gt;
            log &amp;quot;КРИТИЧНО: остановка не удалась; файлы не переключаем.&amp;quot;&lt;br /&gt;
        fi&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    exit &amp;quot;$result&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
trap finish EXIT&lt;br /&gt;
&lt;br /&gt;
install -d -m 700 &amp;quot;$STATE_DIR&amp;quot;&lt;br /&gt;
&lt;br /&gt;
exec 9&amp;gt;/run/lock/my-app-update.lock&lt;br /&gt;
if ! flock -n 9; then&lt;br /&gt;
    log &amp;quot;Другой запуск уже выполняется.&amp;quot;&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
if [[ -e &amp;quot;$PAUSE_FILE&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;Автообновление на паузе: $PAUSE_FILE&amp;quot;&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
cd &amp;quot;$APP_DIR&amp;quot;&lt;br /&gt;
&lt;br /&gt;
current_branch=$(git_app branch --show-current)&lt;br /&gt;
if [[ &amp;quot;$current_branch&amp;quot; != &amp;quot;$BRANCH&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;Ожидалась ветка $BRANCH, получена: $current_branch&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
working_changes=$(git_app status --porcelain --untracked-files=all)&lt;br /&gt;
if [[ -n &amp;quot;$working_changes&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;Есть локальные изменения или неотслеживаемые файлы.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
# Если приложение было остановлено администратором,&lt;br /&gt;
# обновлятор не должен сам запускать его.&lt;br /&gt;
if ! systemctl is-active --quiet &amp;quot;$APP_SERVICE&amp;quot;; then&lt;br /&gt;
    log &amp;quot;Приложение не активно. Обновление пропущено.&amp;quot;&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
log &amp;quot;Проверяем $REMOTE/$BRANCH.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
as_app env \&lt;br /&gt;
  GIT_TERMINAL_PROMPT=0 \&lt;br /&gt;
  GIT_SSH_COMMAND=&amp;quot;ssh -o BatchMode=yes -o ConnectTimeout=10&amp;quot; \&lt;br /&gt;
  timeout 60 git -C &amp;quot;$APP_DIR&amp;quot; fetch &amp;quot;$REMOTE&amp;quot; \&lt;br /&gt;
  &amp;quot;refs/heads/$BRANCH:refs/remotes/$REMOTE/$BRANCH&amp;quot;&lt;br /&gt;
&lt;br /&gt;
old_commit=$(git_app rev-parse HEAD)&lt;br /&gt;
new_commit=$(git_app rev-parse &amp;quot;refs/remotes/$REMOTE/$BRANCH&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
if [[ &amp;quot;$old_commit&amp;quot; == &amp;quot;$new_commit&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;Новых коммитов нет.&amp;quot;&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
if ! git_app merge-base --is-ancestor &amp;quot;$old_commit&amp;quot; &amp;quot;$new_commit&amp;quot;; then&lt;br /&gt;
    log &amp;quot;Истории разошлись или удалённая ветка отстаёт.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
# Разрешены только перечисленные пути.&lt;br /&gt;
# Зависимости, конфигурация, юниты и прочее требуют ручной установки.&lt;br /&gt;
changed_files=$(git_app diff --no-renames --name-only \&lt;br /&gt;
    &amp;quot;$old_commit&amp;quot; &amp;quot;$new_commit&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
while IFS= read -r changed_path; do&lt;br /&gt;
    case &amp;quot;$changed_path&amp;quot; in&lt;br /&gt;
        migrations/*|*/migrations/*|alembic/*|*/alembic/*)&lt;br /&gt;
            log &amp;quot;Миграции требуют ручного обновления.&amp;quot;&lt;br /&gt;
            exit 1&lt;br /&gt;
            ;;&lt;br /&gt;
        app/*.py|main.py|tests/*|docs/*|README.md)&lt;br /&gt;
            ;;&lt;br /&gt;
        *)&lt;br /&gt;
            log &amp;quot;Есть изменения вне разрешённых путей. Нужна ручная установка.&amp;quot;&lt;br /&gt;
            exit 1&lt;br /&gt;
            ;;&lt;br /&gt;
    esac&lt;br /&gt;
done &amp;lt;&amp;lt;&amp;lt; &amp;quot;$changed_files&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Не начинать установку поверх уже неисправного приложения.&lt;br /&gt;
if ! health_once; then&lt;br /&gt;
    log &amp;quot;Текущая версия не проходит проверку состояния.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
# Повторная проверка перед изменением файлов.&lt;br /&gt;
working_changes=$(git_app status --porcelain --untracked-files=all)&lt;br /&gt;
if [[ -n &amp;quot;$working_changes&amp;quot; ]] ||&lt;br /&gt;
   [[ &amp;quot;$(git_app rev-parse HEAD)&amp;quot; != &amp;quot;$old_commit&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;Рабочая копия изменилась во время проверки.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
backup_branch=&amp;quot;backup/auto-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
git_app branch &amp;quot;$backup_branch&amp;quot; &amp;quot;$old_commit&amp;quot;&lt;br /&gt;
&lt;br /&gt;
printf &#039;old=%s\nnew=%s\nbackup=%s\n&#039; \&lt;br /&gt;
    &amp;quot;$old_commit&amp;quot; &amp;quot;$new_commit&amp;quot; &amp;quot;$backup_branch&amp;quot; &amp;gt; &amp;quot;$PAUSE_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Маркер удаляется только после успешного обновления.&lt;br /&gt;
# При обрыве или перезагрузке следующий запуск не продолжит установку.&lt;br /&gt;
deployment_started=1&lt;br /&gt;
&lt;br /&gt;
log &amp;quot;Устанавливаем $new_commit. Резервная ветка: $backup_branch&amp;quot;&lt;br /&gt;
&lt;br /&gt;
systemctl stop &amp;quot;$APP_SERVICE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if systemctl is-active --quiet &amp;quot;$APP_SERVICE&amp;quot;; then&lt;br /&gt;
    log &amp;quot;Приложение не остановилось.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
git_app merge --ff-only --no-overwrite-ignore &amp;quot;$new_commit&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Проверка синтаксиса без создания файлов __pycache__.&lt;br /&gt;
# Пути нужно адаптировать под структуру проекта.&lt;br /&gt;
as_app &amp;quot;$APP_DIR/.venv/bin/python&amp;quot; - &amp;quot;$APP_DIR&amp;quot; &amp;lt;&amp;lt;&#039;PY&#039;&lt;br /&gt;
import pathlib&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
root = pathlib.Path(sys.argv[1])&lt;br /&gt;
files = list((root / &amp;quot;app&amp;quot;).rglob(&amp;quot;*.py&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
entry = root / &amp;quot;main.py&amp;quot;&lt;br /&gt;
if entry.is_file():&lt;br /&gt;
    files.append(entry)&lt;br /&gt;
&lt;br /&gt;
if not files:&lt;br /&gt;
    raise SystemExit(&amp;quot;Не найдены исходники для проверки&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
for path in files:&lt;br /&gt;
    compile(path.read_bytes(), str(path), &amp;quot;exec&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(f&amp;quot;Проверен синтаксис файлов: {len(files)}&amp;quot;)&lt;br /&gt;
PY&lt;br /&gt;
&lt;br /&gt;
systemctl start &amp;quot;$APP_SERVICE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if ! wait_healthy; then&lt;br /&gt;
    log &amp;quot;Новая версия не прошла проверку состояния.&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
rm -- &amp;quot;$PAUSE_FILE&amp;quot;&lt;br /&gt;
deployment_started=0&lt;br /&gt;
log &amp;quot;Обновление завершено: $new_commit&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Установить владельца, права и проверить синтаксис Bash:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /usr/local/sbin/my-app-update&lt;br /&gt;
chmod 750 /usr/local/sbin/my-app-update&lt;br /&gt;
bash -n /usr/local/sbin/my-app-update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсутствие вывода при успешном завершении bash -n означает, что синтаксис Bash корректен. Это не проверка работоспособности всей процедуры.&lt;br /&gt;
&lt;br /&gt;
=== Как устроена защита ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Механизм !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;flock&amp;lt;/code&amp;gt;&lt;br /&gt;
| Не позволяет двум экземплярам скрипта одновременно менять приложение.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;git status&amp;lt;/code&amp;gt;&lt;br /&gt;
| Останавливает обновление при локальных изменениях.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;fetch&amp;lt;/code&amp;gt; с ограничением времени&lt;br /&gt;
| Проверяет GitLab без остановки программы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;merge --ff-only&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отказывается объединять разошедшиеся истории.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;--no-overwrite-ignore&amp;lt;/code&amp;gt;&lt;br /&gt;
| Не разрешает перезаписывать мешающие обновлению игнорируемые файлы.&lt;br /&gt;
|-&lt;br /&gt;
| Разрешённые пути&lt;br /&gt;
| Отправляет изменения зависимостей и конфигурации на ручную установку.&lt;br /&gt;
|-&lt;br /&gt;
| Резервная ветка&lt;br /&gt;
| Сохраняет ссылку на предыдущий коммит.&lt;br /&gt;
|-&lt;br /&gt;
| Проверка синтаксиса и HTTP&lt;br /&gt;
| Проверяет код и ответ запущенного приложения.&lt;br /&gt;
|-&lt;br /&gt;
| Файл &amp;lt;code&amp;gt;PAUSED&amp;lt;/code&amp;gt;&lt;br /&gt;
| Блокирует дальнейшие установки после ошибки или прерванного обновления.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Git, Python и HTTP-проверка выполняются от имени myapp. Root используется для управления службой и служебными файлами обновлятора.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Список разрешённых путей не анализирует смысл кода.&#039;&#039;&#039; Даже изменение одного Python-файла может оказаться несовместимым с данными. Поэтому проверка изменений и CI перед публикацией в рабочую ветку обязательны.&lt;br /&gt;
&lt;br /&gt;
Во время работы обновлятора не выполнять ручные Git-операции в этом каталоге. Блокировка flock действует только на процессы, которые используют тот же файл блокировки.&lt;br /&gt;
&lt;br /&gt;
=== 5. Создание службы обновления ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/my-app-update.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Update my-app from GitLab&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
After=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=oneshot&lt;br /&gt;
User=root&lt;br /&gt;
UMask=0077&lt;br /&gt;
ExecStart=/usr/local/sbin/my-app-update&lt;br /&gt;
TimeoutStartSec=15min&lt;br /&gt;
StandardOutput=journal&lt;br /&gt;
StandardError=journal&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это отдельная служба обновлятора. Существующую my-app.service заменять не нужно.&lt;br /&gt;
&lt;br /&gt;
TimeoutStartSec ограничивает длительность всей операции. При принудительном завершении откат не гарантирован: файл PAUSED сохраняется для ручного восстановления.&lt;br /&gt;
&lt;br /&gt;
=== 6. Создание таймера ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/my-app-update.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Check my-app updates every 3 minutes&lt;br /&gt;
&lt;br /&gt;
[Timer]&lt;br /&gt;
OnBootSec=2min&lt;br /&gt;
OnUnitInactiveSec=3min&lt;br /&gt;
AccuracySec=10s&lt;br /&gt;
Unit=my-app-update.service&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=timers.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметры:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;OnBootSec=2min&amp;lt;/code&amp;gt; — первая проверка через две минуты после загрузки. При включении таймера позднее этого момента она может начаться сразу.&lt;br /&gt;
* &amp;lt;code&amp;gt;OnUnitInactiveSec=3min&amp;lt;/code&amp;gt; — следующая проверка через три минуты после завершения предыдущего запуска.&lt;br /&gt;
* &amp;lt;code&amp;gt;AccuracySec=10s&amp;lt;/code&amp;gt; — допустимое окно срабатывания таймера.&lt;br /&gt;
&lt;br /&gt;
Для другого интервала заменить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
OnUnitInactiveSec=2min&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
или:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
OnUnitInactiveSec=5min&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это интервал между проверками, а не гарантированный срок установки: сама операция тоже занимает время.&lt;br /&gt;
&lt;br /&gt;
=== 7. Первый запуск вручную ===&lt;br /&gt;
&lt;br /&gt;
До включения расписания адаптировать пути, пользователя, ветку и healthcheck.&lt;br /&gt;
&lt;br /&gt;
Проверить файлы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify \&lt;br /&gt;
  /etc/systemd/system/my-app-update.service \&lt;br /&gt;
  /etc/systemd/system/my-app-update.timer&lt;br /&gt;
&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запустить одну проверку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start my-app-update.service&lt;br /&gt;
journalctl -u my-app-update.service -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот запуск уже устанавливает новые коммиты, если они есть.&#039;&#039;&#039; Выполнять в согласованное время обслуживания.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить весь сценарий на тестовой копии, включая успешное обновление и отказ проверки с откатом.&lt;br /&gt;
&lt;br /&gt;
После успешного выполнения oneshot-служба обычно имеет состояние inactive (dead). Для неё это нормально.&lt;br /&gt;
&lt;br /&gt;
Результат последнего запуска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl show my-app-update.service \&lt;br /&gt;
  -p Result \&lt;br /&gt;
  -p ExecMainStatus&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Result=success&lt;br /&gt;
ExecMainStatus=0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 8. Включение расписания ===&lt;br /&gt;
&lt;br /&gt;
После проверки включить таймер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable --now my-app-update.timer&lt;br /&gt;
systemctl list-timers --all my-app-update.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В таблице будут показаны последнее и следующее срабатывания.&lt;br /&gt;
&lt;br /&gt;
=== Просмотр журналов ===&lt;br /&gt;
&lt;br /&gt;
Журнал обновлятора:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u my-app-update.service -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение в реальном времени:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u my-app-update.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Журнал самого приложения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u my-app.service -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример штатной проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Проверяем origin/main.&lt;br /&gt;
Новых коммитов нет.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Изменение интервала ===&lt;br /&gt;
&lt;br /&gt;
Изменить OnUnitInactiveSec в файле таймера, затем выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart my-app-update.timer&lt;br /&gt;
systemctl list-timers --all my-app-update.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Временное отключение ===&lt;br /&gt;
&lt;br /&gt;
Остановить расписание и отключить его автозапуск:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl disable --now my-app-update.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это не останавливает приложение и не прерывает уже выполняющееся обновление.&lt;br /&gt;
&lt;br /&gt;
Перед ручными работами проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status my-app-update.service --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Дождаться завершения текущей операции.&lt;br /&gt;
&lt;br /&gt;
=== Что делать после ошибки обновления ===&lt;br /&gt;
&lt;br /&gt;
Если ошибка произошла после начала установки, скрипт пытается вернуть предыдущий код. Дальнейшие установки блокируются файлом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/lib/my-app-updater/PAUSED&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отключить таймер и изучить состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl disable --now my-app-update.timer&lt;br /&gt;
&lt;br /&gt;
cat /var/lib/my-app-updater/PAUSED&lt;br /&gt;
&lt;br /&gt;
journalctl -u my-app-update.service -n 150 --no-pager&lt;br /&gt;
systemctl status my-app.service --no-pager -l&lt;br /&gt;
&lt;br /&gt;
runuser -u myapp -- git -C /opt/my-app status&lt;br /&gt;
runuser -u myapp -- git -C /opt/my-app log -1 --oneline&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После успешного отката репозиторий находится в detached HEAD на старом коммите. Ветка main может по-прежнему указывать на неудачное обновление.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не переключаться обратно на main и не удалять PAUSED вслепую.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для восстановления:&lt;br /&gt;
&lt;br /&gt;
# Исправить или отменить проблемное изменение в GitLab.&lt;br /&gt;
# Вручную установить и проверить исправленную версию по процедуре ручного обновления.&lt;br /&gt;
# Убедиться, что текущая ветка main, рабочая копия чистая и приложение исправно.&lt;br /&gt;
# Только после этого снять паузу.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
rm /var/lib/my-app-updater/PAUSED&lt;br /&gt;
systemctl reset-failed my-app-update.service&lt;br /&gt;
systemctl enable --now my-app-update.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При отключении питания, заполнении диска или принудительном завершении скрипта автоматический откат может не выполниться. Нужно проверить код и состояние службы через консоль.&lt;br /&gt;
&lt;br /&gt;
=== Изменение зависимостей или базы данных ===&lt;br /&gt;
&lt;br /&gt;
Если в GitLab изменились requirements.txt, lock-файл, юнит, конфигурация или файлы миграций, обновлятор откажется устанавливать такой коммит.&lt;br /&gt;
&lt;br /&gt;
В этом случае:&lt;br /&gt;
&lt;br /&gt;
# Отключить таймер.&lt;br /&gt;
# Дождаться завершения обновлятора.&lt;br /&gt;
# Сделать необходимые резервные копии.&lt;br /&gt;
# Выполнить ручное обновление по инструкции проекта.&lt;br /&gt;
# Проверить приложение.&lt;br /&gt;
# Снова включить таймер.&lt;br /&gt;
&lt;br /&gt;
Не добавлять автоматическую установку зависимостей или миграций без отдельного плана восстановления.&lt;br /&gt;
&lt;br /&gt;
=== Ограничения ===&lt;br /&gt;
&lt;br /&gt;
* Резервная ветка сохраняет только код, а не базу и пользовательские файлы.&lt;br /&gt;
* Успешный HTTP 200 не заменяет полноценные функциональные тесты.&lt;br /&gt;
* Скрипт не поддерживает развёртывание Git LFS и submodules без дополнительной адаптации.&lt;br /&gt;
* Приложение не должно самостоятельно менять отслеживаемые файлы.&lt;br /&gt;
* На время обновления не должно быть внешнего механизма, который снова запускает остановленную службу.&lt;br /&gt;
* Ошибки записываются в журнал; уведомления администратору здесь не настроены.&lt;br /&gt;
* Резервные ветки постепенно накапливаются. Их удаление следует выполнять отдельно после проверки стабильности и наличия резервных копий.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=164</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=164"/>
		<updated>2026-09-28T18:36:19Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Небольшие инструкции, полезные команды и практические приёмы администрирования Linux.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все IP-адреса, имена и идентификаторы приведены для примера. Заменяйте их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Подключение с Mac к LXC-контейнеру по SSH без ввода пароля root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox. Знать или создавать пароль root контейнера для этого не требуется.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение для примера&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Что необходимо ===&lt;br /&gt;
&lt;br /&gt;
* Административный доступ к консоли узла Proxmox.&lt;br /&gt;
* Запущенный LXC-контейнер с работающим SSH-сервером.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — через локальную сеть или VPN.&lt;br /&gt;
* Разрешённый на SSH-сервере вход root по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание ключа на Mac ===&lt;br /&gt;
&lt;br /&gt;
Открыть &#039;&#039;&#039;Терминал на Mac&#039;&#039;&#039; и выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
При создании нового ключа появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac. Его нельзя публиковать или передавать.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт ключ без парольной фразы. Получивший приватный ключ сможет использовать его для подключения к серверам, где разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Парольную фразу такого ключа можно сохранить в связке ключей macOS — порядок приведён ниже.&lt;br /&gt;
&lt;br /&gt;
=== 2. Копирование публичного ключа ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю выведенную строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Нужен именно публичный ключ:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Копировать строку целиком, без добавления переносов.&lt;br /&gt;
* Не копировать отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Не копировать графический рисунок ключа.&lt;br /&gt;
* Не передавать содержимое приватного файла &amp;lt;code&amp;gt;id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, но файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, восстановить публичный ключ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Вход в контейнер через Proxmox ===&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox открыть &#039;&#039;&#039;Shell узла, на котором запущен контейнер&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие команды выполняются &#039;&#039;&#039;внутри контейнера от имени root&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== 4. Добавление ключа в контейнер ===&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог и файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
touch /root/.ssh/authorized_keys&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; скопированной строкой с Mac, сохранив одинарные кавычки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;\n%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет запись в конец файла и сохраняет ранее добавленные ключи.&lt;br /&gt;
&lt;br /&gt;
Начальный перенос строки не позволяет новому ключу склеиться с предыдущей записью. Пустые строки в файле допустимы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 5. Проверка подлинности сервера ===&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение ключа сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с тем, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сравнивать нужно ключи одного типа&#039;&#039;&#039;: в этом примере ED25519.&lt;br /&gt;
&lt;br /&gt;
=== 6. Подключение с Mac ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить адрес на IP своего контейнера.&lt;br /&gt;
&lt;br /&gt;
Если появился запрос подтверждения ключа сервера и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения подключения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Сохранение парольной фразы ключа в macOS ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот шаг нужен только для ключа, защищённого парольной фразой.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; относится к приватному ключу на Mac, а не к паролю root контейнера.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для автоматического использования связки ключей добавить настройки из следующего раздела.&lt;br /&gt;
&lt;br /&gt;
=== 8. Короткая команда подключения ===&lt;br /&gt;
&lt;br /&gt;
Можно назначить подключению понятное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек SSH:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить блок, заменив адрес на нужный:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если блок &amp;lt;code&amp;gt;Host my-container&amp;lt;/code&amp;gt; уже существует, изменить его вместо создания дубликата. Если в файле есть общий блок &amp;lt;code&amp;gt;Host *&amp;lt;/code&amp;gt;, этот отдельный блок разместить перед ним.&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключение выполняется короткой командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Диагностика ===&lt;br /&gt;
&lt;br /&gt;
==== Запрашивается пароль root ====&lt;br /&gt;
&lt;br /&gt;
Авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить подключение с явным указанием ключа и подробным выводом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внутри контейнера через консоль Proxmox проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;700&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Проверить, что:&lt;br /&gt;
&lt;br /&gt;
* В файле находится публичный ключ с нужного Mac.&lt;br /&gt;
* Ключ записан одной строкой.&lt;br /&gt;
* Указаны правильные IP-адрес и пользователь.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
==== Connection refused ====&lt;br /&gt;
&lt;br /&gt;
Соединение отклонено.&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт подключения. Также причиной может быть правило межсетевого экрана, отклоняющее соединение.&lt;br /&gt;
&lt;br /&gt;
==== Connection timed out ====&lt;br /&gt;
&lt;br /&gt;
Сервер не ответил за отведённое время.&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его сеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
==== REMOTE HOST IDENTIFICATION HAS CHANGED ====&lt;br /&gt;
&lt;br /&gt;
Сохранённый на Mac ключ сервера отличается от текущего.&lt;br /&gt;
&lt;br /&gt;
Причиной может быть переустановка контейнера, замена ключей SSH или появление другого устройства по тому же адресу.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить новый отпечаток через доверенную консоль Proxmox. Не удалять старую запись без проверки причины изменения.&lt;br /&gt;
&lt;br /&gt;
=== Примечания ===&lt;br /&gt;
&lt;br /&gt;
* Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
* Для каждого дополнительного компьютера можно создать собственный ключ и добавить его публичную часть отдельной строкой в &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Чтобы отозвать доступ конкретного ключа, удалить соответствующую строку из &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;. Уже открытые SSH-сеансы при этом не завершаются.&lt;br /&gt;
* Добавление ключа само по себе не отключает парольную авторизацию SSH.&lt;br /&gt;
* Приватные ключи, пароли и другие секреты не должны попадать в публичную документацию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Следующую хитрость добавляйте ниже отдельным разделом:&lt;br /&gt;
== Название хитрости ==&lt;br /&gt;
Описание и команды.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Создание службы systemd: автозапуск и перезапуск программы ==&lt;br /&gt;
&lt;br /&gt;
=== Что такое юнит ===&lt;br /&gt;
&lt;br /&gt;
Юнит — объект, которым управляет systemd. Юнит с расширением &amp;lt;code&amp;gt;.service&amp;lt;/code&amp;gt; описывает службу: какую программу запустить, под каким пользователем и что делать при её завершении.&lt;br /&gt;
&lt;br /&gt;
Служба позволяет:&lt;br /&gt;
&lt;br /&gt;
* Запускать программу при загрузке системы.&lt;br /&gt;
* Продолжать работу после отключения от SSH.&lt;br /&gt;
* Автоматически перезапускать программу после сбоя.&lt;br /&gt;
* Просматривать состояние и журналы стандартными командами.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён рабочий учебный пример для Debian и Ubuntu с systemd. Служба будет записывать сообщение в журнал каждые 30 секунд.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются на том сервере или внутри того контейнера, где должна работать программа, от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание пользователя службы ===&lt;br /&gt;
&lt;br /&gt;
Для программы, которой не нужны административные права, создать отдельного системного пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
id demo-service &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || useradd \&lt;br /&gt;
  --system \&lt;br /&gt;
  --user-group \&lt;br /&gt;
  --home-dir /opt/demo-service \&lt;br /&gt;
  --no-create-home \&lt;br /&gt;
  --shell /usr/sbin/nologin \&lt;br /&gt;
  demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь предназначен для запуска службы, а не для интерактивного входа.&lt;br /&gt;
&lt;br /&gt;
Создать каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
install -d -o root -g root -m 755 /opt/demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Создание программы для проверки ===&lt;br /&gt;
&lt;br /&gt;
Открыть файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
    printf &#039;%s — служба работает\n&#039; &amp;quot;$(date --iso-8601=seconds)&amp;quot;&lt;br /&gt;
    sleep 30&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить: &amp;lt;code&amp;gt;Ctrl + O&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ctrl + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /opt/demo-service/run.sh&lt;br /&gt;
chmod 755 /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь службы сможет прочитать и запустить файл, но не изменить его.&lt;br /&gt;
&lt;br /&gt;
=== 3. Создание юнита ===&lt;br /&gt;
&lt;br /&gt;
Открыть новый файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Example background service&lt;br /&gt;
StartLimitIntervalSec=60&lt;br /&gt;
StartLimitBurst=5&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=exec&lt;br /&gt;
User=demo-service&lt;br /&gt;
Group=demo-service&lt;br /&gt;
WorkingDirectory=/opt/demo-service&lt;br /&gt;
ExecStart=/bin/bash /opt/demo-service/run.sh&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
StandardOutput=journal&lt;br /&gt;
StandardError=journal&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пояснение параметров ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Описание службы, зависимости и ограничения запуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Description&amp;lt;/code&amp;gt;&lt;br /&gt;
| Название, которое отображается в состоянии службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitIntervalSec=60&amp;lt;/code&amp;gt;&lt;br /&gt;
| Интервал учёта частых запусков — 60 секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitBurst=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Допускается до пяти запусков за указанный интервал. Ограничивает бесконечные попытки запуска при ошибке.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Service]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Параметры процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Type=exec&amp;lt;/code&amp;gt;&lt;br /&gt;
| systemd ожидает успешного запуска исполняемого файла. Это ещё не означает, что приложение полностью готово обслуживать запросы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;User&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;Group&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пользователь и группа процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WorkingDirectory&amp;lt;/code&amp;gt;&lt;br /&gt;
| Рабочий каталог программы. Должен существовать и быть доступен пользователю службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt;&lt;br /&gt;
| Команда запуска с абсолютными путями.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Restart=on-failure&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапуск после ошибки или аварийного завершения. Штатное завершение с кодом 0 не вызывает перезапуск.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RestartSec=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пауза перед перезапуском — пять секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardOutput=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Обычный вывод программы направляется в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardError=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ошибки программы направляются в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Install]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Настройки включения автозапуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WantedBy=multi-user.target&amp;lt;/code&amp;gt;&lt;br /&gt;
| Позволяет включить службу в обычный многопользовательский режим загрузки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка и запуск ===&lt;br /&gt;
&lt;br /&gt;
Проверить юнит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если обнаружены ошибки в созданном файле — исправить их до запуска.&lt;br /&gt;
&lt;br /&gt;
Перечитать юниты, включить автозапуск и сразу запустить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемое состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Просмотр журнала ===&lt;br /&gt;
&lt;br /&gt;
Последние 50 записей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение за новыми записями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нажатие &amp;lt;code&amp;gt;Ctrl + C&amp;lt;/code&amp;gt; завершает просмотр журнала, но не останавливает службу.&lt;br /&gt;
&lt;br /&gt;
=== Основные команды управления ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Команда !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl start demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl stop demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Остановить. Настройка Restart не отменяет ручную остановку.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Посмотреть состояние.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl enable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Включить автозапуск, не запуская службу немедленно.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск, не останавливая текущий процесс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable --now demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск и остановить службу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl cat demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Показать юнит и дополнительные настройки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Как адаптировать под свою программу ===&lt;br /&gt;
&lt;br /&gt;
Заменить имя службы, пользователя, рабочий каталог и команду запуска.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-приложения с виртуальным окружением:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
WorkingDirectory=/opt/my-app&lt;br /&gt;
ExecStart=/opt/my-app/.venv/bin/python -u /opt/my-app/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Виртуальное окружение и файл программы должны существовать. Активировать окружение командой &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; не требуется.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; отключает буферизацию стандартных потоков Python, чтобы сообщения быстрее попадали в журнал.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Особенности:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Программа должна работать на переднем плане: не добавляйте &amp;lt;code&amp;gt;&amp;amp;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nohup&amp;lt;/code&amp;gt; или собственный переход в фон.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt; не является обычной командной строкой оболочки: конструкции &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;&amp;amp;amp;&amp;amp;amp;&amp;lt;/code&amp;gt; не выполняются как в Bash.&lt;br /&gt;
* Сложную последовательность команд удобнее оформить отдельным скриптом.&lt;br /&gt;
* Пользователю службы нужны права чтения программы и записи только в необходимые каталоги данных.&lt;br /&gt;
* Переменные из интерактивного SSH-сеанса автоматически в службу не передаются.&lt;br /&gt;
&lt;br /&gt;
Для программы, которой при запуске нужна настроенная сеть, в секцию &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt; можно добавить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
After=network-online.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это не гарантирует доступность Интернета или внешнего API. Приложение должно самостоятельно повторять неудачные подключения.&lt;br /&gt;
&lt;br /&gt;
=== Применение изменений ===&lt;br /&gt;
&lt;br /&gt;
После изменения юнита:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart demo-service.service&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если изменён только код программы, обычно достаточно перезапуска службы.&lt;br /&gt;
&lt;br /&gt;
Если сработало ограничение частых запусков, сначала исправить причину по журналу, затем выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reset-failed demo-service.service&lt;br /&gt;
systemctl start demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Отключение парольного входа по SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Разрешить новые SSH-подключения только по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
Имя пользователя по-прежнему указывается, например &amp;lt;code&amp;gt;root@192.168.2.2&amp;lt;/code&amp;gt;. Меняется способ подтверждения доступа.&lt;br /&gt;
&lt;br /&gt;
Настройка не удаляет системные пароли и не меняет правила входа через локальную консоль или использования sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пример предназначен для Debian и Ubuntu с OpenSSH. Команды сервера выполняются от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка входа по ключу ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не закрывайте текущий сеанс до завершения всех проверок.&#039;&#039;&#039; Держите доступной консоль Proxmox или другую независимую консоль сервера.&lt;br /&gt;
&lt;br /&gt;
В новом терминале Mac проверить вход с запретом перехода к парольной авторизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PreferredAuthentications=publickey \&lt;br /&gt;
  -o PasswordAuthentication=no \&lt;br /&gt;
  -o KbdInteractiveAuthentication=no \&lt;br /&gt;
  -o IdentitiesOnly=yes \&lt;br /&gt;
  -i ~/.ssh/id_ed25519 \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вход не работает, сначала исправить авторизацию по ключу.&lt;br /&gt;
&lt;br /&gt;
Если сервером пользуются несколько администраторов, заранее настроить ключи для каждого.&lt;br /&gt;
&lt;br /&gt;
=== 2. Резервная копия конфигурации ===&lt;br /&gt;
&lt;br /&gt;
На сервере выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config \&lt;br /&gt;
  &amp;quot;/etc/ssh/sshd_config.backup-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Изменение настроек ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить в самое начало файла, перед директивами &amp;lt;code&amp;gt;Include&amp;lt;/code&amp;gt; и блоками &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
PubkeyAuthentication yes&lt;br /&gt;
PasswordAuthentication no&lt;br /&gt;
KbdInteractiveAuthentication no&lt;br /&gt;
AuthenticationMethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PubkeyAuthentication yes&amp;lt;/code&amp;gt;&lt;br /&gt;
| Разрешить авторизацию по публичному ключу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить обычную парольную авторизацию.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KbdInteractiveAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить интерактивную авторизацию, которая также может запрашивать пароль или одноразовый код.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AuthenticationMethods publickey&amp;lt;/code&amp;gt;&lt;br /&gt;
| Оставить только авторизацию по публичному ключу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот вариант также исключает другие способы входа и схемы «ключ плюс одноразовый код».&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для большинства параметров OpenSSH используется первое полученное значение. Блоки &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; могут задавать отдельные правила для пользователей и адресов, поэтому нужна проверка итоговой конфигурации.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;PermitRootLogin&amp;lt;/code&amp;gt; без необходимости не менять. Значение &amp;lt;code&amp;gt;no&amp;lt;/code&amp;gt; запрещает root любой SSH-вход; &amp;lt;code&amp;gt;prohibit-password&amp;lt;/code&amp;gt; допускает вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка перед применением ===&lt;br /&gt;
&lt;br /&gt;
Проверить синтаксис:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсутствие вывода при успешном завершении означает, что проверка пройдена. При ошибке конфигурацию не применять.&lt;br /&gt;
&lt;br /&gt;
Посмотреть общие итоговые параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
pubkeyauthentication yes&lt;br /&gt;
passwordauthentication no&lt;br /&gt;
kbdinteractiveauthentication no&lt;br /&gt;
authenticationmethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; дополнительно проверить конкретное подключение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T \&lt;br /&gt;
  -C user=root,addr=192.168.2.50,host=mac-client,laddr=192.168.2.2,lport=22 \&lt;br /&gt;
  | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|permitrootlogin) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В примере:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; — пользователь сервера.&lt;br /&gt;
* &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; — адрес клиента, видимый серверу.&lt;br /&gt;
* &amp;lt;code&amp;gt;host&amp;lt;/code&amp;gt; — имя клиента для правил Match Host.&lt;br /&gt;
* &amp;lt;code&amp;gt;laddr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lport&amp;lt;/code&amp;gt; — адрес и порт сервера.&lt;br /&gt;
&lt;br /&gt;
Подставить реальные параметры подключения. Проверить также другие учётные записи и адреса, для которых настроены отдельные правила.&lt;br /&gt;
&lt;br /&gt;
Если значения отличаются от ожидаемых, найти и исправить соответствующие настройки в основном файле, подключаемых файлах или блоках Match.&lt;br /&gt;
&lt;br /&gt;
=== 5. Применение ===&lt;br /&gt;
&lt;br /&gt;
Для стандартной службы SSH в Debian и Ubuntu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В системах, где служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload sshd.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выполняется только вариант с фактическим именем службы.&lt;br /&gt;
&lt;br /&gt;
Перечитывание конфигурации штатно сохраняет открытые сеансы.&lt;br /&gt;
&lt;br /&gt;
=== 6. Проверка нового подключения ===&lt;br /&gt;
&lt;br /&gt;
Не закрывая старый сеанс, в новом терминале Mac повторить команду проверки входа по ключу из первого шага.&lt;br /&gt;
&lt;br /&gt;
Затем проверить отказ для парольных способов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PubkeyAuthentication=no \&lt;br /&gt;
  -o PreferredAuthentications=password,keyboard-interactive \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат — отказ, обычно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Permission denied (publickey).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пароль учётной записи запрашиваться не должен.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Старый сеанс можно закрыть после успешного нового входа по ключу и проверки отказа для пароля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Восстановление при ошибке ===&lt;br /&gt;
&lt;br /&gt;
Использовать оставленный открытым сеанс или консоль Proxmox.&lt;br /&gt;
&lt;br /&gt;
Найти резервную копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lt /etc/ssh/sshd_config.backup-*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Восстановить нужную копию, указав её фактическое имя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config.backup-YYYYMMDD-HHMMSS /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить и применить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, заменить её имя в команде.&lt;br /&gt;
&lt;br /&gt;
=== Важно помнить ===&lt;br /&gt;
&lt;br /&gt;
* Парольная фраза приватного ключа на Mac может запрашиваться и после отключения паролей на сервере — это отдельная защита самого ключа.&lt;br /&gt;
* Настройка распространяется также на SFTP и SCP через этот SSH-сервер.&lt;br /&gt;
* Не удаляйте пароль пользователя и не блокируйте учётную запись ради отключения парольного SSH-входа: достаточно настроек SSH.&lt;br /&gt;
&lt;br /&gt;
== Проверка версии и обновление программы из GitLab ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Проверить, появились ли новые изменения в GitLab, сравнить их с установленным на сервере кодом и обновить программу.&lt;br /&gt;
&lt;br /&gt;
Инструкция предназначена для приложения, которое уже установлено из Git-репозитория и запускается через systemd.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все пути, имена и адреса приведены для примера.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Пример&lt;br /&gt;
|-&lt;br /&gt;
| Каталог программы || &amp;lt;code&amp;gt;/opt/my-app&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Репозиторий || &amp;lt;code&amp;gt;git@gitlab.example.com:team/my-app.git&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Удалённый репозиторий || &amp;lt;code&amp;gt;origin&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Рабочая ветка || &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Служба || &amp;lt;code&amp;gt;my-app.service&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Команды Git выполнять от имени владельца рабочей копии. Для управления системной службой нужны права root или sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются поэтапно. При ошибке не переходить к следующему шагу.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Основные понятия ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Термин !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Коммит&lt;br /&gt;
| Зафиксированное состояние кода с уникальным идентификатором.&lt;br /&gt;
|-&lt;br /&gt;
| Ветка&lt;br /&gt;
| Последовательность разработки, например &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; или &amp;lt;code&amp;gt;stable&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| HEAD&lt;br /&gt;
| Текущий коммит рабочей копии.&lt;br /&gt;
|-&lt;br /&gt;
| origin&lt;br /&gt;
| Обычно так называется подключённый удалённый репозиторий.&lt;br /&gt;
|-&lt;br /&gt;
| origin/main&lt;br /&gt;
| Последнее полученное локально состояние ветки main из origin. До fetch сведения могут быть устаревшими.&lt;br /&gt;
|-&lt;br /&gt;
| Тег&lt;br /&gt;
| Именованная отметка версии, например &amp;lt;code&amp;gt;v1.4.0&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| Release&lt;br /&gt;
| Опубликованный выпуск в GitLab, обычно связанный с тегом и описанием изменений.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Новый коммит в ветке не обязательно означает новый стабильный выпуск.&#039;&#039;&#039; Перед установкой проверить назначение ветки, описание выпуска и результаты CI в GitLab.&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка каталога и службы ===&lt;br /&gt;
&lt;br /&gt;
Перейти в каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/my-app&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Убедиться, что открыт нужный репозиторий:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pwd&lt;br /&gt;
git rev-parse --show-toplevel&lt;br /&gt;
git remote -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить, откуда systemd запускает программу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl show my-app.service --no-pager \&lt;br /&gt;
  -p WorkingDirectory \&lt;br /&gt;
  -p ExecStart \&lt;br /&gt;
  -p User&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пути должны соответствовать обновляемому приложению.&lt;br /&gt;
&lt;br /&gt;
Если служба запускает Docker-контейнер, установленный пакет или собранный файл из другого каталога, одного обновления исходников недостаточно. Нужна предусмотренная проектом сборка и установка.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не публикуйте вывод git remote -v, если в адрес репозитория встроен токен доступа.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 2. Определение текущей версии ===&lt;br /&gt;
&lt;br /&gt;
Выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --show-current&lt;br /&gt;
git log -1 --format=&#039;%h %ci %s&#039;&lt;br /&gt;
git rev-parse HEAD&lt;br /&gt;
git status --short --branch&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команды показывают:&lt;br /&gt;
&lt;br /&gt;
* Текущую ветку.&lt;br /&gt;
* Последний коммит, дату и описание.&lt;br /&gt;
* Полный идентификатор коммита.&lt;br /&gt;
* Состояние рабочей копии.&lt;br /&gt;
&lt;br /&gt;
Если имя ветки не выводится, репозиторий находится в состоянии detached HEAD — например, после установки определённого тега. Основной сценарий ниже рассчитан на ветку main.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Коммит в каталоге не доказывает, что запущенный процесс уже использует этот код.&#039;&#039;&#039; После обновления обычно требуется перезапуск или отдельный этап развёртывания.&lt;br /&gt;
&lt;br /&gt;
=== 3. Проверка локальных изменений ===&lt;br /&gt;
&lt;br /&gt;
Выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пустой вывод означает отсутствие отслеживаемых изменений и неотслеживаемых файлов. Игнорируемые файлы, например .env, эта команда не показывает.&lt;br /&gt;
&lt;br /&gt;
Типичные обозначения:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Обозначение !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;M&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл изменён.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;A&amp;lt;/code&amp;gt;&lt;br /&gt;
| Новый файл добавлен в индекс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;D&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл удалён.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;??&amp;lt;/code&amp;gt;&lt;br /&gt;
| Файл не отслеживается Git.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Если есть изменения, сначала выяснить их назначение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff&lt;br /&gt;
git diff --cached&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Не удалять локальные правки ради обновления. Сохранить нужный код отдельно или оформить его в согласованную ветку разработки.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не использовать git reset --hard или git clean -fd как универсальное исправление: они могут уничтожить нужные изменения и файлы.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 4. Получение сведений из GitLab ===&lt;br /&gt;
&lt;br /&gt;
Для примера с веткой main выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git fetch origin refs/heads/main:refs/remotes/origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда получает актуальное состояние нужной ветки. Файлы программы в рабочем каталоге не обновляются, служба продолжает работать.&lt;br /&gt;
&lt;br /&gt;
Если GitLab недоступен или авторизация завершилась ошибкой, остановиться: сравнение со старым origin/main не подтверждает актуальность сервера.&lt;br /&gt;
&lt;br /&gt;
Для приватного репозитория на сервере нужен доступ на чтение, например отдельный SSH Deploy Key. Ключ для входа с Mac на сервер сам по себе не предоставляет серверу доступ к GitLab.&lt;br /&gt;
&lt;br /&gt;
=== 5. Сравнение сервера с GitLab ===&lt;br /&gt;
&lt;br /&gt;
Показать количество уникальных коммитов с каждой стороны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git rev-list --left-right --count HEAD...origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Результат !! Значение !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0 0&amp;lt;/code&amp;gt;&lt;br /&gt;
| История совпадает.&lt;br /&gt;
| Обновление кода не требуется.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0 3&amp;lt;/code&amp;gt;&lt;br /&gt;
| В GitLab есть три новых коммита.&lt;br /&gt;
| Можно изучать обновление.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2 0&amp;lt;/code&amp;gt;&lt;br /&gt;
| На сервере есть два коммита, которых нет в origin/main.&lt;br /&gt;
| Выяснить происхождение локальных коммитов.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;2 3&amp;lt;/code&amp;gt;&lt;br /&gt;
| Истории разошлись.&lt;br /&gt;
| Разобраться с ветками; обычное обновление не выполнять.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Первое число относится к HEAD сервера, второе — к origin/main.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Продолжать основной сценарий следует только при результате 0 N, где N больше нуля, и при текущей ветке main.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 6. Просмотр состава обновления ===&lt;br /&gt;
&lt;br /&gt;
Зафиксировать идентификатор проверяемой версии:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
UPDATE_COMMIT=$(git rev-parse origin/main)&lt;br /&gt;
printf &#039;%s\n&#039; &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие шаги выполнять в том же терминале. После переподключения переменную нужно задать снова.&lt;br /&gt;
&lt;br /&gt;
Посмотреть новые коммиты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git --no-pager log --oneline HEAD..&amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть список и объём изменений:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git --no-pager diff --stat HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
git --no-pager diff --name-status HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть изменения кода:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git diff HEAD &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для выхода из просмотра нажать &amp;lt;code&amp;gt;q&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Перед установкой проверить:&lt;br /&gt;
&lt;br /&gt;
* Изменения зависимостей и требования к версии языка.&lt;br /&gt;
* Новые настройки и переменные окружения.&lt;br /&gt;
* Изменения юнита systemd.&lt;br /&gt;
* Необходимость сборки.&lt;br /&gt;
* Миграции базы данных.&lt;br /&gt;
* Инструкцию обновления и совместимость со старой версией.&lt;br /&gt;
&lt;br /&gt;
Обновляться будем до сохранённого UPDATE_COMMIT — именно до просмотренной версии.&lt;br /&gt;
&lt;br /&gt;
=== 7. Подготовка отката ===&lt;br /&gt;
&lt;br /&gt;
Создать локальную ветку, сохраняющую текущий коммит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
BACKUP_BRANCH=&amp;quot;backup/before-update-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
git branch &amp;quot;$BACKUP_BRANCH&amp;quot; HEAD&lt;br /&gt;
printf &#039;Ветка для отката: %s\n&#039; &amp;quot;$BACKUP_BRANCH&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Записать её имя.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Эта ветка сохраняет только версию кода в Git.&#039;&#039;&#039; Она не является резервной копией базы данных, загруженных файлов, .env или виртуального окружения.&lt;br /&gt;
&lt;br /&gt;
До обновления отдельно обеспечить восстановление:&lt;br /&gt;
&lt;br /&gt;
* Конфигурации и секретов.&lt;br /&gt;
* Базы данных штатными средствами используемой СУБД.&lt;br /&gt;
* Пользовательских файлов.&lt;br /&gt;
* Зависимостей приложения.&lt;br /&gt;
&lt;br /&gt;
При миграциях заранее определить, совместима ли новая структура базы со старым кодом. Копирование файлов работающей базы обычной командой cp не заменяет корректную резервную копию.&lt;br /&gt;
&lt;br /&gt;
=== 8. Остановка и обновление кода ===&lt;br /&gt;
&lt;br /&gt;
Этот способ предполагает короткий простой приложения.&lt;br /&gt;
&lt;br /&gt;
Ещё раз проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --show-current&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается ветка main и пустой вывод второй команды.&lt;br /&gt;
&lt;br /&gt;
Остановить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl stop my-app.service&lt;br /&gt;
sudo systemctl is-active my-app.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый ответ — &amp;lt;code&amp;gt;inactive&amp;lt;/code&amp;gt;. Для неактивной службы команда is-active возвращает ненулевой код, это нормально.&lt;br /&gt;
&lt;br /&gt;
Если приложение запускается также таймером, сокетом или внешним монитором, на время обновления приостановить и этот механизм.&lt;br /&gt;
&lt;br /&gt;
Обновить рабочую копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git merge --ff-only &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;--ff-only&amp;lt;/code&amp;gt; разрешает только прямое продвижение по истории без создания merge-коммита. При расхождении веток команда откажется выполнять слияние.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При ошибке не продолжать установку и не запускать непроверенную версию.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 9. Зависимости, сборка и проверки ===&lt;br /&gt;
&lt;br /&gt;
Выполнить шаги, предусмотренные документацией проекта. Универсальной команды установки для всех программ нет.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-проекта, использующего виртуальное окружение и requirements.txt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
.venv/bin/python -m pip install -r requirements.txt&lt;br /&gt;
.venv/bin/python -m pip check&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для проверки синтаксиса Python, если исходники находятся в каталоге app:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
.venv/bin/python -m compileall -q app&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить каталог app реальным каталогом исходников.&lt;br /&gt;
&lt;br /&gt;
Проверка синтаксиса не заменяет тестирование функций программы. Если проект использует lock-файл или другой менеджер зависимостей, применять его штатную процедуру.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;При ошибке установки, сборки, тестов или миграции остановиться.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Миграции базы выполнять только по инструкции проекта и после резервного копирования.&lt;br /&gt;
&lt;br /&gt;
Если изменился установленный юнит systemd, проверить и применить его отдельно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemd-analyze verify /etc/systemd/system/my-app.service&lt;br /&gt;
sudo systemctl daemon-reload&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Изменение копии юнита в Git-репозитории само по себе не обновляет файл в /etc/systemd/system.&lt;br /&gt;
&lt;br /&gt;
=== 10. Запуск и проверка ===&lt;br /&gt;
&lt;br /&gt;
После успешного выполнения подготовительных шагов запустить приложение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl start my-app.service&lt;br /&gt;
sudo systemctl status my-app.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть свежие журналы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo journalctl -u my-app.service --since &amp;quot;5 minutes ago&amp;quot; --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить установленный коммит с выбранным:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git rev-parse HEAD&lt;br /&gt;
printf &#039;%s\n&#039; &amp;quot;$UPDATE_COMMIT&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Идентификаторы должны совпасть.&lt;br /&gt;
&lt;br /&gt;
Проверить программу по назначению:&lt;br /&gt;
&lt;br /&gt;
* Для бота — отправить тестовую команду.&lt;br /&gt;
* Для сайта — открыть страницу и проверить основную операцию.&lt;br /&gt;
* Для API — выполнить предусмотренную проверку состояния.&lt;br /&gt;
* Для фоновой службы — убедиться, что она обрабатывает задания.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Состояние active (running) подтверждает наличие процесса, но не гарантирует работоспособность приложения.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 11. Откат к предыдущему коду ===&lt;br /&gt;
&lt;br /&gt;
Откат выполнять только после оценки совместимости старого кода с текущей базой и зависимостями.&lt;br /&gt;
&lt;br /&gt;
Остановить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl stop my-app.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Найти сохранённую ветку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git branch --list &#039;backup/before-update-*&#039;&lt;br /&gt;
git status --porcelain&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии новых локальных изменений сначала сохранить и изучить их.&lt;br /&gt;
&lt;br /&gt;
Переключиться на фактическую резервную ветку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch backup/before-update-YYYYMMDD-HHMMSS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подставить имя из списка. Команда меняет рабочие файлы на сохранённую версию, не переписывая ветку main.&lt;br /&gt;
&lt;br /&gt;
Затем:&lt;br /&gt;
&lt;br /&gt;
# Восстановить совместимые зависимости и конфигурацию.&lt;br /&gt;
# При необходимости выполнить предусмотренное восстановление базы.&lt;br /&gt;
# Проверить приложение.&lt;br /&gt;
# Запустить службу и посмотреть журнал.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo systemctl start my-app.service&lt;br /&gt;
sudo systemctl status my-app.service --no-pager -l&lt;br /&gt;
sudo journalctl -u my-app.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;После отката текущей становится резервная ветка.&#039;&#039;&#039; Перед следующим обновлением нужно осознанно выбрать дальнейшую ветку или выпуск.&lt;br /&gt;
&lt;br /&gt;
Повторная установка старого requirements.txt не гарантирует точное восстановление окружения: новые лишние пакеты могут остаться, а незакреплённые версии — измениться.&lt;br /&gt;
&lt;br /&gt;
=== Если новая версия опубликована тегом ===&lt;br /&gt;
&lt;br /&gt;
Если проект выпускает стабильные версии тегами, ориентироваться на указанный в GitLab Release тег, а не на последний коммит main.&lt;br /&gt;
&lt;br /&gt;
Получить теги:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git fetch origin --tags&lt;br /&gt;
git tag --list --sort=-version:refname&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порядок списка не гарантирует, что первый тег — рекомендованный стабильный выпуск. Проверить описание релиза и отметку предварительной версии в GitLab.&lt;br /&gt;
&lt;br /&gt;
Для выбранного примера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git show --no-patch v1.4.0&lt;br /&gt;
git diff --stat HEAD v1.4.0&lt;br /&gt;
git log --oneline HEAD..v1.4.0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После просмотра, резервного копирования и остановки службы вместо обновления ветки можно установить конкретный тег:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git switch --detach v1.4.0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это отдельный вариант установки. После него выполнить зависимости, сборку и проверки согласно выпуску.&lt;br /&gt;
&lt;br /&gt;
Состояние detached HEAD здесь ожидаемо: сервер закреплён за конкретным коммитом версии.&lt;br /&gt;
&lt;br /&gt;
=== Частые ошибки ===&lt;br /&gt;
&lt;br /&gt;
==== not a git repository ====&lt;br /&gt;
&lt;br /&gt;
Команда выполнена не в каталоге репозитория:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/my-app&lt;br /&gt;
git status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Permission denied (publickey) при fetch ====&lt;br /&gt;
&lt;br /&gt;
GitLab не принял SSH-ключ сервера.&lt;br /&gt;
&lt;br /&gt;
Проверить адрес origin и доступ серверного ключа к нужному проекту. Не переносить приватный ключ с личного компьютера без необходимости.&lt;br /&gt;
&lt;br /&gt;
==== Your local changes would be overwritten ====&lt;br /&gt;
&lt;br /&gt;
На сервере есть изменения файлов, которым мешает обновление.&lt;br /&gt;
&lt;br /&gt;
Посмотреть git status и git diff. Не применять принудительный сброс без понимания, какие данные будут потеряны.&lt;br /&gt;
&lt;br /&gt;
==== Not possible to fast-forward ====&lt;br /&gt;
&lt;br /&gt;
Истории разошлись. Проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git log --oneline --graph --decorate --max-count=30 HEAD origin/main&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Разобраться с локальными коммитами и изменениями ветки в GitLab до обновления.&lt;br /&gt;
&lt;br /&gt;
==== Код обновлён, поведение старое ====&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Был ли перезапущен нужный процесс.&lt;br /&gt;
* Из какого каталога запускается служба.&lt;br /&gt;
* Не требуется ли сборка.&lt;br /&gt;
* Не работает ли другая копия приложения.&lt;br /&gt;
* Не запускается ли приложение из Docker-образа или установленного пакета.&lt;br /&gt;
&lt;br /&gt;
=== Короткая проверка наличия обновлений ===&lt;br /&gt;
&lt;br /&gt;
Следующий блок только получает сведения и сравнивает версии. Он не обновляет рабочие файлы и не перезапускает программу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
(&lt;br /&gt;
  cd /opt/my-app || exit 1&lt;br /&gt;
&lt;br /&gt;
  git status --short --branch&lt;br /&gt;
  git log -1 --oneline&lt;br /&gt;
&lt;br /&gt;
  git fetch origin refs/heads/main:refs/remotes/origin/main || exit 1&lt;br /&gt;
&lt;br /&gt;
  git rev-list --left-right --count HEAD...origin/main&lt;br /&gt;
  git --no-pager log --oneline HEAD..origin/main&lt;br /&gt;
  git --no-pager diff --stat HEAD origin/main&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=163</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=163"/>
		<updated>2026-09-28T18:29:17Z</updated>

		<summary type="html">&lt;p&gt;Artem: /* SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Небольшие инструкции, полезные команды и практические приёмы администрирования Linux.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все IP-адреса, имена и идентификаторы приведены для примера. Заменяйте их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Подключение с Mac к LXC-контейнеру по SSH без ввода пароля root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox. Знать или создавать пароль root контейнера для этого не требуется.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение для примера&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Что необходимо ===&lt;br /&gt;
&lt;br /&gt;
* Административный доступ к консоли узла Proxmox.&lt;br /&gt;
* Запущенный LXC-контейнер с работающим SSH-сервером.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — через локальную сеть или VPN.&lt;br /&gt;
* Разрешённый на SSH-сервере вход root по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание ключа на Mac ===&lt;br /&gt;
&lt;br /&gt;
Открыть &#039;&#039;&#039;Терминал на Mac&#039;&#039;&#039; и выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
При создании нового ключа появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac. Его нельзя публиковать или передавать.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт ключ без парольной фразы. Получивший приватный ключ сможет использовать его для подключения к серверам, где разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Парольную фразу такого ключа можно сохранить в связке ключей macOS — порядок приведён ниже.&lt;br /&gt;
&lt;br /&gt;
=== 2. Копирование публичного ключа ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю выведенную строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Нужен именно публичный ключ:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Копировать строку целиком, без добавления переносов.&lt;br /&gt;
* Не копировать отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Не копировать графический рисунок ключа.&lt;br /&gt;
* Не передавать содержимое приватного файла &amp;lt;code&amp;gt;id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, но файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, восстановить публичный ключ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Вход в контейнер через Proxmox ===&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox открыть &#039;&#039;&#039;Shell узла, на котором запущен контейнер&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие команды выполняются &#039;&#039;&#039;внутри контейнера от имени root&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== 4. Добавление ключа в контейнер ===&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог и файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
touch /root/.ssh/authorized_keys&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; скопированной строкой с Mac, сохранив одинарные кавычки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;\n%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет запись в конец файла и сохраняет ранее добавленные ключи.&lt;br /&gt;
&lt;br /&gt;
Начальный перенос строки не позволяет новому ключу склеиться с предыдущей записью. Пустые строки в файле допустимы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 5. Проверка подлинности сервера ===&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение ключа сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с тем, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сравнивать нужно ключи одного типа&#039;&#039;&#039;: в этом примере ED25519.&lt;br /&gt;
&lt;br /&gt;
=== 6. Подключение с Mac ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить адрес на IP своего контейнера.&lt;br /&gt;
&lt;br /&gt;
Если появился запрос подтверждения ключа сервера и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения подключения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Сохранение парольной фразы ключа в macOS ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот шаг нужен только для ключа, защищённого парольной фразой.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; относится к приватному ключу на Mac, а не к паролю root контейнера.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для автоматического использования связки ключей добавить настройки из следующего раздела.&lt;br /&gt;
&lt;br /&gt;
=== 8. Короткая команда подключения ===&lt;br /&gt;
&lt;br /&gt;
Можно назначить подключению понятное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек SSH:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить блок, заменив адрес на нужный:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если блок &amp;lt;code&amp;gt;Host my-container&amp;lt;/code&amp;gt; уже существует, изменить его вместо создания дубликата. Если в файле есть общий блок &amp;lt;code&amp;gt;Host *&amp;lt;/code&amp;gt;, этот отдельный блок разместить перед ним.&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключение выполняется короткой командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Диагностика ===&lt;br /&gt;
&lt;br /&gt;
==== Запрашивается пароль root ====&lt;br /&gt;
&lt;br /&gt;
Авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить подключение с явным указанием ключа и подробным выводом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внутри контейнера через консоль Proxmox проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;700&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Проверить, что:&lt;br /&gt;
&lt;br /&gt;
* В файле находится публичный ключ с нужного Mac.&lt;br /&gt;
* Ключ записан одной строкой.&lt;br /&gt;
* Указаны правильные IP-адрес и пользователь.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
==== Connection refused ====&lt;br /&gt;
&lt;br /&gt;
Соединение отклонено.&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт подключения. Также причиной может быть правило межсетевого экрана, отклоняющее соединение.&lt;br /&gt;
&lt;br /&gt;
==== Connection timed out ====&lt;br /&gt;
&lt;br /&gt;
Сервер не ответил за отведённое время.&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его сеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
==== REMOTE HOST IDENTIFICATION HAS CHANGED ====&lt;br /&gt;
&lt;br /&gt;
Сохранённый на Mac ключ сервера отличается от текущего.&lt;br /&gt;
&lt;br /&gt;
Причиной может быть переустановка контейнера, замена ключей SSH или появление другого устройства по тому же адресу.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить новый отпечаток через доверенную консоль Proxmox. Не удалять старую запись без проверки причины изменения.&lt;br /&gt;
&lt;br /&gt;
=== Примечания ===&lt;br /&gt;
&lt;br /&gt;
* Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
* Для каждого дополнительного компьютера можно создать собственный ключ и добавить его публичную часть отдельной строкой в &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Чтобы отозвать доступ конкретного ключа, удалить соответствующую строку из &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;. Уже открытые SSH-сеансы при этом не завершаются.&lt;br /&gt;
* Добавление ключа само по себе не отключает парольную авторизацию SSH.&lt;br /&gt;
* Приватные ключи, пароли и другие секреты не должны попадать в публичную документацию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Следующую хитрость добавляйте ниже отдельным разделом:&lt;br /&gt;
== Название хитрости ==&lt;br /&gt;
Описание и команды.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Создание службы systemd: автозапуск и перезапуск программы ==&lt;br /&gt;
&lt;br /&gt;
=== Что такое юнит ===&lt;br /&gt;
&lt;br /&gt;
Юнит — объект, которым управляет systemd. Юнит с расширением &amp;lt;code&amp;gt;.service&amp;lt;/code&amp;gt; описывает службу: какую программу запустить, под каким пользователем и что делать при её завершении.&lt;br /&gt;
&lt;br /&gt;
Служба позволяет:&lt;br /&gt;
&lt;br /&gt;
* Запускать программу при загрузке системы.&lt;br /&gt;
* Продолжать работу после отключения от SSH.&lt;br /&gt;
* Автоматически перезапускать программу после сбоя.&lt;br /&gt;
* Просматривать состояние и журналы стандартными командами.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён рабочий учебный пример для Debian и Ubuntu с systemd. Служба будет записывать сообщение в журнал каждые 30 секунд.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются на том сервере или внутри того контейнера, где должна работать программа, от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание пользователя службы ===&lt;br /&gt;
&lt;br /&gt;
Для программы, которой не нужны административные права, создать отдельного системного пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
id demo-service &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || useradd \&lt;br /&gt;
  --system \&lt;br /&gt;
  --user-group \&lt;br /&gt;
  --home-dir /opt/demo-service \&lt;br /&gt;
  --no-create-home \&lt;br /&gt;
  --shell /usr/sbin/nologin \&lt;br /&gt;
  demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь предназначен для запуска службы, а не для интерактивного входа.&lt;br /&gt;
&lt;br /&gt;
Создать каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
install -d -o root -g root -m 755 /opt/demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Создание программы для проверки ===&lt;br /&gt;
&lt;br /&gt;
Открыть файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
    printf &#039;%s — служба работает\n&#039; &amp;quot;$(date --iso-8601=seconds)&amp;quot;&lt;br /&gt;
    sleep 30&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить: &amp;lt;code&amp;gt;Ctrl + O&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ctrl + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /opt/demo-service/run.sh&lt;br /&gt;
chmod 755 /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь службы сможет прочитать и запустить файл, но не изменить его.&lt;br /&gt;
&lt;br /&gt;
=== 3. Создание юнита ===&lt;br /&gt;
&lt;br /&gt;
Открыть новый файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Example background service&lt;br /&gt;
StartLimitIntervalSec=60&lt;br /&gt;
StartLimitBurst=5&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=exec&lt;br /&gt;
User=demo-service&lt;br /&gt;
Group=demo-service&lt;br /&gt;
WorkingDirectory=/opt/demo-service&lt;br /&gt;
ExecStart=/bin/bash /opt/demo-service/run.sh&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
StandardOutput=journal&lt;br /&gt;
StandardError=journal&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пояснение параметров ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Описание службы, зависимости и ограничения запуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Description&amp;lt;/code&amp;gt;&lt;br /&gt;
| Название, которое отображается в состоянии службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitIntervalSec=60&amp;lt;/code&amp;gt;&lt;br /&gt;
| Интервал учёта частых запусков — 60 секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitBurst=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Допускается до пяти запусков за указанный интервал. Ограничивает бесконечные попытки запуска при ошибке.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Service]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Параметры процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Type=exec&amp;lt;/code&amp;gt;&lt;br /&gt;
| systemd ожидает успешного запуска исполняемого файла. Это ещё не означает, что приложение полностью готово обслуживать запросы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;User&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;Group&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пользователь и группа процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WorkingDirectory&amp;lt;/code&amp;gt;&lt;br /&gt;
| Рабочий каталог программы. Должен существовать и быть доступен пользователю службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt;&lt;br /&gt;
| Команда запуска с абсолютными путями.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Restart=on-failure&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапуск после ошибки или аварийного завершения. Штатное завершение с кодом 0 не вызывает перезапуск.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RestartSec=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пауза перед перезапуском — пять секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardOutput=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Обычный вывод программы направляется в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardError=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ошибки программы направляются в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Install]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Настройки включения автозапуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WantedBy=multi-user.target&amp;lt;/code&amp;gt;&lt;br /&gt;
| Позволяет включить службу в обычный многопользовательский режим загрузки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка и запуск ===&lt;br /&gt;
&lt;br /&gt;
Проверить юнит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если обнаружены ошибки в созданном файле — исправить их до запуска.&lt;br /&gt;
&lt;br /&gt;
Перечитать юниты, включить автозапуск и сразу запустить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемое состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Просмотр журнала ===&lt;br /&gt;
&lt;br /&gt;
Последние 50 записей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение за новыми записями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нажатие &amp;lt;code&amp;gt;Ctrl + C&amp;lt;/code&amp;gt; завершает просмотр журнала, но не останавливает службу.&lt;br /&gt;
&lt;br /&gt;
=== Основные команды управления ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Команда !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl start demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl stop demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Остановить. Настройка Restart не отменяет ручную остановку.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Посмотреть состояние.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl enable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Включить автозапуск, не запуская службу немедленно.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск, не останавливая текущий процесс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable --now demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск и остановить службу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl cat demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Показать юнит и дополнительные настройки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Как адаптировать под свою программу ===&lt;br /&gt;
&lt;br /&gt;
Заменить имя службы, пользователя, рабочий каталог и команду запуска.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-приложения с виртуальным окружением:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
WorkingDirectory=/opt/my-app&lt;br /&gt;
ExecStart=/opt/my-app/.venv/bin/python -u /opt/my-app/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Виртуальное окружение и файл программы должны существовать. Активировать окружение командой &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; не требуется.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; отключает буферизацию стандартных потоков Python, чтобы сообщения быстрее попадали в журнал.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Особенности:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Программа должна работать на переднем плане: не добавляйте &amp;lt;code&amp;gt;&amp;amp;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nohup&amp;lt;/code&amp;gt; или собственный переход в фон.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt; не является обычной командной строкой оболочки: конструкции &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;&amp;amp;amp;&amp;amp;amp;&amp;lt;/code&amp;gt; не выполняются как в Bash.&lt;br /&gt;
* Сложную последовательность команд удобнее оформить отдельным скриптом.&lt;br /&gt;
* Пользователю службы нужны права чтения программы и записи только в необходимые каталоги данных.&lt;br /&gt;
* Переменные из интерактивного SSH-сеанса автоматически в службу не передаются.&lt;br /&gt;
&lt;br /&gt;
Для программы, которой при запуске нужна настроенная сеть, в секцию &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt; можно добавить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
After=network-online.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это не гарантирует доступность Интернета или внешнего API. Приложение должно самостоятельно повторять неудачные подключения.&lt;br /&gt;
&lt;br /&gt;
=== Применение изменений ===&lt;br /&gt;
&lt;br /&gt;
После изменения юнита:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart demo-service.service&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если изменён только код программы, обычно достаточно перезапуска службы.&lt;br /&gt;
&lt;br /&gt;
Если сработало ограничение частых запусков, сначала исправить причину по журналу, затем выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reset-failed demo-service.service&lt;br /&gt;
systemctl start demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Отключение парольного входа по SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Разрешить новые SSH-подключения только по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
Имя пользователя по-прежнему указывается, например &amp;lt;code&amp;gt;root@192.168.2.2&amp;lt;/code&amp;gt;. Меняется способ подтверждения доступа.&lt;br /&gt;
&lt;br /&gt;
Настройка не удаляет системные пароли и не меняет правила входа через локальную консоль или использования sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пример предназначен для Debian и Ubuntu с OpenSSH. Команды сервера выполняются от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка входа по ключу ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не закрывайте текущий сеанс до завершения всех проверок.&#039;&#039;&#039; Держите доступной консоль Proxmox или другую независимую консоль сервера.&lt;br /&gt;
&lt;br /&gt;
В новом терминале Mac проверить вход с запретом перехода к парольной авторизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PreferredAuthentications=publickey \&lt;br /&gt;
  -o PasswordAuthentication=no \&lt;br /&gt;
  -o KbdInteractiveAuthentication=no \&lt;br /&gt;
  -o IdentitiesOnly=yes \&lt;br /&gt;
  -i ~/.ssh/id_ed25519 \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вход не работает, сначала исправить авторизацию по ключу.&lt;br /&gt;
&lt;br /&gt;
Если сервером пользуются несколько администраторов, заранее настроить ключи для каждого.&lt;br /&gt;
&lt;br /&gt;
=== 2. Резервная копия конфигурации ===&lt;br /&gt;
&lt;br /&gt;
На сервере выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config \&lt;br /&gt;
  &amp;quot;/etc/ssh/sshd_config.backup-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Изменение настроек ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить в самое начало файла, перед директивами &amp;lt;code&amp;gt;Include&amp;lt;/code&amp;gt; и блоками &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
PubkeyAuthentication yes&lt;br /&gt;
PasswordAuthentication no&lt;br /&gt;
KbdInteractiveAuthentication no&lt;br /&gt;
AuthenticationMethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PubkeyAuthentication yes&amp;lt;/code&amp;gt;&lt;br /&gt;
| Разрешить авторизацию по публичному ключу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить обычную парольную авторизацию.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KbdInteractiveAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить интерактивную авторизацию, которая также может запрашивать пароль или одноразовый код.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AuthenticationMethods publickey&amp;lt;/code&amp;gt;&lt;br /&gt;
| Оставить только авторизацию по публичному ключу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот вариант также исключает другие способы входа и схемы «ключ плюс одноразовый код».&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для большинства параметров OpenSSH используется первое полученное значение. Блоки &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; могут задавать отдельные правила для пользователей и адресов, поэтому нужна проверка итоговой конфигурации.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;PermitRootLogin&amp;lt;/code&amp;gt; без необходимости не менять. Значение &amp;lt;code&amp;gt;no&amp;lt;/code&amp;gt; запрещает root любой SSH-вход; &amp;lt;code&amp;gt;prohibit-password&amp;lt;/code&amp;gt; допускает вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка перед применением ===&lt;br /&gt;
&lt;br /&gt;
Проверить синтаксис:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсутствие вывода при успешном завершении означает, что проверка пройдена. При ошибке конфигурацию не применять.&lt;br /&gt;
&lt;br /&gt;
Посмотреть общие итоговые параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
pubkeyauthentication yes&lt;br /&gt;
passwordauthentication no&lt;br /&gt;
kbdinteractiveauthentication no&lt;br /&gt;
authenticationmethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; дополнительно проверить конкретное подключение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T \&lt;br /&gt;
  -C user=root,addr=192.168.2.50,host=mac-client,laddr=192.168.2.2,lport=22 \&lt;br /&gt;
  | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|permitrootlogin) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В примере:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; — пользователь сервера.&lt;br /&gt;
* &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; — адрес клиента, видимый серверу.&lt;br /&gt;
* &amp;lt;code&amp;gt;host&amp;lt;/code&amp;gt; — имя клиента для правил Match Host.&lt;br /&gt;
* &amp;lt;code&amp;gt;laddr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lport&amp;lt;/code&amp;gt; — адрес и порт сервера.&lt;br /&gt;
&lt;br /&gt;
Подставить реальные параметры подключения. Проверить также другие учётные записи и адреса, для которых настроены отдельные правила.&lt;br /&gt;
&lt;br /&gt;
Если значения отличаются от ожидаемых, найти и исправить соответствующие настройки в основном файле, подключаемых файлах или блоках Match.&lt;br /&gt;
&lt;br /&gt;
=== 5. Применение ===&lt;br /&gt;
&lt;br /&gt;
Для стандартной службы SSH в Debian и Ubuntu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В системах, где служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload sshd.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выполняется только вариант с фактическим именем службы.&lt;br /&gt;
&lt;br /&gt;
Перечитывание конфигурации штатно сохраняет открытые сеансы.&lt;br /&gt;
&lt;br /&gt;
=== 6. Проверка нового подключения ===&lt;br /&gt;
&lt;br /&gt;
Не закрывая старый сеанс, в новом терминале Mac повторить команду проверки входа по ключу из первого шага.&lt;br /&gt;
&lt;br /&gt;
Затем проверить отказ для парольных способов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PubkeyAuthentication=no \&lt;br /&gt;
  -o PreferredAuthentications=password,keyboard-interactive \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат — отказ, обычно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Permission denied (publickey).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пароль учётной записи запрашиваться не должен.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Старый сеанс можно закрыть после успешного нового входа по ключу и проверки отказа для пароля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Восстановление при ошибке ===&lt;br /&gt;
&lt;br /&gt;
Использовать оставленный открытым сеанс или консоль Proxmox.&lt;br /&gt;
&lt;br /&gt;
Найти резервную копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lt /etc/ssh/sshd_config.backup-*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Восстановить нужную копию, указав её фактическое имя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config.backup-YYYYMMDD-HHMMSS /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить и применить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, заменить её имя в команде.&lt;br /&gt;
&lt;br /&gt;
=== Важно помнить ===&lt;br /&gt;
&lt;br /&gt;
* Парольная фраза приватного ключа на Mac может запрашиваться и после отключения паролей на сервере — это отдельная защита самого ключа.&lt;br /&gt;
* Настройка распространяется также на SFTP и SCP через этот SSH-сервер.&lt;br /&gt;
* Не удаляйте пароль пользователя и не блокируйте учётную запись ради отключения парольного SSH-входа: достаточно настроек SSH.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=162</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=162"/>
		<updated>2026-09-28T18:25:55Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Небольшие инструкции, полезные команды и практические приёмы администрирования Linux.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все IP-адреса, имена и идентификаторы приведены для примера. Заменяйте их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Подключение с Mac к LXC-контейнеру по SSH без ввода пароля root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox. Знать или создавать пароль root контейнера для этого не требуется.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение для примера&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Что необходимо ===&lt;br /&gt;
&lt;br /&gt;
* Административный доступ к консоли узла Proxmox.&lt;br /&gt;
* Запущенный LXC-контейнер с работающим SSH-сервером.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — через локальную сеть или VPN.&lt;br /&gt;
* Разрешённый на SSH-сервере вход root по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание ключа на Mac ===&lt;br /&gt;
&lt;br /&gt;
Открыть &#039;&#039;&#039;Терминал на Mac&#039;&#039;&#039; и выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
При создании нового ключа появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac. Его нельзя публиковать или передавать.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт ключ без парольной фразы. Получивший приватный ключ сможет использовать его для подключения к серверам, где разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Парольную фразу такого ключа можно сохранить в связке ключей macOS — порядок приведён ниже.&lt;br /&gt;
&lt;br /&gt;
=== 2. Копирование публичного ключа ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю выведенную строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Нужен именно публичный ключ:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Копировать строку целиком, без добавления переносов.&lt;br /&gt;
* Не копировать отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Не копировать графический рисунок ключа.&lt;br /&gt;
* Не передавать содержимое приватного файла &amp;lt;code&amp;gt;id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, но файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, восстановить публичный ключ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Вход в контейнер через Proxmox ===&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox открыть &#039;&#039;&#039;Shell узла, на котором запущен контейнер&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие команды выполняются &#039;&#039;&#039;внутри контейнера от имени root&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== 4. Добавление ключа в контейнер ===&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог и файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
touch /root/.ssh/authorized_keys&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; скопированной строкой с Mac, сохранив одинарные кавычки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;\n%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет запись в конец файла и сохраняет ранее добавленные ключи.&lt;br /&gt;
&lt;br /&gt;
Начальный перенос строки не позволяет новому ключу склеиться с предыдущей записью. Пустые строки в файле допустимы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 5. Проверка подлинности сервера ===&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение ключа сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с тем, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сравнивать нужно ключи одного типа&#039;&#039;&#039;: в этом примере ED25519.&lt;br /&gt;
&lt;br /&gt;
=== 6. Подключение с Mac ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить адрес на IP своего контейнера.&lt;br /&gt;
&lt;br /&gt;
Если появился запрос подтверждения ключа сервера и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения подключения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Сохранение парольной фразы ключа в macOS ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот шаг нужен только для ключа, защищённого парольной фразой.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; относится к приватному ключу на Mac, а не к паролю root контейнера.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для автоматического использования связки ключей добавить настройки из следующего раздела.&lt;br /&gt;
&lt;br /&gt;
=== 8. Короткая команда подключения ===&lt;br /&gt;
&lt;br /&gt;
Можно назначить подключению понятное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек SSH:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить блок, заменив адрес на нужный:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если блок &amp;lt;code&amp;gt;Host my-container&amp;lt;/code&amp;gt; уже существует, изменить его вместо создания дубликата. Если в файле есть общий блок &amp;lt;code&amp;gt;Host *&amp;lt;/code&amp;gt;, этот отдельный блок разместить перед ним.&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключение выполняется короткой командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Диагностика ===&lt;br /&gt;
&lt;br /&gt;
==== Запрашивается пароль root ====&lt;br /&gt;
&lt;br /&gt;
Авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить подключение с явным указанием ключа и подробным выводом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внутри контейнера через консоль Proxmox проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;700&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Проверить, что:&lt;br /&gt;
&lt;br /&gt;
* В файле находится публичный ключ с нужного Mac.&lt;br /&gt;
* Ключ записан одной строкой.&lt;br /&gt;
* Указаны правильные IP-адрес и пользователь.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
==== Connection refused ====&lt;br /&gt;
&lt;br /&gt;
Соединение отклонено.&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт подключения. Также причиной может быть правило межсетевого экрана, отклоняющее соединение.&lt;br /&gt;
&lt;br /&gt;
==== Connection timed out ====&lt;br /&gt;
&lt;br /&gt;
Сервер не ответил за отведённое время.&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его сеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
==== REMOTE HOST IDENTIFICATION HAS CHANGED ====&lt;br /&gt;
&lt;br /&gt;
Сохранённый на Mac ключ сервера отличается от текущего.&lt;br /&gt;
&lt;br /&gt;
Причиной может быть переустановка контейнера, замена ключей SSH или появление другого устройства по тому же адресу.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить новый отпечаток через доверенную консоль Proxmox. Не удалять старую запись без проверки причины изменения.&lt;br /&gt;
&lt;br /&gt;
=== Примечания ===&lt;br /&gt;
&lt;br /&gt;
* Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
* Для каждого дополнительного компьютера можно создать собственный ключ и добавить его публичную часть отдельной строкой в &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Чтобы отозвать доступ конкретного ключа, удалить соответствующую строку из &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;. Уже открытые SSH-сеансы при этом не завершаются.&lt;br /&gt;
* Добавление ключа само по себе не отключает парольную авторизацию SSH.&lt;br /&gt;
* Приватные ключи, пароли и другие секреты не должны попадать в публичную документацию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Следующую хитрость добавляйте ниже отдельным разделом:&lt;br /&gt;
== Название хитрости ==&lt;br /&gt;
Описание и команды.&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
== Создание службы systemd: автозапуск и перезапуск программы ==&lt;br /&gt;
&lt;br /&gt;
=== Что такое юнит ===&lt;br /&gt;
&lt;br /&gt;
Юнит — объект, которым управляет systemd. Юнит с расширением &amp;lt;code&amp;gt;.service&amp;lt;/code&amp;gt; описывает службу: какую программу запустить, под каким пользователем и что делать при её завершении.&lt;br /&gt;
&lt;br /&gt;
Служба позволяет:&lt;br /&gt;
&lt;br /&gt;
* Запускать программу при загрузке системы.&lt;br /&gt;
* Продолжать работу после отключения от SSH.&lt;br /&gt;
* Автоматически перезапускать программу после сбоя.&lt;br /&gt;
* Просматривать состояние и журналы стандартными командами.&lt;br /&gt;
&lt;br /&gt;
Ниже приведён рабочий учебный пример для Debian и Ubuntu с systemd. Служба будет записывать сообщение в журнал каждые 30 секунд.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Команды выполняются на том сервере или внутри того контейнера, где должна работать программа, от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание пользователя службы ===&lt;br /&gt;
&lt;br /&gt;
Для программы, которой не нужны административные права, создать отдельного системного пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
id demo-service &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || useradd \&lt;br /&gt;
  --system \&lt;br /&gt;
  --user-group \&lt;br /&gt;
  --home-dir /opt/demo-service \&lt;br /&gt;
  --no-create-home \&lt;br /&gt;
  --shell /usr/sbin/nologin \&lt;br /&gt;
  demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь предназначен для запуска службы, а не для интерактивного входа.&lt;br /&gt;
&lt;br /&gt;
Создать каталог программы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
install -d -o root -g root -m 755 /opt/demo-service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 2. Создание программы для проверки ===&lt;br /&gt;
&lt;br /&gt;
Открыть файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
while true; do&lt;br /&gt;
    printf &#039;%s — служба работает\n&#039; &amp;quot;$(date --iso-8601=seconds)&amp;quot;&lt;br /&gt;
    sleep 30&lt;br /&gt;
done&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить: &amp;lt;code&amp;gt;Ctrl + O&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;Ctrl + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /opt/demo-service/run.sh&lt;br /&gt;
chmod 755 /opt/demo-service/run.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пользователь службы сможет прочитать и запустить файл, но не изменить его.&lt;br /&gt;
&lt;br /&gt;
=== 3. Создание юнита ===&lt;br /&gt;
&lt;br /&gt;
Открыть новый файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вставить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Example background service&lt;br /&gt;
StartLimitIntervalSec=60&lt;br /&gt;
StartLimitBurst=5&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=exec&lt;br /&gt;
User=demo-service&lt;br /&gt;
Group=demo-service&lt;br /&gt;
WorkingDirectory=/opt/demo-service&lt;br /&gt;
ExecStart=/bin/bash /opt/demo-service/run.sh&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
StandardOutput=journal&lt;br /&gt;
StandardError=journal&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Пояснение параметров ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Описание службы, зависимости и ограничения запуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Description&amp;lt;/code&amp;gt;&lt;br /&gt;
| Название, которое отображается в состоянии службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitIntervalSec=60&amp;lt;/code&amp;gt;&lt;br /&gt;
| Интервал учёта частых запусков — 60 секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StartLimitBurst=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Допускается до пяти запусков за указанный интервал. Ограничивает бесконечные попытки запуска при ошибке.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Service]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Параметры процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Type=exec&amp;lt;/code&amp;gt;&lt;br /&gt;
| systemd ожидает успешного запуска исполняемого файла. Это ещё не означает, что приложение полностью готово обслуживать запросы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;User&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;Group&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пользователь и группа процесса.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WorkingDirectory&amp;lt;/code&amp;gt;&lt;br /&gt;
| Рабочий каталог программы. Должен существовать и быть доступен пользователю службы.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt;&lt;br /&gt;
| Команда запуска с абсолютными путями.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;Restart=on-failure&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапуск после ошибки или аварийного завершения. Штатное завершение с кодом 0 не вызывает перезапуск.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;RestartSec=5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Пауза перед перезапуском — пять секунд.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardOutput=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Обычный вывод программы направляется в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;StandardError=journal&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ошибки программы направляются в журнал.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;[Install]&amp;lt;/code&amp;gt;&lt;br /&gt;
| Настройки включения автозапуска.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;WantedBy=multi-user.target&amp;lt;/code&amp;gt;&lt;br /&gt;
| Позволяет включить службу в обычный многопользовательский режим загрузки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка и запуск ===&lt;br /&gt;
&lt;br /&gt;
Проверить юнит:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если обнаружены ошибки в созданном файле — исправить их до запуска.&lt;br /&gt;
&lt;br /&gt;
Перечитать юниты, включить автозапуск и сразу запустить службу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемое состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 5. Просмотр журнала ===&lt;br /&gt;
&lt;br /&gt;
Последние 50 записей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение за новыми записями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u demo-service.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нажатие &amp;lt;code&amp;gt;Ctrl + C&amp;lt;/code&amp;gt; завершает просмотр журнала, но не останавливает службу.&lt;br /&gt;
&lt;br /&gt;
=== Основные команды управления ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Команда !! Действие&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl start demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl stop demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Остановить. Настройка Restart не отменяет ручную остановку.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перезапустить.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Посмотреть состояние.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl enable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Включить автозапуск, не запуская службу немедленно.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск, не останавливая текущий процесс.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl disable --now demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Отключить автозапуск и остановить службу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl cat demo-service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Показать юнит и дополнительные настройки.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Как адаптировать под свою программу ===&lt;br /&gt;
&lt;br /&gt;
Заменить имя службы, пользователя, рабочий каталог и команду запуска.&lt;br /&gt;
&lt;br /&gt;
Например, для Python-приложения с виртуальным окружением:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
WorkingDirectory=/opt/my-app&lt;br /&gt;
ExecStart=/opt/my-app/.venv/bin/python -u /opt/my-app/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Виртуальное окружение и файл программы должны существовать. Активировать окружение командой &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; не требуется.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;-u&amp;lt;/code&amp;gt; отключает буферизацию стандартных потоков Python, чтобы сообщения быстрее попадали в журнал.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Особенности:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Программа должна работать на переднем плане: не добавляйте &amp;lt;code&amp;gt;&amp;amp;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;nohup&amp;lt;/code&amp;gt; или собственный переход в фон.&lt;br /&gt;
* &amp;lt;code&amp;gt;ExecStart&amp;lt;/code&amp;gt; не является обычной командной строкой оболочки: конструкции &amp;lt;code&amp;gt;|&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;&amp;amp;amp;&amp;amp;amp;&amp;lt;/code&amp;gt; не выполняются как в Bash.&lt;br /&gt;
* Сложную последовательность команд удобнее оформить отдельным скриптом.&lt;br /&gt;
* Пользователю службы нужны права чтения программы и записи только в необходимые каталоги данных.&lt;br /&gt;
* Переменные из интерактивного SSH-сеанса автоматически в службу не передаются.&lt;br /&gt;
&lt;br /&gt;
Для программы, которой при запуске нужна настроенная сеть, в секцию &amp;lt;code&amp;gt;[Unit]&amp;lt;/code&amp;gt; можно добавить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
After=network-online.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это не гарантирует доступность Интернета или внешнего API. Приложение должно самостоятельно повторять неудачные подключения.&lt;br /&gt;
&lt;br /&gt;
=== Применение изменений ===&lt;br /&gt;
&lt;br /&gt;
После изменения юнита:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemd-analyze verify /etc/systemd/system/demo-service.service&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart demo-service.service&lt;br /&gt;
systemctl status demo-service.service --no-pager -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если изменён только код программы, обычно достаточно перезапуска службы.&lt;br /&gt;
&lt;br /&gt;
Если сработало ограничение частых запусков, сначала исправить причину по журналу, затем выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reset-failed demo-service.service&lt;br /&gt;
systemctl start demo-service.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Отключение парольного входа по SSH ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Разрешить новые SSH-подключения только по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
Имя пользователя по-прежнему указывается, например &amp;lt;code&amp;gt;root@192.168.2.2&amp;lt;/code&amp;gt;. Меняется способ подтверждения доступа.&lt;br /&gt;
&lt;br /&gt;
Настройка не удаляет системные пароли и не меняет правила входа через локальную консоль или использования sudo.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Пример предназначен для Debian и Ubuntu с OpenSSH. Команды сервера выполняются от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 1. Проверка входа по ключу ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не закрывайте текущий сеанс до завершения всех проверок.&#039;&#039;&#039; Держите доступной консоль Proxmox или другую независимую консоль сервера.&lt;br /&gt;
&lt;br /&gt;
В новом терминале Mac проверить вход с запретом перехода к парольной авторизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PreferredAuthentications=publickey \&lt;br /&gt;
  -o PasswordAuthentication=no \&lt;br /&gt;
  -o KbdInteractiveAuthentication=no \&lt;br /&gt;
  -o IdentitiesOnly=yes \&lt;br /&gt;
  -i ~/.ssh/id_ed25519 \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если вход не работает, сначала исправить авторизацию по ключу.&lt;br /&gt;
&lt;br /&gt;
Если сервером пользуются несколько администраторов, заранее настроить ключи для каждого.&lt;br /&gt;
&lt;br /&gt;
=== 2. Резервная копия конфигурации ===&lt;br /&gt;
&lt;br /&gt;
На сервере выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config \&lt;br /&gt;
  &amp;quot;/etc/ssh/sshd_config.backup-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Изменение настроек ===&lt;br /&gt;
&lt;br /&gt;
Открыть:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить в самое начало файла, перед директивами &amp;lt;code&amp;gt;Include&amp;lt;/code&amp;gt; и блоками &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
PubkeyAuthentication yes&lt;br /&gt;
PasswordAuthentication no&lt;br /&gt;
KbdInteractiveAuthentication no&lt;br /&gt;
AuthenticationMethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PubkeyAuthentication yes&amp;lt;/code&amp;gt;&lt;br /&gt;
| Разрешить авторизацию по публичному ключу.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PasswordAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить обычную парольную авторизацию.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;KbdInteractiveAuthentication no&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запретить интерактивную авторизацию, которая также может запрашивать пароль или одноразовый код.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AuthenticationMethods publickey&amp;lt;/code&amp;gt;&lt;br /&gt;
| Оставить только авторизацию по публичному ключу.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот вариант также исключает другие способы входа и схемы «ключ плюс одноразовый код».&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для большинства параметров OpenSSH используется первое полученное значение. Блоки &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; могут задавать отдельные правила для пользователей и адресов, поэтому нужна проверка итоговой конфигурации.&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;PermitRootLogin&amp;lt;/code&amp;gt; без необходимости не менять. Значение &amp;lt;code&amp;gt;no&amp;lt;/code&amp;gt; запрещает root любой SSH-вход; &amp;lt;code&amp;gt;prohibit-password&amp;lt;/code&amp;gt; допускает вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
=== 4. Проверка перед применением ===&lt;br /&gt;
&lt;br /&gt;
Проверить синтаксис:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Отсутствие вывода при успешном завершении означает, что проверка пройдена. При ошибке конфигурацию не применять.&lt;br /&gt;
&lt;br /&gt;
Посмотреть общие итоговые параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
pubkeyauthentication yes&lt;br /&gt;
passwordauthentication no&lt;br /&gt;
kbdinteractiveauthentication no&lt;br /&gt;
authenticationmethods publickey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При наличии &amp;lt;code&amp;gt;Match&amp;lt;/code&amp;gt; дополнительно проверить конкретное подключение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -T \&lt;br /&gt;
  -C user=root,addr=192.168.2.50,host=mac-client,laddr=192.168.2.2,lport=22 \&lt;br /&gt;
  | grep -E &#039;^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|permitrootlogin) &#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В примере:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;user&amp;lt;/code&amp;gt; — пользователь сервера.&lt;br /&gt;
* &amp;lt;code&amp;gt;addr&amp;lt;/code&amp;gt; — адрес клиента, видимый серверу.&lt;br /&gt;
* &amp;lt;code&amp;gt;host&amp;lt;/code&amp;gt; — имя клиента для правил Match Host.&lt;br /&gt;
* &amp;lt;code&amp;gt;laddr&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;lport&amp;lt;/code&amp;gt; — адрес и порт сервера.&lt;br /&gt;
&lt;br /&gt;
Подставить реальные параметры подключения. Проверить также другие учётные записи и адреса, для которых настроены отдельные правила.&lt;br /&gt;
&lt;br /&gt;
Если значения отличаются от ожидаемых, найти и исправить соответствующие настройки в основном файле, подключаемых файлах или блоках Match.&lt;br /&gt;
&lt;br /&gt;
=== 5. Применение ===&lt;br /&gt;
&lt;br /&gt;
Для стандартной службы SSH в Debian и Ubuntu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В системах, где служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload sshd.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выполняется только вариант с фактическим именем службы.&lt;br /&gt;
&lt;br /&gt;
Перечитывание конфигурации штатно сохраняет открытые сеансы.&lt;br /&gt;
&lt;br /&gt;
=== 6. Проверка нового подключения ===&lt;br /&gt;
&lt;br /&gt;
Не закрывая старый сеанс, в новом терминале Mac повторить команду проверки входа по ключу из первого шага.&lt;br /&gt;
&lt;br /&gt;
Затем проверить отказ для парольных способов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh \&lt;br /&gt;
  -o ControlMaster=no \&lt;br /&gt;
  -o ControlPath=none \&lt;br /&gt;
  -o PubkeyAuthentication=no \&lt;br /&gt;
  -o PreferredAuthentications=password,keyboard-interactive \&lt;br /&gt;
  root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат — отказ, обычно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Permission denied (publickey).&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пароль учётной записи запрашиваться не должен.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Старый сеанс можно закрыть после успешного нового входа по ключу и проверки отказа для пароля.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Восстановление при ошибке ===&lt;br /&gt;
&lt;br /&gt;
Использовать оставленный открытым сеанс или консоль Proxmox.&lt;br /&gt;
&lt;br /&gt;
Найти резервную копию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lt /etc/ssh/sshd_config.backup-*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Восстановить нужную копию, указав её фактическое имя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cp -a /etc/ssh/sshd_config.backup-YYYYMMDD-HHMMSS /etc/ssh/sshd_config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверить и применить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/usr/sbin/sshd -t &amp;amp;&amp;amp; systemctl reload ssh.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если служба называется &amp;lt;code&amp;gt;sshd.service&amp;lt;/code&amp;gt;, заменить её имя в команде.&lt;br /&gt;
&lt;br /&gt;
=== Важно помнить ===&lt;br /&gt;
&lt;br /&gt;
* Парольная фраза приватного ключа на Mac может запрашиваться и после отключения паролей на сервере — это отдельная защита самого ключа.&lt;br /&gt;
* Настройка распространяется также на SFTP и SCP через этот SSH-сервер.&lt;br /&gt;
* Не удаляйте пароль пользователя и не блокируйте учётную запись ради отключения парольного SSH-входа: достаточно настроек SSH.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=161</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=161"/>
		<updated>2026-09-28T18:20:14Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Небольшие инструкции, полезные команды и практические приёмы администрирования Linux.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все IP-адреса, имена и идентификаторы приведены для примера. Заменяйте их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу ==&lt;br /&gt;
&lt;br /&gt;
=== Назначение ===&lt;br /&gt;
&lt;br /&gt;
Подключение с Mac к LXC-контейнеру по SSH без ввода пароля root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox. Знать или создавать пароль root контейнера для этого не требуется.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение для примера&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Что необходимо ===&lt;br /&gt;
&lt;br /&gt;
* Административный доступ к консоли узла Proxmox.&lt;br /&gt;
* Запущенный LXC-контейнер с работающим SSH-сервером.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — через локальную сеть или VPN.&lt;br /&gt;
* Разрешённый на SSH-сервере вход root по публичному ключу.&lt;br /&gt;
&lt;br /&gt;
=== 1. Создание ключа на Mac ===&lt;br /&gt;
&lt;br /&gt;
Открыть &#039;&#039;&#039;Терминал на Mac&#039;&#039;&#039; и выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
При создании нового ключа появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac. Его нельзя публиковать или передавать.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт ключ без парольной фразы. Получивший приватный ключ сможет использовать его для подключения к серверам, где разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Парольную фразу такого ключа можно сохранить в связке ключей macOS — порядок приведён ниже.&lt;br /&gt;
&lt;br /&gt;
=== 2. Копирование публичного ключа ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю выведенную строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Нужен именно публичный ключ:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Копировать строку целиком, без добавления переносов.&lt;br /&gt;
* Не копировать отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Не копировать графический рисунок ключа.&lt;br /&gt;
* Не передавать содержимое приватного файла &amp;lt;code&amp;gt;id_ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, но файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, восстановить публичный ключ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 3. Вход в контейнер через Proxmox ===&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox открыть &#039;&#039;&#039;Shell узла, на котором запущен контейнер&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующие команды выполняются &#039;&#039;&#039;внутри контейнера от имени root&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=== 4. Добавление ключа в контейнер ===&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог и файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
touch /root/.ssh/authorized_keys&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; скопированной строкой с Mac, сохранив одинарные кавычки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;\n%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет запись в конец файла и сохраняет ранее добавленные ключи.&lt;br /&gt;
&lt;br /&gt;
Начальный перенос строки не позволяет новому ключу склеиться с предыдущей записью. Пустые строки в файле допустимы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== 5. Проверка подлинности сервера ===&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение ключа сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с тем, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сравнивать нужно ключи одного типа&#039;&#039;&#039;: в этом примере ED25519.&lt;br /&gt;
&lt;br /&gt;
=== 6. Подключение с Mac ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заменить адрес на IP своего контейнера.&lt;br /&gt;
&lt;br /&gt;
Если появился запрос подтверждения ключа сервера и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения подключения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 7. Сохранение парольной фразы ключа в macOS ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот шаг нужен только для ключа, защищённого парольной фразой.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; относится к приватному ключу на Mac, а не к паролю root контейнера.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для автоматического использования связки ключей добавить настройки из следующего раздела.&lt;br /&gt;
&lt;br /&gt;
=== 8. Короткая команда подключения ===&lt;br /&gt;
&lt;br /&gt;
Можно назначить подключению понятное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек SSH:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить блок, заменив адрес на нужный:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если блок &amp;lt;code&amp;gt;Host my-container&amp;lt;/code&amp;gt; уже существует, изменить его вместо создания дубликата. Если в файле есть общий блок &amp;lt;code&amp;gt;Host *&amp;lt;/code&amp;gt;, этот отдельный блок разместить перед ним.&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключение выполняется короткой командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Диагностика ===&lt;br /&gt;
&lt;br /&gt;
==== Запрашивается пароль root ====&lt;br /&gt;
&lt;br /&gt;
Авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac выполнить подключение с явным указанием ключа и подробным выводом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внутри контейнера через консоль Proxmox проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;700&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;600&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt;&lt;br /&gt;
| root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Проверить, что:&lt;br /&gt;
&lt;br /&gt;
* В файле находится публичный ключ с нужного Mac.&lt;br /&gt;
* Ключ записан одной строкой.&lt;br /&gt;
* Указаны правильные IP-адрес и пользователь.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
==== Connection refused ====&lt;br /&gt;
&lt;br /&gt;
Соединение отклонено.&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт подключения. Также причиной может быть правило межсетевого экрана, отклоняющее соединение.&lt;br /&gt;
&lt;br /&gt;
==== Connection timed out ====&lt;br /&gt;
&lt;br /&gt;
Сервер не ответил за отведённое время.&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его сеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
==== REMOTE HOST IDENTIFICATION HAS CHANGED ====&lt;br /&gt;
&lt;br /&gt;
Сохранённый на Mac ключ сервера отличается от текущего.&lt;br /&gt;
&lt;br /&gt;
Причиной может быть переустановка контейнера, замена ключей SSH или появление другого устройства по тому же адресу.&lt;br /&gt;
&lt;br /&gt;
Сначала проверить новый отпечаток через доверенную консоль Proxmox. Не удалять старую запись без проверки причины изменения.&lt;br /&gt;
&lt;br /&gt;
=== Примечания ===&lt;br /&gt;
&lt;br /&gt;
* Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
* Для каждого дополнительного компьютера можно создать собственный ключ и добавить его публичную часть отдельной строкой в &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Чтобы отозвать доступ конкретного ключа, удалить соответствующую строку из &amp;lt;code&amp;gt;authorized_keys&amp;lt;/code&amp;gt;. Уже открытые SSH-сеансы при этом не завершаются.&lt;br /&gt;
* Добавление ключа само по себе не отключает парольную авторизацию SSH.&lt;br /&gt;
* Приватные ключи, пароли и другие секреты не должны попадать в публичную документацию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- Следующую хитрость добавляйте ниже отдельным разделом:&lt;br /&gt;
== Название хитрости ==&lt;br /&gt;
Описание и команды.&lt;br /&gt;
--&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=160</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=160"/>
		<updated>2026-09-28T18:18:59Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;📚 База знаний&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Документация по инфраструктуре, Linux и игровым серверам.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-grid&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🖥️ Инфраструктура ===&lt;br /&gt;
&#039;&#039;Серверы и виртуализация&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Proxmox]]&lt;br /&gt;
* [[PBS]]&lt;br /&gt;
* [[iLO]]&lt;br /&gt;
* [[BrainyCP]]&lt;br /&gt;
* [[Сетевое оборудование]]&lt;br /&gt;
* [[RAMBA Matrix]]&lt;br /&gt;
* [[RAMBA AI Router]]&lt;br /&gt;
* [[Happ-gateway|HAPP Gateway]]&lt;br /&gt;
* [[Kuzya2-0|Телеграм бот Кузя 2.0]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🐧 Linux ===&lt;br /&gt;
&#039;&#039;Системное администрирование&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntu]]&lt;br /&gt;
* [[Debian]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Bash]]&lt;br /&gt;
* [[Sis admin linux|Хитрости администрирования Linux]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🎮 Игровые серверы ===&lt;br /&gt;
&#039;&#039;Игровая инфраструктура&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Rust]]&lt;br /&gt;
* [[LGSM]]&lt;br /&gt;
* [[SteamCMD]]&lt;br /&gt;
* [[Резервное копирование]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ⭐ Избранные статьи ==&lt;br /&gt;
&lt;br /&gt;
* [[Установка Proxmox VE]]&lt;br /&gt;
* [[Настройка Proxmox Backup Server]]&lt;br /&gt;
* [[Настройка BrainyCP]]&lt;br /&gt;
* [[Создание LXC-контейнеров]]&lt;br /&gt;
* [[Настройка Rust-сервера через LGSM]]&lt;br /&gt;
* [[Minecraft_в_2026_году]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🕒 Последние изменения ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:RecentChanges|Посмотреть все последние изменения]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🔗 Полезные ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:AllPages|Все статьи]]&lt;br /&gt;
* [[Special:Categories|Все категории]]&lt;br /&gt;
* [[Special:WantedPages|Нужные страницы]]&lt;br /&gt;
* [[Special:Random|🎲 Случайная статья]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=159</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=159"/>
		<updated>2026-09-28T18:17:16Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;📚 База знаний&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Документация по инфраструктуре, Linux и игровым серверам.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-grid&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🖥️ Инфраструктура ===&lt;br /&gt;
&#039;&#039;Серверы и виртуализация&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Proxmox]]&lt;br /&gt;
* [[PBS]]&lt;br /&gt;
* [[iLO]]&lt;br /&gt;
* [[BrainyCP]]&lt;br /&gt;
* [[Сетевое оборудование]]&lt;br /&gt;
* [[RAMBA Matrix]]&lt;br /&gt;
* [[RAMBA AI Router]]&lt;br /&gt;
* [[Happ-gateway|HAPP Gateway]]&lt;br /&gt;
* [[Kuzya2-0|Телеграм бот Кузя 2.0]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🐧 Linux ===&lt;br /&gt;
&#039;&#039;Системное администрирование&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntu]]&lt;br /&gt;
* [[Debian]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Bash]]&lt;br /&gt;
* [[Sis admin linux|SSH-доступ с Mac по ключу]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🎮 Игровые серверы ===&lt;br /&gt;
&#039;&#039;Игровая инфраструктура&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Rust]]&lt;br /&gt;
* [[LGSM]]&lt;br /&gt;
* [[SteamCMD]]&lt;br /&gt;
* [[Резервное копирование]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ⭐ Избранные статьи ==&lt;br /&gt;
&lt;br /&gt;
* [[Установка Proxmox VE]]&lt;br /&gt;
* [[Настройка Proxmox Backup Server]]&lt;br /&gt;
* [[Настройка BrainyCP]]&lt;br /&gt;
* [[Создание LXC-контейнеров]]&lt;br /&gt;
* [[Настройка Rust-сервера через LGSM]]&lt;br /&gt;
* [[Minecraft_в_2026_году]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🕒 Последние изменения ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:RecentChanges|Посмотреть все последние изменения]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🔗 Полезные ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:AllPages|Все статьи]]&lt;br /&gt;
* [[Special:Categories|Все категории]]&lt;br /&gt;
* [[Special:WantedPages|Нужные страницы]]&lt;br /&gt;
* [[Special:Random|🎲 Случайная статья]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=158</id>
		<title>Sis admin linux</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Sis_admin_linux&amp;diff=158"/>
		<updated>2026-09-28T18:16:09Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «= SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу =  == Назначение ==  Инструкция позволяет настроить подключение с Mac к LXC-контейнеру Proxmox по SSH без ввода пароля пользователя root.  Публичный ключ добавляется через консоль Proxmox, поэтому знать или создавать пароль roo...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу =&lt;br /&gt;
&lt;br /&gt;
== Назначение ==&lt;br /&gt;
&lt;br /&gt;
Инструкция позволяет настроить подключение с Mac к LXC-контейнеру Proxmox по SSH без ввода пароля пользователя root.&lt;br /&gt;
&lt;br /&gt;
Публичный ключ добавляется через консоль Proxmox, поэтому знать или создавать пароль root контейнера для этой настройки не требуется.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все адреса и идентификаторы приведены для примера. Замените их значениями своей инфраструктуры.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Пример&lt;br /&gt;
|-&lt;br /&gt;
| ID контейнера || 123&lt;br /&gt;
|-&lt;br /&gt;
| IP-адрес контейнера || 192.168.2.2&lt;br /&gt;
|-&lt;br /&gt;
| Пользователь SSH || root&lt;br /&gt;
|-&lt;br /&gt;
| Клиент || Mac с macOS&lt;br /&gt;
|-&lt;br /&gt;
| Тип ключа || Ed25519&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Перед началом ==&lt;br /&gt;
&lt;br /&gt;
Для выполнения инструкции необходимы:&lt;br /&gt;
&lt;br /&gt;
* Доступ к терминалу macOS.&lt;br /&gt;
* Административный доступ к консоли узла Proxmox, на котором запущен контейнер.&lt;br /&gt;
* Установленный и работающий SSH-сервер внутри контейнера.&lt;br /&gt;
* Сетевая доступность контейнера с Mac — напрямую через локальную сеть либо через VPN.&lt;br /&gt;
&lt;br /&gt;
SSH-сервер контейнера должен разрешать авторизацию по публичному ключу и вход root по ключу.&lt;br /&gt;
&lt;br /&gt;
== 1. Создание SSH-ключа на Mac ==&lt;br /&gt;
&lt;br /&gt;
Открыть приложение &#039;&#039;&#039;Терминал&#039;&#039;&#039; на Mac.&lt;br /&gt;
&lt;br /&gt;
Выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
if [ ! -f ~/.ssh/id_ed25519 ]; then&lt;br /&gt;
  ssh-keygen -t ed25519 -N &amp;quot;&amp;quot; -f ~/.ssh/id_ed25519&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;SSH-ключ уже существует.&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда создаёт новый ключ только при отсутствии файла &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;. Существующий ключ не перезаписывается.&lt;br /&gt;
&lt;br /&gt;
После создания появляются два файла:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519&amp;lt;/code&amp;gt;&lt;br /&gt;
| Приватный ключ. Остаётся на Mac и не передаётся другим пользователям.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;~/.ssh/id_ed25519.pub&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публичный ключ. Добавляется на сервер, к которому требуется доступ.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; параметр &amp;lt;code&amp;gt;-N &amp;quot;&amp;quot;&amp;lt;/code&amp;gt; создаёт новый ключ без парольной фразы. Получивший этот приватный ключ сможет использовать его для доступа к серверам, на которых разрешён соответствующий публичный ключ.&lt;br /&gt;
&lt;br /&gt;
Если нужна защита ключа парольной фразой, при отсутствии ключа вместо команды выше используйте:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 2. Получение публичного ключа ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Скопировать всю строку, начинающуюся с &amp;lt;code&amp;gt;ssh-ed25519&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Ключ нужно копировать целиком, одной строкой.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Не следует копировать:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Приватный ключ из файла без расширения &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Отпечаток вида &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt;.&lt;br /&gt;
* Графический рисунок, показанный при создании ключа.&lt;br /&gt;
&lt;br /&gt;
Если приватный ключ существует, а соответствующий файл &amp;lt;code&amp;gt;.pub&amp;lt;/code&amp;gt; отсутствует, публичный ключ можно восстановить на Mac:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -y -f ~/.ssh/id_ed25519 &amp;gt; ~/.ssh/id_ed25519.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 3. Вход в контейнер через Proxmox ==&lt;br /&gt;
&lt;br /&gt;
В веб-интерфейсе Proxmox выбрать &#039;&#039;&#039;узел, на котором запущен контейнер&#039;&#039;&#039;, и открыть его &#039;&#039;&#039;Shell&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Выполнить, заменив &amp;lt;code&amp;gt;123&amp;lt;/code&amp;gt; фактическим ID контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct enter 123&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После выполнения команды откроется оболочка контейнера.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Все команды следующего раздела выполняются внутри контейнера от имени root.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== 4. Добавление публичного ключа ==&lt;br /&gt;
&lt;br /&gt;
Подготовить каталог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /root/.ssh&lt;br /&gt;
chmod 700 /root/.ssh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В следующей команде заменить &amp;lt;code&amp;gt;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&amp;lt;/code&amp;gt; полной строкой публичного ключа с Mac. Одинарные кавычки сохранить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
printf &#039;%s\n&#039; &#039;ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ&#039; &amp;gt;&amp;gt; /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Установить владельца и права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown root:root /root/.ssh /root/.ssh/authorized_keys&lt;br /&gt;
chmod 600 /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Оператор &amp;lt;code&amp;gt;&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt; добавляет ключ в конец файла, сохраняя существующие записи.&lt;br /&gt;
&lt;br /&gt;
Каждый публичный ключ должен занимать отдельную строку. Если файл редактировался вручную, убедитесь, что новый ключ не склеился с предыдущим.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Перезапуск SSH-сервера после добавления ключа не требуется.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== 5. Проверка ключа сервера ==&lt;br /&gt;
&lt;br /&gt;
При первом подключении Mac может запросить подтверждение подлинности сервера.&lt;br /&gt;
&lt;br /&gt;
Чтобы проверить отпечаток ключа ED25519, выполнить &#039;&#039;&#039;внутри контейнера через консоль Proxmox&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сравнить полученный отпечаток &amp;lt;code&amp;gt;SHA256:...&amp;lt;/code&amp;gt; с отпечатком, который покажет Mac при подключении.&lt;br /&gt;
&lt;br /&gt;
Сравнивать нужно ключи одного типа: в данном случае ED25519.&lt;br /&gt;
&lt;br /&gt;
== 6. Подключение с Mac ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;В Терминале на Mac&#039;&#039;&#039; выполнить, подставив адрес своего контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если при первом подключении появился запрос доверия к серверу и отпечаток совпадает с проверенным, ввести:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной настройке откроется оболочка контейнера без запроса пароля root.&lt;br /&gt;
&lt;br /&gt;
Для завершения сеанса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Если ключ защищён парольной фразой ==&lt;br /&gt;
&lt;br /&gt;
Запрос &amp;lt;code&amp;gt;Enter passphrase for key&amp;lt;/code&amp;gt; означает, что macOS просит парольную фразу приватного ключа, а не пароль root контейнера.&lt;br /&gt;
&lt;br /&gt;
Чтобы добавить ключ в SSH-агент и сохранить парольную фразу в связке ключей macOS, выполнить &#039;&#039;&#039;на Mac&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh-add --apple-use-keychain ~/.ssh/id_ed25519&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ввести парольную фразу ключа.&lt;br /&gt;
&lt;br /&gt;
Для её дальнейшего использования можно добавить параметры в файл &amp;lt;code&amp;gt;~/.ssh/config&amp;lt;/code&amp;gt;, как показано в следующем разделе.&lt;br /&gt;
&lt;br /&gt;
== Короткая команда подключения ==&lt;br /&gt;
&lt;br /&gt;
Вместо IP-адреса можно использовать удобное имя, например &amp;lt;code&amp;gt;my-container&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;На Mac&#039;&#039;&#039; открыть файл настроек:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/.ssh&lt;br /&gt;
chmod 700 ~/.ssh&lt;br /&gt;
nano ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавить отдельный блок. Если блок с таким именем уже есть, изменить его вместо создания дубликата:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host my-container&lt;br /&gt;
    HostName 192.168.2.2&lt;br /&gt;
    User root&lt;br /&gt;
    IdentityFile ~/.ssh/id_ed25519&lt;br /&gt;
    IdentitiesOnly yes&lt;br /&gt;
    AddKeysToAgent yes&lt;br /&gt;
    UseKeychain yes&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохранить файл в nano:&lt;br /&gt;
&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + O&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Enter&amp;lt;/code&amp;gt;.&lt;br /&gt;
# Нажать &amp;lt;code&amp;gt;Control + X&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Установить права:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod 600 ~/.ssh/config&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь подключаться можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh my-container&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Диагностика ==&lt;br /&gt;
&lt;br /&gt;
=== Сервер запрашивает пароль root ===&lt;br /&gt;
&lt;br /&gt;
Это означает, что авторизация по ключу не завершилась успешно.&lt;br /&gt;
&lt;br /&gt;
На Mac явно указать нужный ключ и включить подробный вывод:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ssh -v -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 root@192.168.2.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Через консоль Proxmox проверить внутри контейнера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -ld /root/.ssh&lt;br /&gt;
ls -l /root/.ssh/authorized_keys&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемые параметры:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Объект !! Права !! Владелец&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh&amp;lt;/code&amp;gt; || 700 — &amp;lt;code&amp;gt;drwx------&amp;lt;/code&amp;gt; || root&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt; || 600 — &amp;lt;code&amp;gt;-rw-------&amp;lt;/code&amp;gt; || root&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Также проверить:&lt;br /&gt;
&lt;br /&gt;
* В файле записан публичный ключ именно с нужного Mac.&lt;br /&gt;
* Ключ не разбит на несколько строк.&lt;br /&gt;
* Подключение выполняется к правильному IP-адресу и пользователю.&lt;br /&gt;
* SSH-сервер разрешает авторизацию по ключу.&lt;br /&gt;
* Вход root по ключу не запрещён настройками SSH.&lt;br /&gt;
&lt;br /&gt;
=== Соединение отклонено: Connection refused ===&lt;br /&gt;
&lt;br /&gt;
Проверить правильность адреса, работу SSH-сервера и порт, на котором он принимает подключения.&lt;br /&gt;
&lt;br /&gt;
=== Сервер не отвечает: Connection timed out ===&lt;br /&gt;
&lt;br /&gt;
Проверить:&lt;br /&gt;
&lt;br /&gt;
* Запущен ли контейнер.&lt;br /&gt;
* Доступна ли его подсеть с Mac.&lt;br /&gt;
* Подключён ли нужный VPN.&lt;br /&gt;
* Не блокируется ли SSH-порт межсетевым экраном.&lt;br /&gt;
&lt;br /&gt;
=== Изменился ключ сервера ===&lt;br /&gt;
&lt;br /&gt;
При предупреждении &amp;lt;code&amp;gt;REMOTE HOST IDENTIFICATION HAS CHANGED&amp;lt;/code&amp;gt; сначала проверить причину изменения и новый отпечаток через доверенную консоль Proxmox.&lt;br /&gt;
&lt;br /&gt;
Не удалять сохранённый ключ сервера без проверки: предупреждение может означать как переустановку контейнера, так и подключение к другому устройству.&lt;br /&gt;
&lt;br /&gt;
== Итог ==&lt;br /&gt;
&lt;br /&gt;
После настройки Mac использует приватный ключ для подтверждения доступа, а контейнер проверяет его по публичному ключу из &amp;lt;code&amp;gt;/root/.ssh/authorized_keys&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Настройка сохраняется после перезагрузки Mac и контейнера.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Добавление ключа само по себе не отключает парольную авторизацию SSH.&#039;&#039;&#039; Настройки разрешённых способов входа управляются отдельно.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=157</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=157"/>
		<updated>2026-09-28T18:16:04Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;📚 База знаний&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Документация по инфраструктуре, Linux и игровым серверам.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-grid&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🖥️ Инфраструктура ===&lt;br /&gt;
&#039;&#039;Серверы и виртуализация&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Proxmox]]&lt;br /&gt;
* [[PBS]]&lt;br /&gt;
* [[iLO]]&lt;br /&gt;
* [[BrainyCP]]&lt;br /&gt;
* [[Сетевое оборудование]]&lt;br /&gt;
* [[RAMBA Matrix]]&lt;br /&gt;
* [[RAMBA AI Router]]&lt;br /&gt;
* [[Happ-gateway|HAPP Gateway]]&lt;br /&gt;
* [[Kuzya2-0|Телеграм бот Кузя 2.0]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🐧 Linux ===&lt;br /&gt;
&#039;&#039;Системное администрирование&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntu]]&lt;br /&gt;
* [[Debian]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Bash]]&lt;br /&gt;
* [[SSH-доступ с macOS к LXC-контейнеру Proxmox по ключу|SSH с Mac по ключу]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== 🎮 Игровые серверы ===&lt;br /&gt;
&#039;&#039;Игровая инфраструктура&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Rust]]&lt;br /&gt;
* [[LGSM]]&lt;br /&gt;
* [[SteamCMD]]&lt;br /&gt;
* [[Резервное копирование]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ⭐ Избранные статьи ==&lt;br /&gt;
&lt;br /&gt;
* [[Установка Proxmox VE]]&lt;br /&gt;
* [[Настройка Proxmox Backup Server]]&lt;br /&gt;
* [[Настройка BrainyCP]]&lt;br /&gt;
* [[Создание LXC-контейнеров]]&lt;br /&gt;
* [[Настройка Rust-сервера через LGSM]]&lt;br /&gt;
* [[Minecraft_в_2026_году]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🕒 Последние изменения ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:RecentChanges|Посмотреть все последние изменения]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🔗 Полезные ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:AllPages|Все статьи]]&lt;br /&gt;
* [[Special:Categories|Все категории]]&lt;br /&gt;
* [[Special:WantedPages|Нужные страницы]]&lt;br /&gt;
* [[Special:Random|🎲 Случайная статья]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Kuzya2-0&amp;diff=156</id>
		<title>Kuzya2-0</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Kuzya2-0&amp;diff=156"/>
		<updated>2026-09-26T06:24:29Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Кузя — интеллектуальный администратор Telegram-сообщества =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Кузя&#039;&#039;&#039; — Telegram-бот для администрирования и сопровождения сообщества. Проект развивается от классического административного бота к интеллектуальному помощнику и AI-модератору, способному анализировать происходящее в чате, помогать участникам и администраторам и самостоятельно выявлять нарушения.&lt;br /&gt;
&lt;br /&gt;
Основная задача проекта — не заменить живых администраторов, а снять с них значительную часть рутинной работы и предоставить дополнительные инструменты для управления сообществом.&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние проекта ==&lt;br /&gt;
&lt;br /&gt;
Кузя уже является рабочим Telegram-ботом и используется для выполнения административных и информационных задач.&lt;br /&gt;
&lt;br /&gt;
На данный момент реализованы следующие возможности:&lt;br /&gt;
&lt;br /&gt;
* выдача мута;&lt;br /&gt;
* снятие мута;&lt;br /&gt;
* временный и постоянный бан;&lt;br /&gt;
* система предупреждений;&lt;br /&gt;
* указание причины нарушения;&lt;br /&gt;
* хранение истории предупреждений;&lt;br /&gt;
* отдельный список администраторов Кузи;&lt;br /&gt;
* приветствие новых участников;&lt;br /&gt;
* публикация информационных сообщений;&lt;br /&gt;
* вывод правил сообщества;&lt;br /&gt;
* публикация ссылок;&lt;br /&gt;
* приглашения;&lt;br /&gt;
* информация о поддержке проекта;&lt;br /&gt;
* взаимодействие с публикациями Telegram-канала;&lt;br /&gt;
* автоматическая публикация информационного сообщения под новым видео;&lt;br /&gt;
* хранение истории сообщений Telegram-чата;&lt;br /&gt;
* изменение ряда настроек и текстов через команды администратора;&lt;br /&gt;
* базовые функции AI-ассистента.&lt;br /&gt;
&lt;br /&gt;
== База данных сообщества ==&lt;br /&gt;
&lt;br /&gt;
Кузя работает с MySQL и ведёт собственную историю чата.&lt;br /&gt;
&lt;br /&gt;
На август 2026 года в базе сохранено около:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;497 000 сообщений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для сообщений сохраняются, в частности:&lt;br /&gt;
&lt;br /&gt;
* дата и время;&lt;br /&gt;
* Telegram ID пользователя;&lt;br /&gt;
* username;&lt;br /&gt;
* отображаемое имя;&lt;br /&gt;
* текст сообщения;&lt;br /&gt;
* Telegram message ID.&lt;br /&gt;
&lt;br /&gt;
Отдельно существует база предупреждений.&lt;br /&gt;
&lt;br /&gt;
В ней сохраняются:&lt;br /&gt;
&lt;br /&gt;
* пользователь;&lt;br /&gt;
* сообщение, за которое выдано предупреждение;&lt;br /&gt;
* причина;&lt;br /&gt;
* номер предупреждения;&lt;br /&gt;
* администратор, принявший решение;&lt;br /&gt;
* дата и время.&lt;br /&gt;
&lt;br /&gt;
Большинство предупреждений связано с исходным сообщением через &#039;&#039;&#039;message_id&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, за время существования Кузи администраторами фактически был создан первоначальный набор вручную размеченных примеров нарушений.&lt;br /&gt;
&lt;br /&gt;
Эти данные в дальнейшем могут использоваться для разработки интеллектуальной системы модерации.&lt;br /&gt;
&lt;br /&gt;
== Концепция дальнейшего развития ==&lt;br /&gt;
&lt;br /&gt;
В перспективе Кузя должен состоять из трёх основных подсистем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    КУЗЯ&lt;br /&gt;
                      |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
        |             |             |&lt;br /&gt;
        v             v             v&lt;br /&gt;
 Telegram Admin   AI Assistant    Guardian&lt;br /&gt;
        |             |             |&lt;br /&gt;
   mute / ban       диалог       модерация&lt;br /&gt;
   warnings         память       антиспам&lt;br /&gt;
   rules            поиск       конфликты&lt;br /&gt;
   channel           RAG         репутация&lt;br /&gt;
        |             |             |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
                      |&lt;br /&gt;
                      v&lt;br /&gt;
                  RAMBA AI&lt;br /&gt;
              Local AI Router&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Локальный искусственный интеллект ==&lt;br /&gt;
&lt;br /&gt;
Основной AI Кузи планируется сделать &#039;&#039;&#039;локальным&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Для обработки запросов используется инфраструктура RAMBA AI с несколькими локальными нейронными моделями.&lt;br /&gt;
&lt;br /&gt;
Архитектура предусматривает три специализированные модели, работающие на локальном сервере с NVIDIA GeForce GTX 1080.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
  Кузя&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 1&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 2&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 3&lt;br /&gt;
    |&lt;br /&gt;
    +------ OpenAI API&lt;br /&gt;
            дополнительный уровень&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
AI Router определяет, какая модель лучше подходит для конкретной задачи.&lt;br /&gt;
&lt;br /&gt;
OpenAI API при этом не является основным интеллектом Кузи. Он рассматривается как дополнительный инструмент для отдельных сложных задач и сценариев, в которых возможностей локальных моделей недостаточно.&lt;br /&gt;
&lt;br /&gt;
Это также позволяет не передавать всю историю сообщества внешним AI-сервисам.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.0 — новая архитектура ==&lt;br /&gt;
&lt;br /&gt;
Первым этапом развития станет создание &#039;&#039;&#039;Kuzya 2.0&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Главный принцип:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сначала переносим все существующие возможности без потери функциональности, затем добавляем AI.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Текущая рабочая версия сохраняется как:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kuzya Legacy Stable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Новая версия разрабатывается отдельно.&lt;br /&gt;
&lt;br /&gt;
В Kuzya 2.0 существующий монолитный код планируется разделить на независимые компоненты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kuzya/&lt;br /&gt;
|&lt;br /&gt;
+-- bot/&lt;br /&gt;
|   +-- moderation/&lt;br /&gt;
|   +-- commands/&lt;br /&gt;
|   +-- channel/&lt;br /&gt;
|   +-- users/&lt;br /&gt;
|   +-- handlers/&lt;br /&gt;
|&lt;br /&gt;
+-- database/&lt;br /&gt;
|   +-- messages&lt;br /&gt;
|   +-- warnings&lt;br /&gt;
|   +-- admins&lt;br /&gt;
|   +-- settings&lt;br /&gt;
|&lt;br /&gt;
+-- ai/&lt;br /&gt;
|   +-- assistant&lt;br /&gt;
|   +-- moderation&lt;br /&gt;
|   +-- context&lt;br /&gt;
|   +-- memory&lt;br /&gt;
|&lt;br /&gt;
+-- services/&lt;br /&gt;
|&lt;br /&gt;
+-- config/&lt;br /&gt;
|&lt;br /&gt;
+-- main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволит развивать отдельные возможности Кузи независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.1 — развитие базы данных ==&lt;br /&gt;
&lt;br /&gt;
Существующая MySQL-база сохраняется.&lt;br /&gt;
&lt;br /&gt;
История почти из полумиллиона сообщений является ценным архивом и не должна изменяться или удаляться в процессе модернизации.&lt;br /&gt;
&lt;br /&gt;
Для новой версии предполагается постепенно перейти к единой структуре данных:&lt;br /&gt;
&lt;br /&gt;
* chats;&lt;br /&gt;
* users;&lt;br /&gt;
* messages;&lt;br /&gt;
* warnings;&lt;br /&gt;
* moderation_actions;&lt;br /&gt;
* admins;&lt;br /&gt;
* chat_settings.&lt;br /&gt;
&lt;br /&gt;
Каждое административное действие сможет дополнительно содержать источник решения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;human&#039;&#039;&#039; — решение администратора;&lt;br /&gt;
* &#039;&#039;&#039;ai&#039;&#039;&#039; — решение AI;&lt;br /&gt;
* &#039;&#039;&#039;rule&#039;&#039;&#039; — автоматическое правило.&lt;br /&gt;
&lt;br /&gt;
Это позволит впоследствии анализировать качество работы AI.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.2 — AI Router ==&lt;br /&gt;
&lt;br /&gt;
Кузя подключается к RAMBA AI Router.&lt;br /&gt;
&lt;br /&gt;
Telegram-бот при этом не запускает и не управляет моделями непосредственно.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя&lt;br /&gt;
 |&lt;br /&gt;
 | запрос&lt;br /&gt;
 v&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; разговорная модель&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; модель сложных задач&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; специализированная модель&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; внешний AI (при необходимости)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволит менять модели независимо от Telegram-бота и использовать одну AI-инфраструктуру для нескольких проектов.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.3 — полноценный AI-ассистент ==&lt;br /&gt;
&lt;br /&gt;
Кузя сможет поддерживать обычный разговор.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, что сегодня обсуждали?&lt;br /&gt;
&lt;br /&gt;
Кузя, объясни подробнее.&lt;br /&gt;
&lt;br /&gt;
Кузя, какие правила относятся к публикации ссылок?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При ответе AI сможет учитывать:&lt;br /&gt;
&lt;br /&gt;
* текущий вопрос;&lt;br /&gt;
* предыдущие сообщения разговора;&lt;br /&gt;
* контекст Telegram-чата;&lt;br /&gt;
* правила сообщества;&lt;br /&gt;
* настройки конкретного чата.&lt;br /&gt;
&lt;br /&gt;
Таким образом появляется краткосрочная память.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.4 — долговременная память ==&lt;br /&gt;
&lt;br /&gt;
История сообщений не должна целиком передаваться нейронной модели.&lt;br /&gt;
&lt;br /&gt;
Для этого предполагается использовать технологию RAG.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
История MySQL&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
  индексация&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
 Vector DB&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
поиск нужной истории&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
     AI&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например, участник сможет спросить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, мы раньше обсуждали эту проблему?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кузя найдёт связанные старые обсуждения и использует их при формировании ответа.&lt;br /&gt;
&lt;br /&gt;
Таким образом накопленная история чата становится долговременной памятью сообщества.&lt;br /&gt;
&lt;br /&gt;
= Kuzya Guardian =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kuzya Guardian&#039;&#039;&#039; — ключевое направление дальнейшего развития проекта.&lt;br /&gt;
&lt;br /&gt;
Это интеллектуальная система модерации Telegram-чата.&lt;br /&gt;
&lt;br /&gt;
== Анализ сообщений ==&lt;br /&gt;
&lt;br /&gt;
Новые сообщения смогут проходить через несколько уровней проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram message&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
простые правила&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
AI-анализ&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
оценка риска&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
решение&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
AI сможет определять, например:&lt;br /&gt;
&lt;br /&gt;
* спам;&lt;br /&gt;
* флуд;&lt;br /&gt;
* нежелательную рекламу;&lt;br /&gt;
* оскорбления;&lt;br /&gt;
* провокации;&lt;br /&gt;
* нарушения правил сообщества;&lt;br /&gt;
* эскалацию конфликтов;&lt;br /&gt;
* повторные нарушения.&lt;br /&gt;
&lt;br /&gt;
При этом анализироваться сможет не только одно сообщение, но и контекст разговора.&lt;br /&gt;
&lt;br /&gt;
== Shadow Mode ==&lt;br /&gt;
&lt;br /&gt;
На первом этапе AI &#039;&#039;&#039;не получает право самостоятельно наказывать пользователей&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Кузя работает в теневом режиме — Shadow Mode.&lt;br /&gt;
&lt;br /&gt;
При обнаружении возможного нарушения в административный чат поступает сообщение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя обнаружил возможное нарушение.&lt;br /&gt;
&lt;br /&gt;
Пользователь: @username&lt;br /&gt;
Тип: оскорбление&lt;br /&gt;
Уверенность: 87 %&lt;br /&gt;
&lt;br /&gt;
Предлагаемое действие:&lt;br /&gt;
Предупреждение&lt;br /&gt;
&lt;br /&gt;
[Нарушение]&lt;br /&gt;
[Не нарушение]&lt;br /&gt;
[Мут]&lt;br /&gt;
[Бан]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательное решение принимает человек.&lt;br /&gt;
&lt;br /&gt;
Решение администратора сохраняется в базе.&lt;br /&gt;
&lt;br /&gt;
== Обучение на решениях администраторов ==&lt;br /&gt;
&lt;br /&gt;
Shadow Mode одновременно позволяет собирать новый качественный набор данных.&lt;br /&gt;
&lt;br /&gt;
Для каждого случая можно сохранять:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
сообщение&lt;br /&gt;
+&lt;br /&gt;
контекст&lt;br /&gt;
+&lt;br /&gt;
решение AI&lt;br /&gt;
+&lt;br /&gt;
решение администратора&lt;br /&gt;
+&lt;br /&gt;
причина&lt;br /&gt;
+&lt;br /&gt;
применённое действие&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом Кузя постепенно получает примеры того, &#039;&#039;&#039;как именно администрация данного сообщества трактует его правила&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Существующая база предупреждений также может использоваться как первоначальный набор размеченных примеров.&lt;br /&gt;
&lt;br /&gt;
== Полуавтоматическая модерация ==&lt;br /&gt;
&lt;br /&gt;
После накопления статистики отдельные очевидные нарушения можно будет обрабатывать автоматически.&lt;br /&gt;
&lt;br /&gt;
Примерная модель:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
низкая уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; никаких действий&lt;br /&gt;
&lt;br /&gt;
средняя уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; запись в журнал&lt;br /&gt;
&lt;br /&gt;
высокая уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; сообщение администраторам&lt;br /&gt;
&lt;br /&gt;
очень высокая уверенность&lt;br /&gt;
+ безопасная категория&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; автоматическое действие&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порог автоматизации будет зависеть от типа нарушения.&lt;br /&gt;
&lt;br /&gt;
Например, очевидный массовый спам можно обрабатывать автоматически, тогда как спорные конфликты между людьми должны передаваться администратору.&lt;br /&gt;
&lt;br /&gt;
== Репутация пользователей ==&lt;br /&gt;
&lt;br /&gt;
В перспективе Guardian сможет учитывать историю поведения пользователя.&lt;br /&gt;
&lt;br /&gt;
Учитываются:&lt;br /&gt;
&lt;br /&gt;
* предупреждения;&lt;br /&gt;
* муты;&lt;br /&gt;
* баны;&lt;br /&gt;
* повторные нарушения;&lt;br /&gt;
* частота конфликтов;&lt;br /&gt;
* длительные периоды без нарушений.&lt;br /&gt;
&lt;br /&gt;
Репутация является внутренним параметром системы и не обязательно должна отображаться участникам.&lt;br /&gt;
&lt;br /&gt;
Она используется только как дополнительный контекст для принятия решения.&lt;br /&gt;
&lt;br /&gt;
== Анализ конфликтов ==&lt;br /&gt;
&lt;br /&gt;
Одна из перспективных функций — обнаружение развивающегося конфликта.&lt;br /&gt;
&lt;br /&gt;
Кузя анализирует последовательность сообщений нескольких участников и может определить постепенную эскалацию.&lt;br /&gt;
&lt;br /&gt;
Вместо немедленного наказания бот сначала сможет предложить участникам прекратить спор.&lt;br /&gt;
&lt;br /&gt;
Если конфликт продолжается, информация передаётся администраторам.&lt;br /&gt;
&lt;br /&gt;
Таким образом система должна оценивать не только отдельные слова, но и развитие разговора.&lt;br /&gt;
&lt;br /&gt;
= Аналитика сообщества =&lt;br /&gt;
&lt;br /&gt;
Кузя сможет формировать статистику Telegram-чата.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Статистика за сутки&lt;br /&gt;
&lt;br /&gt;
Сообщений: 2351&lt;br /&gt;
Активных участников: 187&lt;br /&gt;
Новых участников: 14&lt;br /&gt;
&lt;br /&gt;
Предупреждений: 3&lt;br /&gt;
Мутов: 1&lt;br /&gt;
Удалено спама: 9&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Дополнительно AI сможет определять основные темы обсуждения.&lt;br /&gt;
&lt;br /&gt;
== Ежедневный дайджест ==&lt;br /&gt;
&lt;br /&gt;
В перспективе возможно автоматическое формирование краткого отчёта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Что произошло сегодня&lt;br /&gt;
&lt;br /&gt;
Обсудили:&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Важные ссылки:&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Модерация:&lt;br /&gt;
* 2 предупреждения&lt;br /&gt;
* 1 мут&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это особенно полезно участникам и администраторам, которые не могли постоянно следить за чатом.&lt;br /&gt;
&lt;br /&gt;
= Знание правил сообщества =&lt;br /&gt;
&lt;br /&gt;
Правила конкретного сообщества становятся частью базы знаний Кузи.&lt;br /&gt;
&lt;br /&gt;
Участник сможет спросить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, можно здесь публиковать ссылку на YouTube?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ будет основан именно на действующих правилах данного сообщества.&lt;br /&gt;
&lt;br /&gt;
Кузя также сможет объяснять административные решения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Почему сообщение удалено?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Сообщение нарушает пункт 2 правил:&lt;br /&gt;
ссылка опубликована без необходимого описания.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Этапы разработки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Версия&lt;br /&gt;
! Основная задача&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Legacy&#039;&#039;&#039;&lt;br /&gt;
| Текущий рабочий Кузя&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.0&#039;&#039;&#039;&lt;br /&gt;
| Новая архитектура и полный перенос существующих функций&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.1&#039;&#039;&#039;&lt;br /&gt;
| Новая структура MySQL и сохранение существующей истории&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.2&#039;&#039;&#039;&lt;br /&gt;
| Интеграция с RAMBA AI Router&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.3&#039;&#039;&#039;&lt;br /&gt;
| Полноценные AI-диалоги и краткосрочный контекст&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.4&#039;&#039;&#039;&lt;br /&gt;
| RAG и долговременная память по истории Telegram-чата&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.0&#039;&#039;&#039;&lt;br /&gt;
| Kuzya Guardian&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.1&#039;&#039;&#039;&lt;br /&gt;
| Shadow Mode&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.2&#039;&#039;&#039;&lt;br /&gt;
| Полуавтоматическая модерация&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.3&#039;&#039;&#039;&lt;br /&gt;
| Репутационная система&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.4&#039;&#039;&#039;&lt;br /&gt;
| Анализ конфликтов&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.0&#039;&#039;&#039;&lt;br /&gt;
| Аналитика сообщества и дайджесты&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.1&#039;&#039;&#039;&lt;br /&gt;
| Глубокая интеграция AI с правилами сообщества&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;5.0&#039;&#039;&#039;&lt;br /&gt;
| Полноценный интеллектуальный Community Guardian&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Принципы проекта =&lt;br /&gt;
&lt;br /&gt;
При разработке Кузи предлагается придерживаться нескольких основных принципов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Существующие функции не должны быть потеряны.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Новая версия сначала достигает функционального паритета с текущей и только затем заменяет её.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Решение человека важнее решения AI.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Администратор всегда должен иметь возможность отменить или изменить решение системы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Автоматизация вводится постепенно.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Сначала наблюдение, затем рекомендации и только после проверки качества — автоматические действия.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. История сообщества является ценным активом.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Существующая MySQL-база сохраняется и используется для построения памяти и системы модерации.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Основной AI работает локально.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Локальные модели являются основой интеллектуальных функций Кузи. Внешние AI API используются только как дополнительный инструмент.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Кузя остаётся специализированным ботом.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Его основная область ответственности — Telegram-сообщество.&lt;br /&gt;
&lt;br /&gt;
Управление серверами, Proxmox, GitLab, Matrix и другой инфраструктурой RAMBA выносится в отдельный RAMBA Bot.&lt;br /&gt;
&lt;br /&gt;
= Конечная цель =&lt;br /&gt;
&lt;br /&gt;
Конечная цель проекта — превратить Кузю из набора административных Telegram-команд в полноценного интеллектуального помощника сообщества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                 КУЗЯ&lt;br /&gt;
                   |&lt;br /&gt;
     +-------------+-------------+&lt;br /&gt;
     |             |             |&lt;br /&gt;
     v             v             v&lt;br /&gt;
Администратор  AI-ассистент    Guardian&lt;br /&gt;
     |             |             |&lt;br /&gt;
 команды          диалог       модерация&lt;br /&gt;
 правила          память       антиспам&lt;br /&gt;
 warnings         RAG          конфликты&lt;br /&gt;
 канал            поиск       репутация&lt;br /&gt;
     |             |             |&lt;br /&gt;
     +-------------+-------------+&lt;br /&gt;
                   |&lt;br /&gt;
                   v&lt;br /&gt;
               RAMBA AI&lt;br /&gt;
            Local AI Router&lt;br /&gt;
               GTX 1080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кузя должен не просто выполнять команды администратора, а понимать происходящее в сообществе, помогать его участникам, сохранять накопленные знания и поддерживать порядок, оставляя окончательный контроль за администрацией.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[https://wiki.ramba-art.ru/wiki/Kuzya_2-0_lost_patch| Кузя 2.0 последние изменения]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Kuzya_2-0_lost_patch&amp;diff=155</id>
		<title>Kuzya 2-0 lost patch</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Kuzya_2-0_lost_patch&amp;diff=155"/>
		<updated>2026-09-26T06:21:50Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «&amp;#039;&amp;#039;&amp;#039;Кузя&amp;#039;&amp;#039;&amp;#039; — Telegram-бот для администрирования и сопровождения сообщества. Проект развивается от административного бота к интеллектуальному помощнику, способному поддерживать диалог, находить информацию в истории чата и помогать модераторам.  Основная з...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Кузя&#039;&#039;&#039; — Telegram-бот для администрирования и сопровождения сообщества. Проект развивается от административного бота к интеллектуальному помощнику, способному поддерживать диалог, находить информацию в истории чата и помогать модераторам.&lt;br /&gt;
&lt;br /&gt;
Основная задача Кузи — автоматизировать рутинные действия и предоставить администрации удобные инструменты управления сообществом. Окончательный контроль остаётся у людей.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Текущий этап: Kuzya 2.0 — перенос существующих функций на новую архитектуру. Полный функциональный паритет с Legacy пока не подтверждён.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Состояние разработки в статье отражает проверку репозитория и результатов тестирования по состоянию на &#039;&#039;&#039;18 сентября 2026 года&#039;&#039;&#039;. Наличие кода в репозитории не означает, что все возможности уже развёрнуты и проверены в основном сообществе.&lt;br /&gt;
&lt;br /&gt;
== Репозиторий и версии ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitlab.ramba-art.ru/Gans/noprodaction Репозиторий noProdaction]&lt;br /&gt;
* [https://gitlab.ramba-art.ru/Gans/noprodaction/-/tree/feature/openai-bot-v2 Ветка разработки Kuzya 2.0]&lt;br /&gt;
* [https://gitlab.ramba-art.ru/Gans/noprodaction/-/commits/feature/openai-bot-v2 История изменений Kuzya 2.0]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Версия / ветка&lt;br /&gt;
! Назначение&lt;br /&gt;
! Подтверждённое состояние&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Legacy Stable&#039;&#039;&#039;&lt;br /&gt;
| Существующая версия и эталон поведения при переносе&lt;br /&gt;
| Legacy-код сохранён в репозитории; при проверке ветки &amp;lt;code&amp;gt;main&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;kuzya-1.0&amp;lt;/code&amp;gt; указывали на коммит &amp;lt;code&amp;gt;145bc857&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Kuzya 2.0&#039;&#039;&#039;&lt;br /&gt;
| Новая реализация на aiogram 3&lt;br /&gt;
| Разрабатывается в &amp;lt;code&amp;gt;feature/openai-bot-v2&amp;lt;/code&amp;gt;; часть функций перенесена и проверена&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Последняя подтверждённая точка 2.0&#039;&#039;&#039;&lt;br /&gt;
| Перенос команд модерации&lt;br /&gt;
| Коммит &amp;lt;code&amp;gt;b5095f4f&amp;lt;/code&amp;gt; от 3 сентября 2026 года&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Главный принцип миграции:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Новая версия должна сохранить существующие возможности и архив MySQL. Замена Legacy допускается после проверки функционального паритета.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Базовые AI-функции уже присутствуют в ветке 2.0. Их наличие не означает завершения миграции или готовности будущего Guardian.&lt;br /&gt;
&lt;br /&gt;
== Возможности Legacy Stable ==&lt;br /&gt;
&lt;br /&gt;
Legacy служит исходной точкой для переноса следующих возможностей:&lt;br /&gt;
&lt;br /&gt;
* выдача и снятие мута;&lt;br /&gt;
* временный и постоянный бан;&lt;br /&gt;
* предупреждения с указанием причины;&lt;br /&gt;
* хранение истории предупреждений;&lt;br /&gt;
* внутренний список администраторов Кузи;&lt;br /&gt;
* приветствие новых участников;&lt;br /&gt;
* информационные команды;&lt;br /&gt;
* вывод правил, ссылок и приглашений;&lt;br /&gt;
* информация о поддержке проекта;&lt;br /&gt;
* взаимодействие с публикациями Telegram-канала;&lt;br /&gt;
* информационные сообщения под новыми видео;&lt;br /&gt;
* хранение истории сообщений чата;&lt;br /&gt;
* изменение настроек и текстов административными командами;&lt;br /&gt;
* базовое взаимодействие с AI.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Этот список описывает исходную функциональность проекта, а не подтверждённый полный набор возможностей Kuzya 2.0.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Что уже сделано в Kuzya 2.0 ==&lt;br /&gt;
&lt;br /&gt;
=== Новая основа бота ===&lt;br /&gt;
&lt;br /&gt;
В репозитории зафиксированы:&lt;br /&gt;
&lt;br /&gt;
* создание новой версии на &#039;&#039;&#039;aiogram 3&#039;&#039;&#039;;&lt;br /&gt;
* разделение обработчиков и сервисов;&lt;br /&gt;
* интеграция OpenAI через прокси;&lt;br /&gt;
* AI-ответы в личных сообщениях;&lt;br /&gt;
* сохранение истории в совместимом с Legacy формате;&lt;br /&gt;
* поддержка диалога через reply;&lt;br /&gt;
* перенос информационных команд;&lt;br /&gt;
* перенос приветствий;&lt;br /&gt;
* перенос внутренних администраторов;&lt;br /&gt;
* перенос предупреждений;&lt;br /&gt;
* перенос команд модерации.&lt;br /&gt;
&lt;br /&gt;
Наличие базового reply-диалога не означает готовности полноценного контекста сообщества, долговременной памяти или RAG.&lt;br /&gt;
&lt;br /&gt;
=== Контрольные коммиты ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Дата&lt;br /&gt;
! Коммит&lt;br /&gt;
! Изменение&lt;br /&gt;
|-&lt;br /&gt;
| 26 августа 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;b55de2fa&amp;lt;/code&amp;gt;&lt;br /&gt;
| Создание бота на aiogram 3&lt;br /&gt;
|-&lt;br /&gt;
| 26 августа 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;38472685&amp;lt;/code&amp;gt;&lt;br /&gt;
| Рабочая интеграция OpenAI через прокси&lt;br /&gt;
|-&lt;br /&gt;
| 2 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;aa68090b&amp;lt;/code&amp;gt;&lt;br /&gt;
| AI-ответы в личных сообщениях&lt;br /&gt;
|-&lt;br /&gt;
| 2 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;476d2895&amp;lt;/code&amp;gt;&lt;br /&gt;
| Удаление старого кода из ветки разработки и подготовка Kuzya 2.0&lt;br /&gt;
|-&lt;br /&gt;
| 2 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;e691eb92&amp;lt;/code&amp;gt;&lt;br /&gt;
| История в Legacy-БД и диалог через reply&lt;br /&gt;
|-&lt;br /&gt;
| 2 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;da627b0c&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перенос информационных команд&lt;br /&gt;
|-&lt;br /&gt;
| 2 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;346f7b69&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перенос приветствий&lt;br /&gt;
|-&lt;br /&gt;
| 3 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;2a9a23ea&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перенос внутренних администраторов&lt;br /&gt;
|-&lt;br /&gt;
| 3 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;2ae970c5&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перенос системы предупреждений&lt;br /&gt;
|-&lt;br /&gt;
| 3 сентября 2026&lt;br /&gt;
| &amp;lt;code&amp;gt;b5095f4f&amp;lt;/code&amp;gt;&lt;br /&gt;
| Перенос команд модерации&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Источник: [https://gitlab.ramba-art.ru/Gans/noprodaction/-/commits/feature/openai-bot-v2 история ветки разработки].&lt;br /&gt;
&lt;br /&gt;
=== Внутренние администраторы ===&lt;br /&gt;
&lt;br /&gt;
Перенесена команда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!свой&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда применяется ответом на сообщение пользователя и добавляет его во внутренний список администраторов Кузи.&lt;br /&gt;
&lt;br /&gt;
Подтверждено тестированием:&lt;br /&gt;
&lt;br /&gt;
* распознавание команды;&lt;br /&gt;
* проверка инициатора по внутренней таблице администраторов;&lt;br /&gt;
* определение пользователя из reply;&lt;br /&gt;
* обнаружение уже зарегистрированного администратора;&lt;br /&gt;
* добавление нового администратора в MySQL.&lt;br /&gt;
&lt;br /&gt;
При проверке в тестовом чате количество записей увеличилось с двух до трёх.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Внутренний администратор Кузи и администратор Telegram-чата — разные роли.&#039;&#039;&#039; Команда &amp;lt;code&amp;gt;!свой&amp;lt;/code&amp;gt; управляет внутренним списком и сама по себе не выдаёт административные права Telegram.&lt;br /&gt;
&lt;br /&gt;
=== Предупреждения ===&lt;br /&gt;
&lt;br /&gt;
Перенесена команда:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
!предупреждение причина&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Команда применяется ответом на сообщение нарушителя.&lt;br /&gt;
&lt;br /&gt;
Реализована цепочка:&lt;br /&gt;
&lt;br /&gt;
# Проверка прав внутреннего администратора Кузи.&lt;br /&gt;
# Определение нарушителя и исходного сообщения.&lt;br /&gt;
# Запись предупреждения в MySQL.&lt;br /&gt;
# Подсчёт предупреждений пользователя.&lt;br /&gt;
# Удаление команды и сообщения-нарушения при наличии необходимых прав.&lt;br /&gt;
# Публикация уведомления в чате.&lt;br /&gt;
&lt;br /&gt;
Проверено создание предупреждения с причиной &amp;lt;code&amp;gt;тест&amp;lt;/code&amp;gt; и сохранение соответствующей записи в MySQL.&lt;br /&gt;
&lt;br /&gt;
Добавлено создание отсутствующей таблицы предупреждений по совместимой схеме, включая поле &amp;lt;code&amp;gt;message_id&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Уведомление в отдельном админ-чате и кнопка мута после предупреждения остаются незавершённой частью переноса.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Мут, размут и бан ===&lt;br /&gt;
&lt;br /&gt;
В новой версии используются команды без старого суффикса &amp;lt;code&amp;gt;1&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Команда&lt;br /&gt;
! Назначение&lt;br /&gt;
! Состояние проверки&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!мут 30&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ограничить отправку сообщений на указанное число минут&lt;br /&gt;
| Временный мут проверен в тестовом чате&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!размут&amp;lt;/code&amp;gt;&lt;br /&gt;
| Снять ограничения отправки сообщений&lt;br /&gt;
| Проверено в тестовом чате&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!бан 60&amp;lt;/code&amp;gt;&lt;br /&gt;
| Исключить пользователя и запретить возвращение на указанное число минут&lt;br /&gt;
| Проверен временный бан на одну минуту&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;!бан 0&amp;lt;/code&amp;gt;&lt;br /&gt;
| Постоянный бан&lt;br /&gt;
| Предусмотрен кодом; отдельный live-тест не зафиксирован&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Команды применяются ответом на сообщение пользователя.&lt;br /&gt;
&lt;br /&gt;
Инициатор должен иметь права администратора Telegram-чата. Для &amp;lt;code&amp;gt;!размут&amp;lt;/code&amp;gt; также добавлена проверка прав, отсутствовавшая в разобранном Legacy-обработчике.&lt;br /&gt;
&lt;br /&gt;
Результаты тестов мута, размута и временного бана подтверждены сообщениями бота и наблюдением за поведением тестового пользователя.&lt;br /&gt;
&lt;br /&gt;
=== Среда разработки ===&lt;br /&gt;
&lt;br /&gt;
По последним зафиксированным результатам новая версия запускалась в следующей среде:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Узел / контейнер&lt;br /&gt;
| &amp;lt;code&amp;gt;noprodaction-v2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| &amp;lt;code&amp;gt;503&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Каталог проекта&lt;br /&gt;
| &amp;lt;code&amp;gt;/opt/bots/noprodaction&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Ветка&lt;br /&gt;
| &amp;lt;code&amp;gt;feature/openai-bot-v2&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Сервис&lt;br /&gt;
| &amp;lt;code&amp;gt;kuzya.service&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Окружение Python&lt;br /&gt;
| &amp;lt;code&amp;gt;.venv&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Чат для проверок&lt;br /&gt;
| «Панды»&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Эти сведения описывают последнюю подтверждённую конфигурацию. Текущее состояние сервиса проверяется отдельно на сервере.&lt;br /&gt;
&lt;br /&gt;
== Текущая точка остановки ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Последний подтверждённый завершённый блок — перенос команд модерации.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Он сохранён в репозитории:&lt;br /&gt;
&lt;br /&gt;
[https://gitlab.ramba-art.ru/Gans/noprodaction/-/commit/b5095f4f92f994d07c151fdedf399e27c556eb74 b5095f4f — Migrate legacy moderation commands].&lt;br /&gt;
&lt;br /&gt;
Следующим обсуждалось восстановление действия &#039;&#039;&#039;«Мут на 120 минут»&#039;&#039;&#039; после предупреждения.&lt;br /&gt;
&lt;br /&gt;
В ходе обсуждения предложено расширить этот механизм:&lt;br /&gt;
&lt;br /&gt;
* создать отдельный служебный админ-чат;&lt;br /&gt;
* привязать его к основному сообществу;&lt;br /&gt;
* отправлять туда карточки предупреждений;&lt;br /&gt;
* принимать решение о муте голосованием внутренних администраторов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Привязка чатов и коллективное голосование находятся на стадии проектирования. Их реализация в проверенном состоянии репозитория не подтверждена.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ближайшие задачи ===&lt;br /&gt;
&lt;br /&gt;
# Проверить актуальное состояние ветки, сервиса и соответствие запущенного кода репозиторию.&lt;br /&gt;
# Завершить уведомления о предупреждениях и действие мута на 120 минут.&lt;br /&gt;
# Согласовать правила привязки админ-чата и коллективного голосования.&lt;br /&gt;
# Составить полный список функций Legacy и проверить каждую в Kuzya 2.0.&lt;br /&gt;
# Завершить недостающие функции, включая проверку сценариев публикаций канала и изменения настроек.&lt;br /&gt;
# Подтвердить сохранность архива и совместимость работы с MySQL.&lt;br /&gt;
# После достижения паритета переходить к следующим этапам дорожной карты.&lt;br /&gt;
&lt;br /&gt;
== Планируемая коллективная модерация ==&lt;br /&gt;
&lt;br /&gt;
=== Привязка админ-чата ===&lt;br /&gt;
&lt;br /&gt;
Для основного сообщества предлагается хранить привязку к отдельному служебному чату.&lt;br /&gt;
&lt;br /&gt;
Пример предполагаемой схемы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Основной чат&lt;br /&gt;
     |&lt;br /&gt;
     | предупреждение&lt;br /&gt;
     v&lt;br /&gt;
Привязанный админ-чат&lt;br /&gt;
     |&lt;br /&gt;
     | карточка нарушения&lt;br /&gt;
     v&lt;br /&gt;
Голосование администраторов&lt;br /&gt;
     |&lt;br /&gt;
     v&lt;br /&gt;
Исполнение принятого решения&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В качестве интерфейса обсуждалась двухэтапная привязка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
В основном чате:&lt;br /&gt;
!кодадминчата&lt;br /&gt;
&lt;br /&gt;
В служебном чате:&lt;br /&gt;
!привязать &amp;lt;код&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Названия команд приведены как предложение и пока не являются документированным рабочим интерфейсом.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Голосование за мут ===&lt;br /&gt;
&lt;br /&gt;
Предлагаемая карточка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Новое предупреждение&lt;br /&gt;
&lt;br /&gt;
Чат: название сообщества&lt;br /&gt;
Пользователь: имя / username&lt;br /&gt;
Причина: флуд&lt;br /&gt;
Всего предупреждений: 3&lt;br /&gt;
Выдал: администратор&lt;br /&gt;
&lt;br /&gt;
Предложение: мут на 120 минут&lt;br /&gt;
&lt;br /&gt;
[За мут] [Против]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Предлагаемые правила:&lt;br /&gt;
&lt;br /&gt;
* голосуют внутренние администраторы соответствующего основного чата;&lt;br /&gt;
* каждый администратор имеет один голос;&lt;br /&gt;
* до завершения голосования голос можно изменить;&lt;br /&gt;
* решение принимается при количестве голосов «за» больше половины состава;&lt;br /&gt;
* после исполнения решения голосование закрывается;&lt;br /&gt;
* обычные команды ручной модерации сохраняются.&lt;br /&gt;
&lt;br /&gt;
Предлагаемая формула большинства:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
required_votes = admin_count // 2 + 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Число администраторов&lt;br /&gt;
! Необходимо голосов «за»&lt;br /&gt;
|-&lt;br /&gt;
| 3&lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| 3&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| 3&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| 4&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Перед реализацией необходимо определить:&lt;br /&gt;
&lt;br /&gt;
* окончательный порог голосования;&lt;br /&gt;
* срок действия голосования;&lt;br /&gt;
* условия закрытия без принятого решения;&lt;br /&gt;
* порядок учёта изменений состава администраторов;&lt;br /&gt;
* поведение при ручном муте или бане во время голосования;&lt;br /&gt;
* защиту от повторного исполнения;&lt;br /&gt;
* обработку ошибок Telegram API.&lt;br /&gt;
&lt;br /&gt;
В будущем этот механизм может принимать предложения Guardian. До появления Guardian он должен работать самостоятельно для ручных предупреждений.&lt;br /&gt;
&lt;br /&gt;
== База данных и архив сообщества ==&lt;br /&gt;
&lt;br /&gt;
Кузя использует &#039;&#039;&#039;MySQL&#039;&#039;&#039; для хранения истории и служебных данных.&lt;br /&gt;
&lt;br /&gt;
По исторической оценке за август 2026 года архив содержал около &#039;&#039;&#039;497 000 сообщений&#039;&#039;&#039;. Это ориентир за указанный период, а не текущий результат подсчёта строк.&lt;br /&gt;
&lt;br /&gt;
=== История сообщений ===&lt;br /&gt;
&lt;br /&gt;
В Legacy-формате сохраняются, в частности:&lt;br /&gt;
&lt;br /&gt;
* дата и время;&lt;br /&gt;
* идентификатор чата;&lt;br /&gt;
* Telegram ID пользователя;&lt;br /&gt;
* username;&lt;br /&gt;
* отображаемое имя;&lt;br /&gt;
* текст сообщения;&lt;br /&gt;
* Telegram message ID.&lt;br /&gt;
&lt;br /&gt;
При миграции необходимо сохранять существующий архив и связи между записями.&lt;br /&gt;
&lt;br /&gt;
=== Предупреждения ===&lt;br /&gt;
&lt;br /&gt;
Для предупреждений используются отдельные записи, содержащие:&lt;br /&gt;
&lt;br /&gt;
* пользователя;&lt;br /&gt;
* идентификатор исходного сообщения;&lt;br /&gt;
* причину;&lt;br /&gt;
* значение &amp;lt;code&amp;gt;number_of_warnings&amp;lt;/code&amp;gt;;&lt;br /&gt;
* идентификатор и имя администратора;&lt;br /&gt;
* дату и время.&lt;br /&gt;
&lt;br /&gt;
В перенесённой Legacy-логике каждое новое предупреждение создаёт строку со значением:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
number_of_warnings = 1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Общее число предупреждений пользователя определяется суммированием этого поля.&lt;br /&gt;
&lt;br /&gt;
Для связи с исходным сообщением предусмотрено поле &amp;lt;code&amp;gt;message_id&amp;lt;/code&amp;gt;. Полноту исторических связей необходимо проверить до использования данных для интеллектуальной модерации.&lt;br /&gt;
&lt;br /&gt;
При сопоставлении сообщений требуется учитывать также чат: одного &amp;lt;code&amp;gt;message_id&amp;lt;/code&amp;gt; недостаточно для различения сообщений из разных чатов.&lt;br /&gt;
&lt;br /&gt;
=== Использование архива для AI ===&lt;br /&gt;
&lt;br /&gt;
История предупреждений может стать источником примеров нарушений, но ещё не считается готовым проверенным набором данных.&lt;br /&gt;
&lt;br /&gt;
Перед использованием необходимо:&lt;br /&gt;
&lt;br /&gt;
* проверить наличие исходных сообщений;&lt;br /&gt;
* проверить причины и корректность связей;&lt;br /&gt;
* восстановить доступный контекст;&lt;br /&gt;
* учесть изменения правил сообщества;&lt;br /&gt;
* отделить подтверждённые нарушения от спорных случаев;&lt;br /&gt;
* добавить примеры сообщений без нарушений.&lt;br /&gt;
&lt;br /&gt;
== Архитектура проекта ==&lt;br /&gt;
&lt;br /&gt;
=== Текущая реализация ===&lt;br /&gt;
&lt;br /&gt;
В разработке используются отдельные обработчики и сервисы. Среди подтверждённых компонентов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
main.py&lt;br /&gt;
bot/&lt;br /&gt;
  handlers/&lt;br /&gt;
    common.py&lt;br /&gt;
    info.py&lt;br /&gt;
    ai.py&lt;br /&gt;
    history.py&lt;br /&gt;
    admins.py&lt;br /&gt;
    moderation.py&lt;br /&gt;
  services/&lt;br /&gt;
    database.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Схема показывает известные компоненты и не является полным перечнем файлов репозитория.&lt;br /&gt;
&lt;br /&gt;
=== Целевая архитектура ===&lt;br /&gt;
&lt;br /&gt;
В перспективе Кузя объединит три направления:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    КУЗЯ&lt;br /&gt;
                      |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
        |             |             |&lt;br /&gt;
        v             v             v&lt;br /&gt;
 Telegram Admin   AI Assistant    Guardian&lt;br /&gt;
        |             |             |&lt;br /&gt;
   mute / ban       диалог       анализ нарушений&lt;br /&gt;
   warnings         контекст     предложения&lt;br /&gt;
   rules            поиск        антиспам&lt;br /&gt;
   channel          RAG          конфликты&lt;br /&gt;
        |             |             |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
                      |&lt;br /&gt;
                      v&lt;br /&gt;
                 RAMBA AI Router&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это целевая схема. Guardian, RAG и подключение Кузи к RAMBA AI Router не относятся к подтверждённым завершённым функциям текущей версии.&lt;br /&gt;
&lt;br /&gt;
== AI: текущая реализация и целевое направление ==&lt;br /&gt;
&lt;br /&gt;
=== Текущая реализация ===&lt;br /&gt;
&lt;br /&gt;
В ветке Kuzya 2.0 зафиксированы интеграция OpenAI через прокси, ответы в личных сообщениях и базовый диалог через reply.&lt;br /&gt;
&lt;br /&gt;
Эти возможности необходимо учитывать при описании текущего состояния: AI уже присутствует, хотя миграция Legacy ещё не завершена.&lt;br /&gt;
&lt;br /&gt;
=== Планируемая интеграция RAMBA AI Router ===&lt;br /&gt;
&lt;br /&gt;
Целевое направление — использование локальной инфраструктуры RAMBA AI.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
  Кузя&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
    |&lt;br /&gt;
    +--&amp;gt; локальная модель для быстрых ответов&lt;br /&gt;
    |&lt;br /&gt;
    +--&amp;gt; локальная модель для сложных задач&lt;br /&gt;
    |&lt;br /&gt;
    +--&amp;gt; специализированная модель&lt;br /&gt;
    |&lt;br /&gt;
    +--&amp;gt; внешний AI при необходимости&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Telegram-бот должен обращаться к Router через согласованный интерфейс. Выбор и запуск моделей остаются ответственностью AI-инфраструктуры.&lt;br /&gt;
&lt;br /&gt;
Локальные модели планируются как основа интеллектуальных функций, внешние API — как дополнительный инструмент.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Развитие RAMBA AI Router и его памяти является отдельной работой. Готовность функции Router не означает её автоматического подключения к Кузе.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Дорожная карта ==&lt;br /&gt;
&lt;br /&gt;
Номера версий ниже обозначают планируемые этапы развития, а не список выпущенных релизов.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Этап&lt;br /&gt;
! Основная задача&lt;br /&gt;
! Статус по последней проверке&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Legacy Stable&#039;&#039;&#039;&lt;br /&gt;
| Существующая функциональность и эталон миграции&lt;br /&gt;
| Исходная версия сохранена&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.0&#039;&#039;&#039;&lt;br /&gt;
| Новая архитектура и полный перенос существующих функций&lt;br /&gt;
| В работе; часть функций перенесена и проверена&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.1&#039;&#039;&#039;&lt;br /&gt;
| Нормализация MySQL с сохранением архива&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.2&#039;&#039;&#039;&lt;br /&gt;
| Интеграция с RAMBA AI Router&lt;br /&gt;
| Запланировано; подключение Кузи не подтверждено&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.3&#039;&#039;&#039;&lt;br /&gt;
| Развитие диалогов и краткосрочного контекста&lt;br /&gt;
| Запланировано поверх базовых AI-ответов&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.4&#039;&#039;&#039;&lt;br /&gt;
| RAG по истории Telegram-чата&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.0&#039;&#039;&#039;&lt;br /&gt;
| Основа Kuzya Guardian&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.1&#039;&#039;&#039;&lt;br /&gt;
| Shadow Mode и оценка качества&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.2&#039;&#039;&#039;&lt;br /&gt;
| Полуавтоматическая модерация&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.3&#039;&#039;&#039;&lt;br /&gt;
| Репутация пользователей&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.4&#039;&#039;&#039;&lt;br /&gt;
| Анализ развития конфликтов&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.0&#039;&#039;&#039;&lt;br /&gt;
| Аналитика сообщества и дайджесты&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.1&#039;&#039;&#039;&lt;br /&gt;
| Глубокая интеграция AI с правилами сообщества&lt;br /&gt;
| Запланировано&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;5.0&#039;&#039;&#039;&lt;br /&gt;
| Интеллектуальный Community Guardian&lt;br /&gt;
| Долгосрочная цель&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kuzya 2.0 — функциональный паритет ===&lt;br /&gt;
&lt;br /&gt;
Этап считается завершённым после проверки переноса всех необходимых возможностей Legacy.&lt;br /&gt;
&lt;br /&gt;
Критерии готовности:&lt;br /&gt;
&lt;br /&gt;
* административные и информационные команды работают;&lt;br /&gt;
* приветствия и сценарии публикаций канала проверены;&lt;br /&gt;
* настройки и тексты доступны в предусмотренных сценариях;&lt;br /&gt;
* история и предупреждения сохраняются корректно;&lt;br /&gt;
* права доступа соответствуют назначению команд;&lt;br /&gt;
* архив MySQL сохранён;&lt;br /&gt;
* известные различия с Legacy документированы;&lt;br /&gt;
* подготовлен порядок переключения и возврата к стабильной версии.&lt;br /&gt;
&lt;br /&gt;
=== Kuzya 2.1 — нормализация MySQL ===&lt;br /&gt;
&lt;br /&gt;
Планируется постепенный переход от таблиц отдельных чатов к общей структуре:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;chats&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;users&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;messages&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;warnings&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;moderation_actions&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;admins&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;chat_settings&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Миграция должна сохранять историю, идентификаторы и связи данных.&lt;br /&gt;
&lt;br /&gt;
Для административных действий планируется учитывать источник решения:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;human&amp;lt;/code&amp;gt; — администратор;&lt;br /&gt;
* &amp;lt;code&amp;gt;ai&amp;lt;/code&amp;gt; — AI;&lt;br /&gt;
* &amp;lt;code&amp;gt;rule&amp;lt;/code&amp;gt; — автоматическое правило.&lt;br /&gt;
&lt;br /&gt;
Для коллективных решений дополнительно потребуется хранить сведения о голосовании.&lt;br /&gt;
&lt;br /&gt;
=== Kuzya 2.2 — RAMBA AI Router ===&lt;br /&gt;
&lt;br /&gt;
Планируется подключение Кузи к общему AI-бэкенду.&lt;br /&gt;
&lt;br /&gt;
Это позволит:&lt;br /&gt;
&lt;br /&gt;
* менять модели независимо от Telegram-бота;&lt;br /&gt;
* использовать одну инфраструктуру для нескольких проектов;&lt;br /&gt;
* централизованно управлять маршрутизацией запросов;&lt;br /&gt;
* определить условия обращения к внешнему AI.&lt;br /&gt;
&lt;br /&gt;
=== Kuzya 2.3 — контекст диалогов ===&lt;br /&gt;
&lt;br /&gt;
Планируется развитие диалога с учётом:&lt;br /&gt;
&lt;br /&gt;
* текущего вопроса;&lt;br /&gt;
* предыдущих реплик;&lt;br /&gt;
* цепочки reply;&lt;br /&gt;
* принадлежности сообщений к конкретному чату и разговору;&lt;br /&gt;
* настроек сообщества;&lt;br /&gt;
* доступных правил.&lt;br /&gt;
&lt;br /&gt;
Контекст разных пользователей и чатов должен разделяться в соответствии с назначением диалога.&lt;br /&gt;
&lt;br /&gt;
=== Kuzya 2.4 — RAG по истории ===&lt;br /&gt;
&lt;br /&gt;
История чата не должна целиком передаваться модели при каждом запросе.&lt;br /&gt;
&lt;br /&gt;
Планируемая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Архив MySQL&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
Подготовка и индексация&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
Поисковый индекс&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
Поиск подходящих фрагментов&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
Контекст для ответа AI&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конкретный способ поиска и необходимость векторной базы определяются при реализации.&lt;br /&gt;
&lt;br /&gt;
Пример будущего запроса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, мы раньше обсуждали эту проблему?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Бот должен находить связанные обсуждения и, где возможно, показывать ссылки на исходные сообщения.&lt;br /&gt;
&lt;br /&gt;
== Kuzya Guardian ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kuzya Guardian&#039;&#039;&#039; — планируемая система интеллектуальной помощи модераторам.&lt;br /&gt;
&lt;br /&gt;
Она должна анализировать сообщения и контекст, находить возможные нарушения и предлагать действия.&lt;br /&gt;
&lt;br /&gt;
=== Анализ сообщений ===&lt;br /&gt;
&lt;br /&gt;
Предполагаемые категории:&lt;br /&gt;
&lt;br /&gt;
* спам;&lt;br /&gt;
* флуд;&lt;br /&gt;
* нежелательная реклама;&lt;br /&gt;
* оскорбления;&lt;br /&gt;
* нарушения правил;&lt;br /&gt;
* провокации;&lt;br /&gt;
* эскалация конфликтов;&lt;br /&gt;
* повторные нарушения.&lt;br /&gt;
&lt;br /&gt;
Планируемая последовательность:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Новое сообщение&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
Проверки по правилам&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
AI-анализ сообщения и контекста&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
Оценка и объяснение&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
Рекомендация или передача модераторам&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Shadow Mode ===&lt;br /&gt;
&lt;br /&gt;
На первом этапе Guardian работает в режиме наблюдения.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;AI не получает право самостоятельно наказывать пользователей.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Он формирует предложения, а администрация подтверждает или отклоняет их.&lt;br /&gt;
&lt;br /&gt;
Пример будущей карточки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Возможное нарушение&lt;br /&gt;
&lt;br /&gt;
Пользователь: @username&lt;br /&gt;
Категория: оскорбление&lt;br /&gt;
Основание: пояснение с учётом контекста&lt;br /&gt;
Предлагаемое действие: предупреждение&lt;br /&gt;
&lt;br /&gt;
[Нарушение] [Не нарушение] [Рассмотреть действие]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Решения модераторов сохраняются для оценки качества системы.&lt;br /&gt;
&lt;br /&gt;
=== Данные для оценки качества ===&lt;br /&gt;
&lt;br /&gt;
Для рассмотренного случая планируется сохранять:&lt;br /&gt;
&lt;br /&gt;
* исходное сообщение;&lt;br /&gt;
* доступный контекст;&lt;br /&gt;
* версию правил;&lt;br /&gt;
* оценку и объяснение AI;&lt;br /&gt;
* решение модератора;&lt;br /&gt;
* причину решения;&lt;br /&gt;
* фактически выполненное действие.&lt;br /&gt;
&lt;br /&gt;
Сбор таких примеров не означает автоматического обучения модели. Обучение и изменение логики должны быть отдельными проверяемыми процедурами.&lt;br /&gt;
&lt;br /&gt;
=== Полуавтоматическая модерация ===&lt;br /&gt;
&lt;br /&gt;
Автоматические действия возможны только после оценки качества на реальных примерах.&lt;br /&gt;
&lt;br /&gt;
Для каждой категории необходимо определить:&lt;br /&gt;
&lt;br /&gt;
* допустимые действия;&lt;br /&gt;
* условия передачи решения человеку;&lt;br /&gt;
* ограничения автоматизации;&lt;br /&gt;
* порядок отмены;&lt;br /&gt;
* журнал действий;&lt;br /&gt;
* критерии отключения при ошибках.&lt;br /&gt;
&lt;br /&gt;
Числовая оценка уверенности модели сама по себе не является достаточным основанием для наказания.&lt;br /&gt;
&lt;br /&gt;
=== Репутация пользователей ===&lt;br /&gt;
&lt;br /&gt;
В перспективе система сможет учитывать:&lt;br /&gt;
&lt;br /&gt;
* предупреждения;&lt;br /&gt;
* подтверждённые муты и баны;&lt;br /&gt;
* повторяемость нарушений;&lt;br /&gt;
* отменённые решения;&lt;br /&gt;
* периоды без нарушений.&lt;br /&gt;
&lt;br /&gt;
Репутация рассматривается как дополнительный контекст. Она не должна автоматически превращать любое сообщение пользователя в нарушение.&lt;br /&gt;
&lt;br /&gt;
=== Анализ конфликтов ===&lt;br /&gt;
&lt;br /&gt;
Планируется анализ последовательности сообщений нескольких участников.&lt;br /&gt;
&lt;br /&gt;
Цель — обнаруживать развитие конфликта и предлагать своевременное вмешательство модераторов.&lt;br /&gt;
&lt;br /&gt;
Возможные действия:&lt;br /&gt;
&lt;br /&gt;
* рекомендация прекратить спор;&lt;br /&gt;
* уведомление администрации;&lt;br /&gt;
* передача контекста на рассмотрение.&lt;br /&gt;
&lt;br /&gt;
== Аналитика сообщества ==&lt;br /&gt;
&lt;br /&gt;
На последующих этапах Кузя сможет формировать:&lt;br /&gt;
&lt;br /&gt;
* статистику сообщений;&lt;br /&gt;
* число активных участников;&lt;br /&gt;
* сведения о новых участниках;&lt;br /&gt;
* статистику предупреждений и других действий;&lt;br /&gt;
* основные темы обсуждения;&lt;br /&gt;
* ежедневные дайджесты.&lt;br /&gt;
&lt;br /&gt;
Пример будущего дайджеста:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Итоги дня&lt;br /&gt;
&lt;br /&gt;
Основные обсуждения:&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
Полезные ссылки:&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
Модерация:&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
Вопросы, требующие внимания администрации:&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При формировании отчётов необходимо различать фактическую статистику из БД и выводы AI.&lt;br /&gt;
&lt;br /&gt;
== Знание правил сообщества ==&lt;br /&gt;
&lt;br /&gt;
Планируется включение действующих правил конкретного чата в контекст ответов.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, можно здесь публиковать ссылку на YouTube?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ должен опираться на правила выбранного сообщества.&lt;br /&gt;
&lt;br /&gt;
Для объяснения модерации желательно указывать:&lt;br /&gt;
&lt;br /&gt;
* применённый пункт правил;&lt;br /&gt;
* основание решения;&lt;br /&gt;
* источник решения — человек, правило или AI;&lt;br /&gt;
* возможность пересмотра администрацией.&lt;br /&gt;
&lt;br /&gt;
== Разделение Кузи и RAMBA Bot ==&lt;br /&gt;
&lt;br /&gt;
Кузя специализируется на Telegram-сообществе:&lt;br /&gt;
&lt;br /&gt;
* участники;&lt;br /&gt;
* правила;&lt;br /&gt;
* диалоги;&lt;br /&gt;
* история;&lt;br /&gt;
* модерация;&lt;br /&gt;
* аналитика.&lt;br /&gt;
&lt;br /&gt;
Управление серверами и инфраструктурой относится к отдельному &#039;&#039;&#039;RAMBA Bot&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Целевая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя                         RAMBA Bot&lt;br /&gt;
 |                               |&lt;br /&gt;
 | сообщество                    | инфраструктура&lt;br /&gt;
 |                               |&lt;br /&gt;
 +---------------+---------------+&lt;br /&gt;
                 |&lt;br /&gt;
                 v&lt;br /&gt;
           RAMBA AI Router&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Общий AI-бэкенд не означает общие права доступа или смешивание контекста двух ботов.&lt;br /&gt;
&lt;br /&gt;
== Принципы проекта ==&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Сохранять существующие функции.&#039;&#039;&#039; Завершить и проверить перенос Legacy перед заменой стабильной версии.&lt;br /&gt;
# &#039;&#039;&#039;Сохранять архив.&#039;&#039;&#039; Не терять историю MySQL, предупреждения и связи между данными.&lt;br /&gt;
# &#039;&#039;&#039;Разделять готовое и запланированное.&#039;&#039;&#039; Документировать реализацию, тестирование и развёртывание отдельно.&lt;br /&gt;
# &#039;&#039;&#039;Сохранять контроль администрации.&#039;&#039;&#039; Решения должны быть объяснимыми и доступными для пересмотра.&lt;br /&gt;
# &#039;&#039;&#039;Вводить автоматизацию постепенно.&#039;&#039;&#039; Сначала наблюдение и оценка качества, затем ограниченные действия.&lt;br /&gt;
# &#039;&#039;&#039;Развивать локальный AI как целевую основу.&#039;&#039;&#039; Подключение Router проводить отдельным проверяемым этапом.&lt;br /&gt;
# &#039;&#039;&#039;Сохранять специализацию Кузи.&#039;&#039;&#039; Инфраструктурные задачи выносить в RAMBA Bot.&lt;br /&gt;
# &#039;&#039;&#039;Фиксировать рабочие этапы.&#039;&#039;&#039; Сохранять изменения в Git и обновлять документацию по подтверждённым результатам.&lt;br /&gt;
&lt;br /&gt;
== Конечная цель ==&lt;br /&gt;
&lt;br /&gt;
Кузя должен стать помощником сообщества, который:&lt;br /&gt;
&lt;br /&gt;
* выполняет административные команды;&lt;br /&gt;
* помогает участникам;&lt;br /&gt;
* находит накопленные знания;&lt;br /&gt;
* поддерживает содержательный диалог;&lt;br /&gt;
* предлагает модераторам обоснованные решения;&lt;br /&gt;
* формирует полезные отчёты;&lt;br /&gt;
* оставляет окончательный контроль за администрацией.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ближайшая практическая цель — завершить Kuzya 2.0, подтвердить паритет с Legacy и сохранить существующий архив.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA]]&lt;br /&gt;
[[Категория:RAMBA AI]]&lt;br /&gt;
[[Категория:Telegram]]&lt;br /&gt;
[[Категория:Боты]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=HAPP_Gateway&amp;diff=154</id>
		<title>HAPP Gateway</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=HAPP_Gateway&amp;diff=154"/>
		<updated>2026-09-16T21:24:22Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot; |- ! style=&amp;quot;background:#d9ead3; width:220px;&amp;quot; | Статус | &amp;#039;&amp;#039;&amp;#039;PRODUCTION / ACTIVE&amp;#039;&amp;#039;&amp;#039; |- ! Текущий режим | Automatic healthcheck + hourly optimization |- ! Основной идентификатор | &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt; |- ! Автопереключение | Включено |- ! Rollback | Включён |- ! Healthcheck | Каждые ~3 минуты |- ! Optimizer | Примерно 1 раз в ч...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;background:#d9ead3; width:220px;&amp;quot; | Статус&lt;br /&gt;
| &#039;&#039;&#039;PRODUCTION / ACTIVE&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
! Текущий режим&lt;br /&gt;
| Automatic healthcheck + hourly optimization&lt;br /&gt;
|-&lt;br /&gt;
! Основной идентификатор&lt;br /&gt;
| &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
! Автопереключение&lt;br /&gt;
| Включено&lt;br /&gt;
|-&lt;br /&gt;
! Rollback&lt;br /&gt;
| Включён&lt;br /&gt;
|-&lt;br /&gt;
! Healthcheck&lt;br /&gt;
| Каждые ~3 минуты&lt;br /&gt;
|-&lt;br /&gt;
! Optimizer&lt;br /&gt;
| Примерно 1 раз в час&lt;br /&gt;
|-&lt;br /&gt;
! Порог переключения&lt;br /&gt;
| 15%&lt;br /&gt;
|-&lt;br /&gt;
! Последнее документирование&lt;br /&gt;
| 17.09.2026&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= HAPP Gateway: автоматический выбор сервера и отказоустойчивость =&lt;br /&gt;
&lt;br /&gt;
== Назначение ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HAPP Gateway&#039;&#039;&#039; — шлюз для выборочной маршрутизации трафика через HAPP/VLESS.&lt;br /&gt;
&lt;br /&gt;
Система работает в LXC-контейнере и предоставляет одновременно:&lt;br /&gt;
&lt;br /&gt;
* локальный HTTP proxy;&lt;br /&gt;
* локальный SOCKS proxy;&lt;br /&gt;
* HTTP/SOCKS proxy для устройств локальной сети;&lt;br /&gt;
* TUN-интерфейс для policy routing;&lt;br /&gt;
* автоматический контроль работоспособности HAPP;&lt;br /&gt;
* автоматическое обновление подписки;&lt;br /&gt;
* автоматический benchmark доступных серверов;&lt;br /&gt;
* автоматическое аварийное переключение;&lt;br /&gt;
* периодическую оптимизацию выбора сервера.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр !! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Контейнер || &amp;lt;code&amp;gt;happ-gateway&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| IP || &amp;lt;code&amp;gt;192.168.1.52&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ОС || Debian 13&lt;br /&gt;
|-&lt;br /&gt;
| HAPP CLI || &amp;lt;code&amp;gt;/usr/local/bin/happ&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| HAPP home || &amp;lt;code&amp;gt;/root/.config/happ-cli&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| HTTP proxy локальный || &amp;lt;code&amp;gt;127.0.0.1:10809&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SOCKS proxy локальный || &amp;lt;code&amp;gt;127.0.0.1:10808&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| HTTP proxy LAN || &amp;lt;code&amp;gt;192.168.1.52:11081&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| SOCKS proxy LAN || &amp;lt;code&amp;gt;192.168.1.52:11080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| TUN interface || &amp;lt;code&amp;gt;thapp&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Policy routing table || &amp;lt;code&amp;gt;100&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Основные задачи системы:&lt;br /&gt;
&lt;br /&gt;
* автоматически контролировать работоспособность текущего HAPP-сервера;&lt;br /&gt;
* обновлять список серверов;&lt;br /&gt;
* тестировать доступные серверы;&lt;br /&gt;
* выбирать наиболее быстрый рабочий сервер;&lt;br /&gt;
* автоматически переключаться при отказе;&lt;br /&gt;
* не переключаться без необходимости;&lt;br /&gt;
* синхронизировать Proxy и TUN;&lt;br /&gt;
* сохранять прямой маршрут до upstream HAPP-сервера;&lt;br /&gt;
* не допускать рекурсивной маршрутизации HAPP через самого себя;&lt;br /&gt;
* автоматически очищать временные маршруты после benchmark;&lt;br /&gt;
* выполнять проверку нового сервера после переключения;&lt;br /&gt;
* выполнять rollback при неудачном переключении.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Общая схема ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                         Internet&lt;br /&gt;
                            ^&lt;br /&gt;
                            |&lt;br /&gt;
                      HAPP upstream&lt;br /&gt;
                            ^&lt;br /&gt;
                            |&lt;br /&gt;
                  direct route table 100&lt;br /&gt;
                            ^&lt;br /&gt;
                            |&lt;br /&gt;
                 +-------------------+&lt;br /&gt;
                 |   happ-gateway    |&lt;br /&gt;
                 |   192.168.1.52    |&lt;br /&gt;
                 +-------------------+&lt;br /&gt;
                     |           |&lt;br /&gt;
                Proxy mode     TUN mode&lt;br /&gt;
                     |           |&lt;br /&gt;
             127.0.0.1:10809    thapp&lt;br /&gt;
             127.0.0.1:10808&lt;br /&gt;
                     |&lt;br /&gt;
                  socat LAN&lt;br /&gt;
                     |&lt;br /&gt;
          +----------+----------+&lt;br /&gt;
          |                     |&lt;br /&gt;
      HTTP 11081            SOCKS 11080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Управление системой выполняют два независимых контура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                +----------------------+&lt;br /&gt;
                |     HAPP CONTROL     |&lt;br /&gt;
                +----------------------+&lt;br /&gt;
                    |              |&lt;br /&gt;
                    |              |&lt;br /&gt;
             HEALTHCHECK        OPTIMIZER&lt;br /&gt;
             ~3 минуты          ~1 час&lt;br /&gt;
                    |              |&lt;br /&gt;
                    +------+-------+&lt;br /&gt;
                           |&lt;br /&gt;
                     HAPP SWITCH&lt;br /&gt;
                           |&lt;br /&gt;
                     Proxy + TUN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Основные systemd-службы ==&lt;br /&gt;
&lt;br /&gt;
=== happ-gateway.service ===&lt;br /&gt;
&lt;br /&gt;
Основной HAPP Proxy.&lt;br /&gt;
&lt;br /&gt;
Файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/happ-gateway.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример текущей команды запуска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ExecStart=/usr/local/bin/happ \&lt;br /&gt;
  --home /root/.config/happ-cli \&lt;br /&gt;
  connect 60 \&lt;br /&gt;
  --mode proxy \&lt;br /&gt;
  --socks 10808 \&lt;br /&gt;
  --http 10809&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перед запуском выполняются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ExecStartPre=/usr/local/sbin/happ-wait-network.sh&lt;br /&gt;
ExecStartPre=/usr/local/sbin/happ-prep-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;happ-prep-routes.sh&amp;lt;/code&amp;gt; подготавливает прямые маршруты, необходимые HAPP до создания Proxy/TUN.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== happ-tun.service ===&lt;br /&gt;
&lt;br /&gt;
Запускает HAPP в режиме TUN.&lt;br /&gt;
&lt;br /&gt;
Файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/happ-tun.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ExecStart=/usr/local/bin/happ \&lt;br /&gt;
  --home /root/.config/happ-cli \&lt;br /&gt;
  connect 60 \&lt;br /&gt;
  --mode tun&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перед запуском также выполняется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ExecStartPre=/usr/local/sbin/happ-wait-network.sh&lt;br /&gt;
ExecStartPre=/usr/local/sbin/happ-prep-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После создания TUN-интерфейса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ExecStartPost=/usr/local/sbin/happ-tun-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== happ-http.service ===&lt;br /&gt;
&lt;br /&gt;
Публикует HTTP proxy в локальную сеть.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.1.52:11081&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
127.0.0.1:10809&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Используется &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Служба связана с &amp;lt;code&amp;gt;happ-gateway.service&amp;lt;/code&amp;gt;, поэтому при перезапуске основного gateway LAN proxy также перезапускается.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== happ-socat.service ===&lt;br /&gt;
&lt;br /&gt;
Публикует SOCKS proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.1.52:11080&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
127.0.0.1:10808&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также используется &amp;lt;code&amp;gt;socat&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Идентификация серверов ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно: HAPP ID нельзя считать постоянным идентификатором сервера.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
После обновления подписки номера HAPP могут измениться.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №8 -&amp;gt; HAPP #60&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После следующего обновления подписки тот же сервер теоретически может получить другой ID:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №8 -&amp;gt; HAPP #47&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому постоянным логическим идентификатором системы является:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=N&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HAPP ID считается временным.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние ==&lt;br /&gt;
&lt;br /&gt;
Состояние production хранится в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/lib/happ/current&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=8&lt;br /&gt;
ID=60&lt;br /&gt;
ENDPOINT=selec180.apruxdomain.website:444&lt;br /&gt;
UPDATED=2026-09-16T23:43:32+03:00&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Поле !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt; || Постоянный логический номер обхода&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ID&amp;lt;/code&amp;gt; || Текущий временный HAPP ID&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ENDPOINT&amp;lt;/code&amp;gt; || Текущий upstream endpoint&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UPDATED&amp;lt;/code&amp;gt; || Время последнего изменения production mapping&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Почему нельзя использовать только endpoint ==&lt;br /&gt;
&lt;br /&gt;
В подписке могут существовать несколько записей с одним и тем же endpoint.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HAPP #43  selec180.apruxdomain.website:444  АВТО ОБХОД&lt;br /&gt;
HAPP #60  selec180.apruxdomain.website:444  ОБХОД №8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому endpoint также не является достаточным идентификатором.&lt;br /&gt;
&lt;br /&gt;
Для production используется именно явный тег:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №N&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Автоматические записи вида:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
АВТО ОБХОД&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
не используются системой автоматического выбора.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Resolver BYPASS -&amp;gt; HAPP ID ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-resolve-bypass.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Назначение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №8&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
актуальный список HAPP&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
ID / protocol / endpoint&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-resolve-bypass.sh 8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=8&lt;br /&gt;
ID=60&lt;br /&gt;
PROTOCOL=vless&lt;br /&gt;
ENDPOINT=selec180.apruxdomain.website:444&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом остальные компоненты системы работают с постоянным &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt;, а resolver определяет актуальный HAPP ID.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Подготовка маршрутов ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-prep-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он динамически определяет:&lt;br /&gt;
&lt;br /&gt;
* IP сервера подписки;&lt;br /&gt;
* IP текущего HAPP upstream;&lt;br /&gt;
* текущий endpoint HAPP;&lt;br /&gt;
* необходимые direct routes.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DIRECT: sub.renawave.space -&amp;gt; 37.9.4.201 via 192.168.1.1 dev eth0 table 100&lt;br /&gt;
DIRECT: selec180.apruxdomain.website -&amp;gt; 31.129.42.180 via 192.168.1.1 dev eth0 table 100&lt;br /&gt;
&lt;br /&gt;
Current HAPP server #60 endpoint selec180.apruxdomain.website:444 prepared&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это критически важно.&lt;br /&gt;
&lt;br /&gt;
Без direct route может возникнуть рекурсивная маршрутизация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HAPP upstream&lt;br /&gt;
     ^&lt;br /&gt;
     |&lt;br /&gt;
    HAPP&lt;br /&gt;
     ^&lt;br /&gt;
     |&lt;br /&gt;
   thapp&lt;br /&gt;
     ^&lt;br /&gt;
     |&lt;br /&gt;
    HAPP&lt;br /&gt;
     ^&lt;br /&gt;
     |&lt;br /&gt;
   thapp&lt;br /&gt;
    ...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть HAPP пытается подключиться к собственному upstream через собственный TUN.&lt;br /&gt;
&lt;br /&gt;
Результатом становятся timeout, TLS error или полная потеря доступа к upstream.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Policy routing ==&lt;br /&gt;
&lt;br /&gt;
Используется routing table:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основная схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.0.0.0/1 dev thapp&lt;br /&gt;
128.0.0.0/1 dev thapp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть основной интернет-трафик направляется через HAPP TUN.&lt;br /&gt;
&lt;br /&gt;
Локальные/служебные сети обходят TUN.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.0.0.0/8 via 192.168.1.1 dev eth0&lt;br /&gt;
172.16.0.0/12 via 192.168.1.1 dev eth0&lt;br /&gt;
192.168.0.0/16 via 192.168.1.1 dev eth0&lt;br /&gt;
&lt;br /&gt;
10.20.0.0/24 via 192.168.1.53 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Дополнительно динамически создаются прямые маршруты до:&lt;br /&gt;
&lt;br /&gt;
* текущего HAPP upstream;&lt;br /&gt;
* сервера подписки.&lt;br /&gt;
&lt;br /&gt;
Пример состояния на момент документирования:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
31.129.42.180 via 192.168.1.1 dev eth0&lt;br /&gt;
37.9.4.201 via 192.168.1.1 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ip route show table 100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039; IP-адреса &amp;lt;code&amp;gt;31.129.42.180&amp;lt;/code&amp;gt; и &amp;lt;code&amp;gt;37.9.4.201&amp;lt;/code&amp;gt; приведены как пример состояния системы на момент документирования. Они разрешаются динамически и могут измениться.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== happ-tun-routes.sh ==&lt;br /&gt;
&lt;br /&gt;
Файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-tun-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После финальной очистки конфигурации в нём больше нет IP конкретных HAPP-серверов или сервера подписки.&lt;br /&gt;
&lt;br /&gt;
Сохраняются только инфраструктурные маршруты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.1.0/24&lt;br /&gt;
10.20.0.0/24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример логики:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    192.168.1.0/24 dev eth0 src 192.168.1.52&lt;br /&gt;
&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    10.20.0.0/24 via 192.168.1.53 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом смена HAPP upstream не требует ручного изменения &amp;lt;code&amp;gt;happ-tun-routes.sh&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Обновление подписки ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-refresh-current.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
прочитать текущий BYPASS&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
direct route к subscription&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
happ sub update ramba&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
найти тот же ОБХОД №N&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
получить актуальный HAPP ID&lt;br /&gt;
        |&lt;br /&gt;
        +---- ID/endpoint не изменились&lt;br /&gt;
        |            |&lt;br /&gt;
        |            v&lt;br /&gt;
        |      ничего не перезапускать&lt;br /&gt;
        |&lt;br /&gt;
        +---- mapping изменился&lt;br /&gt;
                     |&lt;br /&gt;
                     v&lt;br /&gt;
             обновить systemd units&lt;br /&gt;
                     |&lt;br /&gt;
                     v&lt;br /&gt;
                  restart&lt;br /&gt;
                     |&lt;br /&gt;
                     v&lt;br /&gt;
                   verify&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Current selection: ОБХОД №8&lt;br /&gt;
Old ID:       #60&lt;br /&gt;
New ID:       #60&lt;br /&gt;
Old endpoint: selec180.apruxdomain.website:444&lt;br /&gt;
New endpoint: selec180.apruxdomain.website:444&lt;br /&gt;
&lt;br /&gt;
REFRESH OK: mapping unchanged&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если mapping не изменился, production не перезапускается.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Benchmark серверов ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-benchmark.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Benchmark проверяет только явно заданные серверы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №1&lt;br /&gt;
ОБХОД №2&lt;br /&gt;
ОБХОД №3&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Записи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
АВТО ОБХОД&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
исключаются.&lt;br /&gt;
&lt;br /&gt;
Протокол &amp;lt;code&amp;gt;hysteria2&amp;lt;/code&amp;gt; в текущей реализации benchmark пропускается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SKIP (hysteria2)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестируются VLESS-кандидаты.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Алгоритм benchmark ==&lt;br /&gt;
&lt;br /&gt;
Для каждого кандидата выполняется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
endpoint&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
direct /32 route&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
temporary HAPP proxy&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
warm-up&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
Telegram request x3&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
median&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
WORKING / REJECTED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основная проверка выполняется запросом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://api.telegram.org&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Рабочий результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTP 302&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ping или обычное TCP-соединение не используются как основной критерий.&lt;br /&gt;
&lt;br /&gt;
Таким образом проверяется не просто доступность IP, а реальное прохождение HTTPS-трафика через конкретный HAPP-сервер.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Расчёт скорости ==&lt;br /&gt;
&lt;br /&gt;
Для каждого кандидата выполняется три теста.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
test 1: 0.201306s OK&lt;br /&gt;
test 2: 0.221358s OK&lt;br /&gt;
test 3: 5.189619s OK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Используется медиана:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MEDIAN: 0.221358s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет уменьшить влияние одиночного всплеска задержки.&lt;br /&gt;
&lt;br /&gt;
Для признания сервера рабочим требуется не менее двух успешных запросов из трёх.&lt;br /&gt;
&lt;br /&gt;
Если условие не выполняется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
REJECTED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Пример результата benchmark ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WORKING BYPASS SERVERS&lt;br /&gt;
&lt;br /&gt;
ОБХОД №5  HAPP #57  188.225.82.56:7443                0.221358s&lt;br /&gt;
ОБХОД №8  HAPP #60  selec180.apruxdomain.website:444  0.223532s&lt;br /&gt;
ОБХОД №4  HAPP #56  188.225.58.133:7443               0.366614s&lt;br /&gt;
ОБХОД №13 HAPP #65  selec248.apruxdomain.website:444  0.611755s&lt;br /&gt;
&lt;br /&gt;
BEST: BYPASS=5 ID=57 ENDPOINT=188.225.82.56:7443 MEDIAN=0.221358s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Очистка временных маршрутов ==&lt;br /&gt;
&lt;br /&gt;
Во время benchmark для каждого upstream создаётся временный direct &amp;lt;code&amp;gt;/32&amp;lt;/code&amp;gt; route.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
188.225.82.56/32&lt;br /&gt;
188.225.58.133/32&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После завершения benchmark временные candidate routes автоматически удаляются.&lt;br /&gt;
&lt;br /&gt;
Cleanup сначала завершает временный HAPP-процесс benchmark, затем удаляет созданные маршруты.&lt;br /&gt;
&lt;br /&gt;
После очистки вызывается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-prep-routes.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он повторно создаёт необходимые production routes.&lt;br /&gt;
&lt;br /&gt;
Нормальное состояние после benchmark содержит только необходимые dynamic direct routes.&lt;br /&gt;
&lt;br /&gt;
Пример на момент документирования:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
31.129.42.180 via 192.168.1.1 dev eth0&lt;br /&gt;
37.9.4.201 via 192.168.1.1 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Временные маршруты других кандидатов после benchmark отсутствуют.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Переключение HAPP-сервера ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-switch.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На вход передаётся &#039;&#039;&#039;BYPASS&#039;&#039;&#039;, а не HAPP ID.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-switch.sh 8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ОБХОД №8&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
resolver&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
актуальный HAPP ID&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
direct route&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
backup конфигурации&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
обновление gateway + TUN&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
restart Proxy&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
Telegram readiness check&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
restart TUN&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
LAN Telegram check&lt;br /&gt;
    |&lt;br /&gt;
    +-------- OK --------&amp;gt; сохранить state&lt;br /&gt;
    |&lt;br /&gt;
    +-------- FAIL ------&amp;gt; rollback&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После запуска нового Proxy выполняется readiness-loop.&lt;br /&gt;
&lt;br /&gt;
Пример успешной проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTP=302&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Только после успешной проверки Proxy выполняется переключение TUN.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Rollback ==&lt;br /&gt;
&lt;br /&gt;
Перед переключением создаются резервные копии:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;happ-gateway.service&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;happ-tun.service&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;/var/lib/happ/current&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Если новый сервер не проходит проверку, выполняется автоматический rollback.&lt;br /&gt;
&lt;br /&gt;
При rollback старый BYPASS заново разрешается через актуальный список подписки.&lt;br /&gt;
&lt;br /&gt;
Это важно, потому что старый HAPP ID после обновления подписки уже мог измениться.&lt;br /&gt;
&lt;br /&gt;
Логика:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
new server&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
verification&lt;br /&gt;
    |&lt;br /&gt;
 +--+--+&lt;br /&gt;
 |     |&lt;br /&gt;
OK    FAIL&lt;br /&gt;
 |     |&lt;br /&gt;
save  resolve old BYPASS&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
    restore&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
    restart&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Healthcheck ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-healthcheck.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Systemd timer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-healthcheck.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Период проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
примерно каждые 3 минуты&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяется реальный Telegram-запрос через production HTTP proxy.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HEALTHY: Telegram HTTP=302 TIME=0.212754s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Счётчик последовательных ошибок хранится:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/var/lib/happ/fail-count&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной проверке:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fail-count = 0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Аварийное восстановление ==&lt;br /&gt;
&lt;br /&gt;
Одна ошибка не приводит к немедленному переключению.&lt;br /&gt;
&lt;br /&gt;
Используется защита от случайных кратковременных сбоев.&lt;br /&gt;
&lt;br /&gt;
Алгоритм:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram check&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
    FAIL&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
fail-count = 1&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
    ждать&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
следующий healthcheck&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
    FAIL&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
fail-count = 2&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
refresh subscription&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
benchmark&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
best working BYPASS&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
switch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом переключение выполняется после двух последовательных ошибок.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Hourly Optimizer ==&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-optimizer.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Systemd timer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-optimizer.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Период:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
примерно один раз в час&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Используется также:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RandomizedDelaySec=5min&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому фактическое время запуска может немного отличаться от ровного часа.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Алгоритм Optimizer ==&lt;br /&gt;
&lt;br /&gt;
Optimizer выполняет:&lt;br /&gt;
&lt;br /&gt;
# обновление подписки;&lt;br /&gt;
# синхронизацию текущего BYPASS;&lt;br /&gt;
# benchmark доступных серверов;&lt;br /&gt;
# определение median текущего сервера;&lt;br /&gt;
# определение BEST;&lt;br /&gt;
# сравнение производительности;&lt;br /&gt;
# принятие решения KEEP/SWITCH.&lt;br /&gt;
&lt;br /&gt;
Схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sub update&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
sync current BYPASS&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
benchmark&lt;br /&gt;
    |&lt;br /&gt;
    +---------------------+&lt;br /&gt;
    |                     |&lt;br /&gt;
    v                     v&lt;br /&gt;
CURRENT                 BEST&lt;br /&gt;
    |                     |&lt;br /&gt;
    +----------+----------+&lt;br /&gt;
               |&lt;br /&gt;
               v&lt;br /&gt;
          comparison&lt;br /&gt;
               |&lt;br /&gt;
         +-----+-----+&lt;br /&gt;
         |           |&lt;br /&gt;
        KEEP       SWITCH&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Защита от постоянных переключений ==&lt;br /&gt;
&lt;br /&gt;
Используется порог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
MIN_GAIN_PERCENT=15&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Новый сервер должен быть минимум на 15% быстрее текущего.&lt;br /&gt;
&lt;br /&gt;
Если выигрыш меньше 15%, переключение не выполняется.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Current: ОБХОД №8&lt;br /&gt;
Best:    ОБХОД №5 (0.221358s)&lt;br /&gt;
&lt;br /&gt;
Current median: 0.223532s&lt;br /&gt;
Improvement: 0.97%&lt;br /&gt;
Required:    15%&lt;br /&gt;
&lt;br /&gt;
KEEP: improvement is below threshold.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это предотвращает бессмысленные переключения из-за разницы в несколько миллисекунд.&lt;br /&gt;
&lt;br /&gt;
Если текущий сервер вообще не проходит benchmark, правило 15% не применяется.&lt;br /&gt;
&lt;br /&gt;
В этом случае выполняется аварийное переключение на лучший рабочий BYPASS.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Блокировка параллельных операций ==&lt;br /&gt;
&lt;br /&gt;
Управляющие скрипты используют общий lock-файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/run/happ-control.lock&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
через:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
flock&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он защищает основные управляющие операции от параллельного выполнения.&lt;br /&gt;
&lt;br /&gt;
При передаче управления в &amp;lt;code&amp;gt;happ-switch.sh&amp;lt;/code&amp;gt; вызывающий контроллер освобождает блокировку, после чего &amp;lt;code&amp;gt;happ-switch.sh&amp;lt;/code&amp;gt; получает её самостоятельно.&lt;br /&gt;
&lt;br /&gt;
Это существенно снижает риск одновременного выполнения:&lt;br /&gt;
&lt;br /&gt;
* healthcheck;&lt;br /&gt;
* optimizer;&lt;br /&gt;
* ручного switch.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Текущий production ==&lt;br /&gt;
&lt;br /&gt;
На момент документирования:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=8&lt;br /&gt;
HAPP ID=60&lt;br /&gt;
Endpoint=selec180.apruxdomain.website:444&lt;br /&gt;
Resolved IP=31.129.42.180&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Типичная измеренная задержка Telegram:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
~0.2–0.3 сек&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Важно:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;HAPP ID=60&amp;lt;/code&amp;gt; не является постоянным.&lt;br /&gt;
&lt;br /&gt;
Также IP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
31.129.42.180&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
является результатом DNS-разрешения endpoint на момент документирования и может измениться.&lt;br /&gt;
&lt;br /&gt;
Постоянным логическим идентификатором является:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Systemd timers ==&lt;br /&gt;
&lt;br /&gt;
Проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl list-timers --all --no-pager | grep happ&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Нормальное состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-healthcheck.timer   active&lt;br /&gt;
happ-optimizer.timer     active&lt;br /&gt;
happ-autoselect.timer    inactive&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Старый:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-autoselect.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
оставлен выключенным.&lt;br /&gt;
&lt;br /&gt;
Он не учитывает новую модель:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS -&amp;gt; dynamic HAPP ID&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и не должен использоваться совместно с новой системой.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Быстрая диагностика ==&lt;br /&gt;
&lt;br /&gt;
=== Проверить production ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-healthcheck.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HEALTHY: Telegram HTTP=302 TIME=...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить текущее состояние ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cat /var/lib/happ/current&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
BYPASS=8&lt;br /&gt;
ID=60&lt;br /&gt;
ENDPOINT=selec180.apruxdomain.website:444&lt;br /&gt;
UPDATED=...&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить маршруты ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ip route show table 100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить Proxy из LAN ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
curl --max-time 8 \&lt;br /&gt;
  -x http://192.168.1.52:11081 \&lt;br /&gt;
  -o /dev/null -sS \&lt;br /&gt;
  -w &#039;HTTP=%{http_code} TIME=%{time_total}s\n&#039; \&lt;br /&gt;
  https://api.telegram.org&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HTTP=302&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить HAPP список ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/bin/happ \&lt;br /&gt;
  --home /root/.config/happ-cli \&lt;br /&gt;
  list&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить конкретный BYPASS ===&lt;br /&gt;
&lt;br /&gt;
Например, ОБХОД №8:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-resolve-bypass.sh 8&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Обновить подписку и синхронизировать production ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-refresh-current.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Запустить benchmark вручную ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-benchmark.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Benchmark &#039;&#039;&#039;не переключает&#039;&#039;&#039; production самостоятельно.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Запустить optimizer вручную ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-optimizer.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Optimizer уже может принять решение о переключении.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Переключиться вручную ===&lt;br /&gt;
&lt;br /&gt;
Например, на ОБХОД №5:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-switch.sh 5&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перед ручным переключением желательно убедиться, что выбранный BYPASS присутствует в актуальной подписке.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить службы ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl status happ-gateway \&lt;br /&gt;
  happ-tun \&lt;br /&gt;
  happ-http \&lt;br /&gt;
  happ-socat \&lt;br /&gt;
  --no-pager&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Проверить таймеры ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemctl status happ-healthcheck.timer --no-pager&lt;br /&gt;
systemctl status happ-optimizer.timer --no-pager&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Последние логи healthcheck ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
journalctl -u happ-healthcheck.service -n 50 --no-pager&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Последние логи optimizer ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
journalctl -u happ-optimizer.service -n 100 --no-pager&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Основные файлы ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Файл !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-wait-network.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Ожидание готовности сети&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-prep-routes.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Подготовка dynamic direct routes&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-tun-routes.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Базовые маршруты после запуска TUN&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-resolve-bypass.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| BYPASS -&amp;gt; ID / protocol / endpoint&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-refresh-current.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Обновление подписки и синхронизация текущего BYPASS&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-benchmark.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Benchmark HAPP-серверов&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-switch.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Безопасное переключение production&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-healthcheck.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Аварийный контроль production&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/usr/local/sbin/happ-optimizer.sh&amp;lt;/code&amp;gt;&lt;br /&gt;
| Плановый выбор более быстрого сервера&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/var/lib/happ/current&amp;lt;/code&amp;gt;&lt;br /&gt;
| Текущее production-состояние&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/var/lib/happ/fail-count&amp;lt;/code&amp;gt;&lt;br /&gt;
| Счётчик последовательных отказов&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;/run/happ-control.lock&amp;lt;/code&amp;gt;&lt;br /&gt;
| Блокировка управляющих операций&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Основные systemd units ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Unit !! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-gateway.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Основной HTTP/SOCKS HAPP Proxy&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-tun.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| HAPP TUN&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-http.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публикация HTTP proxy в LAN&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-socat.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Публикация SOCKS proxy в LAN&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-healthcheck.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Проверка production&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-healthcheck.timer&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запуск healthcheck примерно каждые 3 минуты&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-optimizer.service&amp;lt;/code&amp;gt;&lt;br /&gt;
| Полный цикл оптимизации&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-optimizer.timer&amp;lt;/code&amp;gt;&lt;br /&gt;
| Запуск optimizer примерно раз в час&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-autoselect.timer&amp;lt;/code&amp;gt;&lt;br /&gt;
| Старый механизм — отключён&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Логика системы целиком ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                           HAPP Gateway&lt;br /&gt;
                                |&lt;br /&gt;
              +-----------------+-----------------+&lt;br /&gt;
              |                                   |&lt;br /&gt;
        каждые ~3 мин                       каждый ~1 час&lt;br /&gt;
         HEALTHCHECK                           OPTIMIZER&lt;br /&gt;
              |                                   |&lt;br /&gt;
              v                                   v&lt;br /&gt;
      Telegram через Proxy                   sub update&lt;br /&gt;
              |                                   |&lt;br /&gt;
        +-----+-----+                             v&lt;br /&gt;
        |           |                        sync BYPASS&lt;br /&gt;
        |           |                             |&lt;br /&gt;
     HEALTHY       FAIL                           v&lt;br /&gt;
        |           |                         benchmark&lt;br /&gt;
        |           |                             |&lt;br /&gt;
      ничего    первый FAIL                 +-----+-----+&lt;br /&gt;
                    |                       |           |&lt;br /&gt;
                  ждать                  CURRENT       BEST&lt;br /&gt;
                    |                       |           |&lt;br /&gt;
               следующий check              +-----+-----+&lt;br /&gt;
                    |                             |&lt;br /&gt;
                  FAIL                            v&lt;br /&gt;
                    |                         comparison&lt;br /&gt;
                    v                             |&lt;br /&gt;
              второй FAIL                  +-----+-----+&lt;br /&gt;
                    |                       |           |&lt;br /&gt;
                    v                    &amp;lt; 15%        &amp;gt;= 15%&lt;br /&gt;
                 refresh                    |           |&lt;br /&gt;
                    |                       v           v&lt;br /&gt;
                    v                     KEEP       SWITCH&lt;br /&gt;
                benchmark                               |&lt;br /&gt;
                    |                                   |&lt;br /&gt;
                    v                                   |&lt;br /&gt;
             best working BYPASS                        |&lt;br /&gt;
                    |                                   |&lt;br /&gt;
                    v                                   |&lt;br /&gt;
                  SWITCH &amp;lt;------------------------------+&lt;br /&gt;
                    |&lt;br /&gt;
                    v&lt;br /&gt;
              resolve BYPASS&lt;br /&gt;
                    |&lt;br /&gt;
                    v&lt;br /&gt;
               direct route&lt;br /&gt;
                    |&lt;br /&gt;
                    v&lt;br /&gt;
              restart Proxy&lt;br /&gt;
                    |&lt;br /&gt;
                    v&lt;br /&gt;
             Telegram verify&lt;br /&gt;
                    |&lt;br /&gt;
              +-----+-----+&lt;br /&gt;
              |           |&lt;br /&gt;
             FAIL         OK&lt;br /&gt;
              |           |&lt;br /&gt;
              v           v&lt;br /&gt;
           rollback   restart TUN&lt;br /&gt;
                          |&lt;br /&gt;
                          v&lt;br /&gt;
                    LAN verification&lt;br /&gt;
                          |&lt;br /&gt;
                     +----+----+&lt;br /&gt;
                     |         |&lt;br /&gt;
                    FAIL       OK&lt;br /&gt;
                     |         |&lt;br /&gt;
                     v         v&lt;br /&gt;
                  rollback   SAVE STATE&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Проверенное production-состояние ==&lt;br /&gt;
&lt;br /&gt;
На момент завершения настройки система прошла полный цикл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
refresh subscription       OK&lt;br /&gt;
BYPASS resolution          OK&lt;br /&gt;
benchmark                  OK&lt;br /&gt;
temporary route cleanup    OK&lt;br /&gt;
optimizer decision         OK&lt;br /&gt;
production healthcheck     OK&lt;br /&gt;
Telegram HTTP 302          OK&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последний контрольный optimizer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Current: ОБХОД №8&lt;br /&gt;
Best:    ОБХОД №5&lt;br /&gt;
&lt;br /&gt;
Current median: 0.223532s&lt;br /&gt;
Best median:    0.221358s&lt;br /&gt;
&lt;br /&gt;
Improvement: 0.97%&lt;br /&gt;
Required:    15%&lt;br /&gt;
&lt;br /&gt;
KEEP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После benchmark таблица маршрутизации была автоматически очищена от временных candidate routes.&lt;br /&gt;
&lt;br /&gt;
Production после полного цикла:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HEALTHY&lt;br /&gt;
Telegram HTTP=302&lt;br /&gt;
TIME ~0.27s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Результат ==&lt;br /&gt;
&lt;br /&gt;
После внедрения новой схемы HAPP Gateway:&lt;br /&gt;
&lt;br /&gt;
* не зависит от постоянства HAPP ID;&lt;br /&gt;
* использует &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt; как постоянный логический идентификатор;&lt;br /&gt;
* автоматически обновляет подписку;&lt;br /&gt;
* синхронизирует BYPASS с актуальным HAPP ID;&lt;br /&gt;
* автоматически восстанавливает direct routes;&lt;br /&gt;
* предотвращает рекурсивную маршрутизацию upstream через HAPP TUN;&lt;br /&gt;
* контролирует реальную доступность Telegram;&lt;br /&gt;
* тестирует серверы через реальный HAPP proxy;&lt;br /&gt;
* использует медиану вместо одного измерения;&lt;br /&gt;
* требует минимум два успешных теста из трёх;&lt;br /&gt;
* не переключается при незначительной разнице скорости;&lt;br /&gt;
* автоматически переключается при отказе;&lt;br /&gt;
* синхронно обновляет Proxy и TUN;&lt;br /&gt;
* выполняет post-switch verification;&lt;br /&gt;
* поддерживает автоматический rollback;&lt;br /&gt;
* автоматически очищает временные benchmark routes;&lt;br /&gt;
* координирует управляющие операции через общий &amp;lt;code&amp;gt;flock&amp;lt;/code&amp;gt;;&lt;br /&gt;
* автоматически выполняет healthcheck примерно каждые 3 минуты;&lt;br /&gt;
* автоматически выполняет полную оптимизацию примерно раз в час.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Текущая схема считается production-ready.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== История конфигурации ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;17.09.2026&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* внедрён постоянный идентификатор &amp;lt;code&amp;gt;BYPASS&amp;lt;/code&amp;gt;;&lt;br /&gt;
* реализован resolver &amp;lt;code&amp;gt;BYPASS -&amp;gt; HAPP ID&amp;lt;/code&amp;gt;;&lt;br /&gt;
* реализовано динамическое обновление подписки;&lt;br /&gt;
* реализована автоматическая синхронизация HAPP ID;&lt;br /&gt;
* реализован benchmark VLESS-серверов;&lt;br /&gt;
* основной критерий проверки переведён на реальный HTTPS-запрос к Telegram;&lt;br /&gt;
* реализован расчёт median;&lt;br /&gt;
* реализован безопасный switch Proxy + TUN;&lt;br /&gt;
* реализован rollback;&lt;br /&gt;
* добавлен healthcheck timer;&lt;br /&gt;
* добавлен hourly optimizer;&lt;br /&gt;
* установлен порог переключения 15%;&lt;br /&gt;
* добавлена очистка временных &amp;lt;code&amp;gt;/32&amp;lt;/code&amp;gt; routes;&lt;br /&gt;
* удалены hardcoded upstream IP из &amp;lt;code&amp;gt;happ-tun-routes.sh&amp;lt;/code&amp;gt;;&lt;br /&gt;
* старый &amp;lt;code&amp;gt;happ-autoselect.timer&amp;lt;/code&amp;gt; отключён;&lt;br /&gt;
* выполнена финальная production-проверка.&lt;br /&gt;
&lt;br /&gt;
[[Категория:Infrastructure]]&lt;br /&gt;
[[Категория:VPN]]&lt;br /&gt;
[[Категория:HAPP]]&lt;br /&gt;
[[Категория:Networking]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=153</id>
		<title>Мониторинг</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=153"/>
		<updated>2026-09-10T21:56:33Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;rambamonitor /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;rambavpn /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;rambainfra /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=152</id>
		<title>Мониторинг</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=152"/>
		<updated>2026-09-10T21:27:27Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;rambamonitor /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;rambavpn /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_20Selective_VPN_Gateway&amp;diff=151</id>
		<title>RAMBA 20Selective VPN Gateway</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_20Selective_VPN_Gateway&amp;diff=151"/>
		<updated>2026-09-10T21:10:58Z</updated>

		<summary type="html">&lt;p&gt;Artem: Artem переименовал страницу RAMBA 20Selective VPN Gateway в RAMBA Selective VPN Gateway&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#перенаправление [[RAMBA Selective VPN Gateway]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_Selective_VPN_Gateway&amp;diff=150</id>
		<title>RAMBA Selective VPN Gateway</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_Selective_VPN_Gateway&amp;diff=150"/>
		<updated>2026-09-10T21:10:58Z</updated>

		<summary type="html">&lt;p&gt;Artem: Artem переименовал страницу RAMBA 20Selective VPN Gateway в RAMBA Selective VPN Gateway&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:RAMBA Selective VPN Gateway}}&lt;br /&gt;
&lt;br /&gt;
= RAMBA Selective VPN Gateway =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA Selective VPN Gateway&#039;&#039;&#039; — шлюз селективной маршрутизации трафика на базе&lt;br /&gt;
&#039;&#039;&#039;WireGuard + nftables + dnsmasq + HAPP/VLESS&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Система позволяет подключать мобильные устройства к домашней сети через WireGuard&lt;br /&gt;
и отправлять через HAPP только трафик выбранных сервисов.&lt;br /&gt;
&lt;br /&gt;
Остальной интернет-трафик выходит напрямую через основной маршрутизатор.&lt;br /&gt;
&lt;br /&gt;
По состоянию на сентябрь 2026 года через HAPP маршрутизируются:&lt;br /&gt;
&lt;br /&gt;
* YouTube&lt;br /&gt;
* Instagram&lt;br /&gt;
* Telegram&lt;br /&gt;
* OpenAI / ChatGPT&lt;br /&gt;
&lt;br /&gt;
Discord тестировался, однако был исключён из селективной маршрутизации из-за проблем&lt;br /&gt;
с голосовым UDP-трафиком.&lt;br /&gt;
&lt;br /&gt;
== Архитектура ==&lt;br /&gt;
&lt;br /&gt;
Основная схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                         INTERNET&lt;br /&gt;
                            |&lt;br /&gt;
                  Public IP / Router&lt;br /&gt;
                            |&lt;br /&gt;
                   UDP 51821 -&amp;gt; 51820&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                 +---------------------+&lt;br /&gt;
                 | CT103 vpn-gateway   |&lt;br /&gt;
                 | 192.168.1.53        |&lt;br /&gt;
                 |                     |&lt;br /&gt;
                 | WireGuard           |&lt;br /&gt;
                 | dnsmasq             |&lt;br /&gt;
                 | nftables            |&lt;br /&gt;
                 | policy routing      |&lt;br /&gt;
                 +----------+----------+&lt;br /&gt;
                            |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                |                       |&lt;br /&gt;
        обычный трафик            выбранный трафик&lt;br /&gt;
                |                       |&lt;br /&gt;
                v                       v&lt;br /&gt;
         192.168.1.1             192.168.1.52&lt;br /&gt;
        основной роутер                 |&lt;br /&gt;
                                        v&lt;br /&gt;
                              +--------------------+&lt;br /&gt;
                              | CT502 happ-gateway |&lt;br /&gt;
                              | HAPP / VLESS       |&lt;br /&gt;
                              +---------+----------+&lt;br /&gt;
                                        |&lt;br /&gt;
                                        v&lt;br /&gt;
                                      VPN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Клиент WireGuard использует:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.0/24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Адрес шлюза:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Компоненты ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Адрес&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| CT103 vpn-gateway&lt;br /&gt;
| 192.168.1.53&lt;br /&gt;
| WireGuard, DNS, nftables, selective routing&lt;br /&gt;
|-&lt;br /&gt;
| CT502 happ-gateway&lt;br /&gt;
| 192.168.1.52&lt;br /&gt;
| HAPP/VLESS VPN gateway&lt;br /&gt;
|-&lt;br /&gt;
| Основной маршрутизатор&lt;br /&gt;
| 192.168.1.1&lt;br /&gt;
| Обычный выход в Интернет&lt;br /&gt;
|-&lt;br /&gt;
| WireGuard&lt;br /&gt;
| 10.20.0.1/24&lt;br /&gt;
| VPN-сеть клиентов&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== WireGuard ==&lt;br /&gt;
&lt;br /&gt;
WireGuard работает внутри LXC-контейнера &#039;&#039;&#039;CT103&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Основной интерфейс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wg0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.1/24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порт WireGuard внутри сети:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
UDP 51820&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На внешнем маршрутизаторе настроен проброс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WAN UDP 51821&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
192.168.1.53:51820&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Клиенты используют:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AllowedIPs = 0.0.0.0/0&lt;br /&gt;
DNS = 10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом весь IPv4-трафик клиента сначала поступает на &#039;&#039;&#039;vpn-gateway&#039;&#039;&#039;,&lt;br /&gt;
а уже там принимается решение о дальнейшем маршруте.&lt;br /&gt;
&lt;br /&gt;
== Принцип селективной маршрутизации ==&lt;br /&gt;
&lt;br /&gt;
Для выбранного трафика устанавливается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fwmark 0x1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На CT103 существует отдельная таблица маршрутизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Правило:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100: from all fwmark 0x1 lookup 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таблица 200:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
default via 192.168.1.52 dev eth0&lt;br /&gt;
192.168.1.0/24 dev eth0 scope link src 192.168.1.53&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
без mark&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
192.168.1.1&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
обычный Интернет&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mark 0x1&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
table 200&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
192.168.1.52&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
HAPP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== nftables ==&lt;br /&gt;
&lt;br /&gt;
Основной конфигурационный файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/nftables.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Актуальная логика:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
table ip selective {&lt;br /&gt;
    set happ_ipv4 {&lt;br /&gt;
        type ipv4_addr&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set telegram_ipv4 {&lt;br /&gt;
        type ipv4_addr&lt;br /&gt;
        flags interval&lt;br /&gt;
        elements = {&lt;br /&gt;
            91.108.4.0/22,&lt;br /&gt;
            91.108.8.0/22,&lt;br /&gt;
            91.108.12.0/22,&lt;br /&gt;
            91.108.16.0/22,&lt;br /&gt;
            91.108.56.0/22,&lt;br /&gt;
            149.154.160.0/20&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    chain prerouting {&lt;br /&gt;
        type filter hook prerouting priority mangle;&lt;br /&gt;
        policy accept;&lt;br /&gt;
&lt;br /&gt;
        iifname &amp;quot;wg0&amp;quot; ip daddr @telegram_ipv4 \&lt;br /&gt;
            counter meta mark set 0x1&lt;br /&gt;
&lt;br /&gt;
        iifname &amp;quot;wg0&amp;quot; ip daddr @happ_ipv4 \&lt;br /&gt;
            counter meta mark set 0x1&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Набор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
заполняется динамически через &#039;&#039;&#039;dnsmasq&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Telegram использует отдельный статический набор IP-сетей, поскольку мобильное&lt;br /&gt;
приложение может устанавливать MTProto-соединения непосредственно с IP-адресами&lt;br /&gt;
Telegram.&lt;br /&gt;
&lt;br /&gt;
== DNS-based routing ==&lt;br /&gt;
&lt;br /&gt;
На CT103 работает &#039;&#039;&#039;dnsmasq&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
WireGuard-клиенты используют:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DNS = 10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конфигурация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/dnsmasq.d/wireguard.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
interface=wg0&lt;br /&gt;
listen-address=10.20.0.1&lt;br /&gt;
bind-dynamic&lt;br /&gt;
&lt;br /&gt;
no-resolv&lt;br /&gt;
server=1.1.1.1&lt;br /&gt;
server=1.0.0.1&lt;br /&gt;
&lt;br /&gt;
cache-size=2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Домены сервисов находятся в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/dnsmasq.d/happ-domains.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При DNS-разрешении IP-адрес автоматически добавляется в nftables set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого трафик WireGuard-клиента к этому IP получает &#039;&#039;&#039;mark 0x1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== YouTube ==&lt;br /&gt;
&lt;br /&gt;
Для YouTube используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/youtube.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/youtu.be/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/googlevideo.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/ytimg.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/youtubei.googleapis.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/ggpht.com/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особенно важен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
googlevideo.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
так как через него передаётся значительная часть видеопотока YouTube.&lt;br /&gt;
&lt;br /&gt;
== Instagram ==&lt;br /&gt;
&lt;br /&gt;
Используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/instagram.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/cdninstagram.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/fbcdn.net/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следует учитывать, что &#039;&#039;&#039;fbcdn.net&#039;&#039;&#039; является общей инфраструктурой Meta.&lt;br /&gt;
&lt;br /&gt;
Поэтому некоторые ресурсы других сервисов Meta также могут попасть через HAPP.&lt;br /&gt;
&lt;br /&gt;
== Telegram ==&lt;br /&gt;
&lt;br /&gt;
Одних DNS-правил для Telegram оказалось недостаточно.&lt;br /&gt;
&lt;br /&gt;
Telegram может подключаться непосредственно к IP-адресам дата-центров.&lt;br /&gt;
&lt;br /&gt;
Поэтому используется статический nftables set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
set telegram_ipv4 {&lt;br /&gt;
    type ipv4_addr&lt;br /&gt;
    flags interval&lt;br /&gt;
&lt;br /&gt;
    elements = {&lt;br /&gt;
        91.108.4.0/22,&lt;br /&gt;
        91.108.8.0/22,&lt;br /&gt;
        91.108.12.0/22,&lt;br /&gt;
        91.108.16.0/22,&lt;br /&gt;
        91.108.56.0/22,&lt;br /&gt;
        149.154.160.0/20&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Трафик маркируется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
iifname &amp;quot;wg0&amp;quot; ip daddr @telegram_ipv4 \&lt;br /&gt;
    counter meta mark set 0x1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Работа правила проверяется счётчиком:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft list chain ip selective prerouting&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OpenAI / ChatGPT ==&lt;br /&gt;
&lt;br /&gt;
Для OpenAI используется DNS-based routing.&lt;br /&gt;
&lt;br /&gt;
Основные правила:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/chatgpt.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/openai.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/auth.openai.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaistatic.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaiusercontent.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaistatsig.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/openaimerge.com/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При тестировании мобильного приложения ChatGPT после очистки набора:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft flush set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DNS-запросы приложения снова заполняли &#039;&#039;&#039;happ_ipv4&#039;&#039;&#039;, а счётчик правила&lt;br /&gt;
селективной маршрутизации увеличивался при отправке сообщений.&lt;br /&gt;
&lt;br /&gt;
Таким образом работа ChatGPT через HAPP была подтверждена непосредственно&lt;br /&gt;
трафиком WireGuard-клиента.&lt;br /&gt;
&lt;br /&gt;
== Discord ==&lt;br /&gt;
&lt;br /&gt;
Discord первоначально был добавлен в DNS-based routing.&lt;br /&gt;
&lt;br /&gt;
Тестировались домены:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
discord.com&lt;br /&gt;
discordapp.com&lt;br /&gt;
discordapp.net&lt;br /&gt;
discordcdn.com&lt;br /&gt;
discord.gg&lt;br /&gt;
discord.media&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обычный HTTPS-трафик успешно попадал в &#039;&#039;&#039;happ_ipv4&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
При тестировании голосового соединения были обнаружены отдельные UDP endpoints.&lt;br /&gt;
&lt;br /&gt;
Примеры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
155.212.196.192&lt;br /&gt;
155.212.204.196&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Был создан экспериментальный набор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
discord_voice_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и голосовой трафик начал попадать под &#039;&#039;&#039;mark 0x1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Однако при реальном голосовом соединении наблюдались проблемы:&lt;br /&gt;
&lt;br /&gt;
* очень небольшой объём трафика попадал под статическое правило;&lt;br /&gt;
* voice endpoint мог изменяться;&lt;br /&gt;
* входящий голос практически отсутствовал;&lt;br /&gt;
* маршрутизация двух отдельных IP не обеспечивала стабильную работу Discord Voice.&lt;br /&gt;
&lt;br /&gt;
Поэтому эксперимент был отменён.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Текущее состояние: Discord полностью исключён из selective routing.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Discord проходит обычным маршрутом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Android&lt;br /&gt;
   |&lt;br /&gt;
WireGuard&lt;br /&gt;
   |&lt;br /&gt;
CT103 vpn-gateway&lt;br /&gt;
   |&lt;br /&gt;
192.168.1.1&lt;br /&gt;
   |&lt;br /&gt;
Internet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это решение принято намеренно, чтобы не нарушать работу голосовых каналов.&lt;br /&gt;
&lt;br /&gt;
== HAPP Gateway ==&lt;br /&gt;
&lt;br /&gt;
CT502:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.1.52&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
работает как отдельный VLESS/HAPP gateway.&lt;br /&gt;
&lt;br /&gt;
Используется TUN-интерфейс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
thapp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
пример адреса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
198.18.0.1/30&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HAPP создаёт отдельную таблицу маршрутизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для корректного возврата трафика WireGuard необходимо сохранить маршруты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    192.168.1.0/24 dev eth0 src 192.168.1.52&lt;br /&gt;
&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    10.20.0.0/24 via 192.168.1.53 dev eth0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Иначе широкое правило:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.0.0/16&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
может отправить обратный трафик WireGuard-клиента не в CT103.&lt;br /&gt;
&lt;br /&gt;
== HAPP Auto Selector ==&lt;br /&gt;
&lt;br /&gt;
На CT502 работает автоматический выбор HAPP-сервера.&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-autoselect.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он выполняет реальные HTTP-запросы через тестовый HAPP proxy и сравнивает&lt;br /&gt;
время ответа нескольких стран.&lt;br /&gt;
&lt;br /&gt;
Тестовые порты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SOCKS 12080&lt;br /&gt;
HTTP  12081&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого сервера выполняется несколько запросов и используется медианное&lt;br /&gt;
значение времени ответа.&lt;br /&gt;
&lt;br /&gt;
Переключение производится только при достаточно заметном улучшении, чтобы&lt;br /&gt;
избежать постоянного переключения между близкими по скорости серверами.&lt;br /&gt;
&lt;br /&gt;
Проверка выполняется systemd timer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-autoselect.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка состояния ==&lt;br /&gt;
&lt;br /&gt;
=== WireGuard ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active wg-quick@wg0&lt;br /&gt;
wg show&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== nftables ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active nftables&lt;br /&gt;
nft list chain ip selective prerouting&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DNS ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active dnsmasq&lt;br /&gt;
dnsmasq --test&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic HAPP set ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft list set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Очистить набор для диагностики:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft flush set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После открытия нужного приложения набор должен заполниться снова.&lt;br /&gt;
&lt;br /&gt;
=== Policy routing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip rule show&lt;br /&gt;
ip route show table 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100: from all fwmark 0x1 lookup 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
default via 192.168.1.52 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка конкретного адреса ===&lt;br /&gt;
&lt;br /&gt;
Обычный маршрут:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route get 1.1.1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Маршрут с HAPP mark:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route get 1.1.1.1 mark 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Второй запрос должен использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 200&lt;br /&gt;
via 192.168.1.52&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Диагностика трафика ==&lt;br /&gt;
&lt;br /&gt;
Трафик конкретного WireGuard-клиента можно наблюдать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 host 10.20.0.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HTTPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 &#039;host 10.20.0.2 and port 443&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UDP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 &#039;host 10.20.0.2 and udp&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DNS и HTTPS одновременно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 \&lt;br /&gt;
    &#039;host 10.20.0.2 and (port 53 or port 443)&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это основной способ поиска сервисов, которые используют дополнительные CDN,&lt;br /&gt;
UDP endpoints или прямые IP-соединения.&lt;br /&gt;
&lt;br /&gt;
== Автозапуск ==&lt;br /&gt;
&lt;br /&gt;
После перезагрузки CT103 должны быть активны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active nftables&lt;br /&gt;
systemctl is-active dnsmasq&lt;br /&gt;
systemctl is-active wg-quick@wg0&lt;br /&gt;
systemctl is-active selective-routing&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сервис selective routing:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
selective-routing.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
восстанавливает:&lt;br /&gt;
&lt;br /&gt;
* маршрут локальной сети в table 200;&lt;br /&gt;
* default route через CT502;&lt;br /&gt;
* правило fwmark 0x1.&lt;br /&gt;
&lt;br /&gt;
== Итоговая схема маршрутизации ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WireGuard Client&lt;br /&gt;
10.20.0.x&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
CT103 vpn-gateway&lt;br /&gt;
      |&lt;br /&gt;
      +--------------------------------------+&lt;br /&gt;
      |                                      |&lt;br /&gt;
      | обычный destination                  | selected destination&lt;br /&gt;
      |                                      |&lt;br /&gt;
      v                                      v&lt;br /&gt;
192.168.1.1                         nftables mark 0x1&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                                  table 200&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                               192.168.1.52&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                                  HAPP/VLESS&lt;br /&gt;
      |                                      |&lt;br /&gt;
      +------------------+-------------------+&lt;br /&gt;
                         |&lt;br /&gt;
                         v&lt;br /&gt;
                      Internet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Сервис&lt;br /&gt;
! Маршрут&lt;br /&gt;
! Метод&lt;br /&gt;
! Статус&lt;br /&gt;
|-&lt;br /&gt;
| YouTube&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Instagram&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Telegram&lt;br /&gt;
| HAPP&lt;br /&gt;
| Статические IP-сети + DNS&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| ChatGPT / OpenAI&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Discord&lt;br /&gt;
| Direct WAN&lt;br /&gt;
| Исключён из selective routing&lt;br /&gt;
| Голос через HAPP отключён&lt;br /&gt;
|-&lt;br /&gt;
| Остальной трафик&lt;br /&gt;
| Direct WAN&lt;br /&gt;
| Main routing table&lt;br /&gt;
| Работает&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
Закрытые ключи WireGuard не должны публиковаться в Wiki, Git или конфигурационных&lt;br /&gt;
примерах.&lt;br /&gt;
&lt;br /&gt;
В документации допускается указывать:&lt;br /&gt;
&lt;br /&gt;
* IP-адреса;&lt;br /&gt;
* порты;&lt;br /&gt;
* имена интерфейсов;&lt;br /&gt;
* публичные ключи при необходимости;&lt;br /&gt;
* архитектуру сети.&lt;br /&gt;
&lt;br /&gt;
Не следует публиковать:&lt;br /&gt;
&lt;br /&gt;
* WireGuard PrivateKey;&lt;br /&gt;
* API keys;&lt;br /&gt;
* HAPP/VLESS credentials;&lt;br /&gt;
* токены;&lt;br /&gt;
* пароли.&lt;br /&gt;
&lt;br /&gt;
== Дальнейшее развитие ==&lt;br /&gt;
&lt;br /&gt;
Возможные следующие этапы:&lt;br /&gt;
&lt;br /&gt;
# Добавление новых сервисов через dnsmasq/nftset.&lt;br /&gt;
# Автоматическая диагностика новых destination IP.&lt;br /&gt;
# Разделение динамических nftables sets по сервисам.&lt;br /&gt;
# Статистика трафика отдельно для каждого сервиса.&lt;br /&gt;
# Web-интерфейс состояния gateway.&lt;br /&gt;
# Автоматическое тестирование HAPP-серверов.&lt;br /&gt;
# Мониторинг WireGuard-клиентов.&lt;br /&gt;
# Безопасная автоматизация добавления и удаления WireGuard-пользователей.&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA]]&lt;br /&gt;
[[Категория:Infrastructure]]&lt;br /&gt;
[[Категория:VPN]]&lt;br /&gt;
[[Категория:WireGuard]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Networking]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_Selective_VPN_Gateway&amp;diff=149</id>
		<title>RAMBA Selective VPN Gateway</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_Selective_VPN_Gateway&amp;diff=149"/>
		<updated>2026-09-10T21:10:24Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «{{DISPLAYTITLE:RAMBA Selective VPN Gateway}}  = RAMBA Selective VPN Gateway =  &amp;#039;&amp;#039;&amp;#039;RAMBA Selective VPN Gateway&amp;#039;&amp;#039;&amp;#039; — шлюз селективной маршрутизации трафика на базе &amp;#039;&amp;#039;&amp;#039;WireGuard + nftables + dnsmasq + HAPP/VLESS&amp;#039;&amp;#039;&amp;#039;.  Система позволяет подключать мобильные устройства к домашней сети через WireGuard и отправлять через HAPP только тра...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{DISPLAYTITLE:RAMBA Selective VPN Gateway}}&lt;br /&gt;
&lt;br /&gt;
= RAMBA Selective VPN Gateway =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA Selective VPN Gateway&#039;&#039;&#039; — шлюз селективной маршрутизации трафика на базе&lt;br /&gt;
&#039;&#039;&#039;WireGuard + nftables + dnsmasq + HAPP/VLESS&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Система позволяет подключать мобильные устройства к домашней сети через WireGuard&lt;br /&gt;
и отправлять через HAPP только трафик выбранных сервисов.&lt;br /&gt;
&lt;br /&gt;
Остальной интернет-трафик выходит напрямую через основной маршрутизатор.&lt;br /&gt;
&lt;br /&gt;
По состоянию на сентябрь 2026 года через HAPP маршрутизируются:&lt;br /&gt;
&lt;br /&gt;
* YouTube&lt;br /&gt;
* Instagram&lt;br /&gt;
* Telegram&lt;br /&gt;
* OpenAI / ChatGPT&lt;br /&gt;
&lt;br /&gt;
Discord тестировался, однако был исключён из селективной маршрутизации из-за проблем&lt;br /&gt;
с голосовым UDP-трафиком.&lt;br /&gt;
&lt;br /&gt;
== Архитектура ==&lt;br /&gt;
&lt;br /&gt;
Основная схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                         INTERNET&lt;br /&gt;
                            |&lt;br /&gt;
                  Public IP / Router&lt;br /&gt;
                            |&lt;br /&gt;
                   UDP 51821 -&amp;gt; 51820&lt;br /&gt;
                            |&lt;br /&gt;
                            v&lt;br /&gt;
                 +---------------------+&lt;br /&gt;
                 | CT103 vpn-gateway   |&lt;br /&gt;
                 | 192.168.1.53        |&lt;br /&gt;
                 |                     |&lt;br /&gt;
                 | WireGuard           |&lt;br /&gt;
                 | dnsmasq             |&lt;br /&gt;
                 | nftables            |&lt;br /&gt;
                 | policy routing      |&lt;br /&gt;
                 +----------+----------+&lt;br /&gt;
                            |&lt;br /&gt;
                +-----------+-----------+&lt;br /&gt;
                |                       |&lt;br /&gt;
        обычный трафик            выбранный трафик&lt;br /&gt;
                |                       |&lt;br /&gt;
                v                       v&lt;br /&gt;
         192.168.1.1             192.168.1.52&lt;br /&gt;
        основной роутер                 |&lt;br /&gt;
                                        v&lt;br /&gt;
                              +--------------------+&lt;br /&gt;
                              | CT502 happ-gateway |&lt;br /&gt;
                              | HAPP / VLESS       |&lt;br /&gt;
                              +---------+----------+&lt;br /&gt;
                                        |&lt;br /&gt;
                                        v&lt;br /&gt;
                                      VPN&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Клиент WireGuard использует:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.0/24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Адрес шлюза:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Компоненты ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Адрес&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| CT103 vpn-gateway&lt;br /&gt;
| 192.168.1.53&lt;br /&gt;
| WireGuard, DNS, nftables, selective routing&lt;br /&gt;
|-&lt;br /&gt;
| CT502 happ-gateway&lt;br /&gt;
| 192.168.1.52&lt;br /&gt;
| HAPP/VLESS VPN gateway&lt;br /&gt;
|-&lt;br /&gt;
| Основной маршрутизатор&lt;br /&gt;
| 192.168.1.1&lt;br /&gt;
| Обычный выход в Интернет&lt;br /&gt;
|-&lt;br /&gt;
| WireGuard&lt;br /&gt;
| 10.20.0.1/24&lt;br /&gt;
| VPN-сеть клиентов&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== WireGuard ==&lt;br /&gt;
&lt;br /&gt;
WireGuard работает внутри LXC-контейнера &#039;&#039;&#039;CT103&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Основной интерфейс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
wg0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
10.20.0.1/24&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порт WireGuard внутри сети:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
UDP 51820&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На внешнем маршрутизаторе настроен проброс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WAN UDP 51821&lt;br /&gt;
        |&lt;br /&gt;
        v&lt;br /&gt;
192.168.1.53:51820&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Клиенты используют:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
AllowedIPs = 0.0.0.0/0&lt;br /&gt;
DNS = 10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом весь IPv4-трафик клиента сначала поступает на &#039;&#039;&#039;vpn-gateway&#039;&#039;&#039;,&lt;br /&gt;
а уже там принимается решение о дальнейшем маршруте.&lt;br /&gt;
&lt;br /&gt;
== Принцип селективной маршрутизации ==&lt;br /&gt;
&lt;br /&gt;
Для выбранного трафика устанавливается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
fwmark 0x1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На CT103 существует отдельная таблица маршрутизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Правило:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100: from all fwmark 0x1 lookup 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таблица 200:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
default via 192.168.1.52 dev eth0&lt;br /&gt;
192.168.1.0/24 dev eth0 scope link src 192.168.1.53&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
без mark&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
192.168.1.1&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
обычный Интернет&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
mark 0x1&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
table 200&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
192.168.1.52&lt;br /&gt;
   |&lt;br /&gt;
   v&lt;br /&gt;
HAPP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== nftables ==&lt;br /&gt;
&lt;br /&gt;
Основной конфигурационный файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/nftables.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Актуальная логика:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
table ip selective {&lt;br /&gt;
    set happ_ipv4 {&lt;br /&gt;
        type ipv4_addr&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    set telegram_ipv4 {&lt;br /&gt;
        type ipv4_addr&lt;br /&gt;
        flags interval&lt;br /&gt;
        elements = {&lt;br /&gt;
            91.108.4.0/22,&lt;br /&gt;
            91.108.8.0/22,&lt;br /&gt;
            91.108.12.0/22,&lt;br /&gt;
            91.108.16.0/22,&lt;br /&gt;
            91.108.56.0/22,&lt;br /&gt;
            149.154.160.0/20&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    chain prerouting {&lt;br /&gt;
        type filter hook prerouting priority mangle;&lt;br /&gt;
        policy accept;&lt;br /&gt;
&lt;br /&gt;
        iifname &amp;quot;wg0&amp;quot; ip daddr @telegram_ipv4 \&lt;br /&gt;
            counter meta mark set 0x1&lt;br /&gt;
&lt;br /&gt;
        iifname &amp;quot;wg0&amp;quot; ip daddr @happ_ipv4 \&lt;br /&gt;
            counter meta mark set 0x1&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Набор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
заполняется динамически через &#039;&#039;&#039;dnsmasq&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Telegram использует отдельный статический набор IP-сетей, поскольку мобильное&lt;br /&gt;
приложение может устанавливать MTProto-соединения непосредственно с IP-адресами&lt;br /&gt;
Telegram.&lt;br /&gt;
&lt;br /&gt;
== DNS-based routing ==&lt;br /&gt;
&lt;br /&gt;
На CT103 работает &#039;&#039;&#039;dnsmasq&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
WireGuard-клиенты используют:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
DNS = 10.20.0.1&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конфигурация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/dnsmasq.d/wireguard.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
interface=wg0&lt;br /&gt;
listen-address=10.20.0.1&lt;br /&gt;
bind-dynamic&lt;br /&gt;
&lt;br /&gt;
no-resolv&lt;br /&gt;
server=1.1.1.1&lt;br /&gt;
server=1.0.0.1&lt;br /&gt;
&lt;br /&gt;
cache-size=2000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Домены сервисов находятся в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/dnsmasq.d/happ-domains.conf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При DNS-разрешении IP-адрес автоматически добавляется в nftables set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого трафик WireGuard-клиента к этому IP получает &#039;&#039;&#039;mark 0x1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== YouTube ==&lt;br /&gt;
&lt;br /&gt;
Для YouTube используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/youtube.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/youtu.be/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/googlevideo.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/ytimg.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/youtubei.googleapis.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/ggpht.com/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Особенно важен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
googlevideo.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
так как через него передаётся значительная часть видеопотока YouTube.&lt;br /&gt;
&lt;br /&gt;
== Instagram ==&lt;br /&gt;
&lt;br /&gt;
Используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/instagram.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/cdninstagram.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/fbcdn.net/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следует учитывать, что &#039;&#039;&#039;fbcdn.net&#039;&#039;&#039; является общей инфраструктурой Meta.&lt;br /&gt;
&lt;br /&gt;
Поэтому некоторые ресурсы других сервисов Meta также могут попасть через HAPP.&lt;br /&gt;
&lt;br /&gt;
== Telegram ==&lt;br /&gt;
&lt;br /&gt;
Одних DNS-правил для Telegram оказалось недостаточно.&lt;br /&gt;
&lt;br /&gt;
Telegram может подключаться непосредственно к IP-адресам дата-центров.&lt;br /&gt;
&lt;br /&gt;
Поэтому используется статический nftables set:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
set telegram_ipv4 {&lt;br /&gt;
    type ipv4_addr&lt;br /&gt;
    flags interval&lt;br /&gt;
&lt;br /&gt;
    elements = {&lt;br /&gt;
        91.108.4.0/22,&lt;br /&gt;
        91.108.8.0/22,&lt;br /&gt;
        91.108.12.0/22,&lt;br /&gt;
        91.108.16.0/22,&lt;br /&gt;
        91.108.56.0/22,&lt;br /&gt;
        149.154.160.0/20&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Трафик маркируется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
iifname &amp;quot;wg0&amp;quot; ip daddr @telegram_ipv4 \&lt;br /&gt;
    counter meta mark set 0x1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Работа правила проверяется счётчиком:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft list chain ip selective prerouting&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== OpenAI / ChatGPT ==&lt;br /&gt;
&lt;br /&gt;
Для OpenAI используется DNS-based routing.&lt;br /&gt;
&lt;br /&gt;
Основные правила:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
nftset=/chatgpt.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/openai.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/auth.openai.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaistatic.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaiusercontent.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/oaistatsig.com/4#ip#selective#happ_ipv4&lt;br /&gt;
nftset=/openaimerge.com/4#ip#selective#happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При тестировании мобильного приложения ChatGPT после очистки набора:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft flush set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DNS-запросы приложения снова заполняли &#039;&#039;&#039;happ_ipv4&#039;&#039;&#039;, а счётчик правила&lt;br /&gt;
селективной маршрутизации увеличивался при отправке сообщений.&lt;br /&gt;
&lt;br /&gt;
Таким образом работа ChatGPT через HAPP была подтверждена непосредственно&lt;br /&gt;
трафиком WireGuard-клиента.&lt;br /&gt;
&lt;br /&gt;
== Discord ==&lt;br /&gt;
&lt;br /&gt;
Discord первоначально был добавлен в DNS-based routing.&lt;br /&gt;
&lt;br /&gt;
Тестировались домены:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
discord.com&lt;br /&gt;
discordapp.com&lt;br /&gt;
discordapp.net&lt;br /&gt;
discordcdn.com&lt;br /&gt;
discord.gg&lt;br /&gt;
discord.media&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обычный HTTPS-трафик успешно попадал в &#039;&#039;&#039;happ_ipv4&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
При тестировании голосового соединения были обнаружены отдельные UDP endpoints.&lt;br /&gt;
&lt;br /&gt;
Примеры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
155.212.196.192&lt;br /&gt;
155.212.204.196&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Был создан экспериментальный набор:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
discord_voice_ipv4&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и голосовой трафик начал попадать под &#039;&#039;&#039;mark 0x1&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Однако при реальном голосовом соединении наблюдались проблемы:&lt;br /&gt;
&lt;br /&gt;
* очень небольшой объём трафика попадал под статическое правило;&lt;br /&gt;
* voice endpoint мог изменяться;&lt;br /&gt;
* входящий голос практически отсутствовал;&lt;br /&gt;
* маршрутизация двух отдельных IP не обеспечивала стабильную работу Discord Voice.&lt;br /&gt;
&lt;br /&gt;
Поэтому эксперимент был отменён.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Текущее состояние: Discord полностью исключён из selective routing.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Discord проходит обычным маршрутом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Android&lt;br /&gt;
   |&lt;br /&gt;
WireGuard&lt;br /&gt;
   |&lt;br /&gt;
CT103 vpn-gateway&lt;br /&gt;
   |&lt;br /&gt;
192.168.1.1&lt;br /&gt;
   |&lt;br /&gt;
Internet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это решение принято намеренно, чтобы не нарушать работу голосовых каналов.&lt;br /&gt;
&lt;br /&gt;
== HAPP Gateway ==&lt;br /&gt;
&lt;br /&gt;
CT502:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.1.52&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
работает как отдельный VLESS/HAPP gateway.&lt;br /&gt;
&lt;br /&gt;
Используется TUN-интерфейс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
thapp&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
пример адреса:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
198.18.0.1/30&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HAPP создаёт отдельную таблицу маршрутизации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для корректного возврата трафика WireGuard необходимо сохранить маршруты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    192.168.1.0/24 dev eth0 src 192.168.1.52&lt;br /&gt;
&lt;br /&gt;
ip route replace table 100 \&lt;br /&gt;
    10.20.0.0/24 via 192.168.1.53 dev eth0&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Иначе широкое правило:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
192.168.0.0/16&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
может отправить обратный трафик WireGuard-клиента не в CT103.&lt;br /&gt;
&lt;br /&gt;
== HAPP Auto Selector ==&lt;br /&gt;
&lt;br /&gt;
На CT502 работает автоматический выбор HAPP-сервера.&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-autoselect.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он выполняет реальные HTTP-запросы через тестовый HAPP proxy и сравнивает&lt;br /&gt;
время ответа нескольких стран.&lt;br /&gt;
&lt;br /&gt;
Тестовые порты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SOCKS 12080&lt;br /&gt;
HTTP  12081&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для каждого сервера выполняется несколько запросов и используется медианное&lt;br /&gt;
значение времени ответа.&lt;br /&gt;
&lt;br /&gt;
Переключение производится только при достаточно заметном улучшении, чтобы&lt;br /&gt;
избежать постоянного переключения между близкими по скорости серверами.&lt;br /&gt;
&lt;br /&gt;
Проверка выполняется systemd timer:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
happ-autoselect.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка состояния ==&lt;br /&gt;
&lt;br /&gt;
=== WireGuard ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active wg-quick@wg0&lt;br /&gt;
wg show&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== nftables ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active nftables&lt;br /&gt;
nft list chain ip selective prerouting&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== DNS ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active dnsmasq&lt;br /&gt;
dnsmasq --test&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Dynamic HAPP set ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft list set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Очистить набор для диагностики:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nft flush set ip selective happ_ipv4&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После открытия нужного приложения набор должен заполниться снова.&lt;br /&gt;
&lt;br /&gt;
=== Policy routing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip rule show&lt;br /&gt;
ip route show table 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидается:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
100: from all fwmark 0x1 lookup 200&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
default via 192.168.1.52 dev eth0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка конкретного адреса ===&lt;br /&gt;
&lt;br /&gt;
Обычный маршрут:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route get 1.1.1.1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Маршрут с HAPP mark:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ip route get 1.1.1.1 mark 1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Второй запрос должен использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
table 200&lt;br /&gt;
via 192.168.1.52&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Диагностика трафика ==&lt;br /&gt;
&lt;br /&gt;
Трафик конкретного WireGuard-клиента можно наблюдать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 host 10.20.0.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HTTPS:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 &#039;host 10.20.0.2 and port 443&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UDP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 &#039;host 10.20.0.2 and udp&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
DNS и HTTPS одновременно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tcpdump -ni wg0 \&lt;br /&gt;
    &#039;host 10.20.0.2 and (port 53 or port 443)&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это основной способ поиска сервисов, которые используют дополнительные CDN,&lt;br /&gt;
UDP endpoints или прямые IP-соединения.&lt;br /&gt;
&lt;br /&gt;
== Автозапуск ==&lt;br /&gt;
&lt;br /&gt;
После перезагрузки CT103 должны быть активны:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl is-active nftables&lt;br /&gt;
systemctl is-active dnsmasq&lt;br /&gt;
systemctl is-active wg-quick@wg0&lt;br /&gt;
systemctl is-active selective-routing&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
active&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сервис selective routing:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
selective-routing.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
восстанавливает:&lt;br /&gt;
&lt;br /&gt;
* маршрут локальной сети в table 200;&lt;br /&gt;
* default route через CT502;&lt;br /&gt;
* правило fwmark 0x1.&lt;br /&gt;
&lt;br /&gt;
== Итоговая схема маршрутизации ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WireGuard Client&lt;br /&gt;
10.20.0.x&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
CT103 vpn-gateway&lt;br /&gt;
      |&lt;br /&gt;
      +--------------------------------------+&lt;br /&gt;
      |                                      |&lt;br /&gt;
      | обычный destination                  | selected destination&lt;br /&gt;
      |                                      |&lt;br /&gt;
      v                                      v&lt;br /&gt;
192.168.1.1                         nftables mark 0x1&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                                  table 200&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                               192.168.1.52&lt;br /&gt;
      |                                      |&lt;br /&gt;
      |                                      v&lt;br /&gt;
      |                                  HAPP/VLESS&lt;br /&gt;
      |                                      |&lt;br /&gt;
      +------------------+-------------------+&lt;br /&gt;
                         |&lt;br /&gt;
                         v&lt;br /&gt;
                      Internet&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Сервис&lt;br /&gt;
! Маршрут&lt;br /&gt;
! Метод&lt;br /&gt;
! Статус&lt;br /&gt;
|-&lt;br /&gt;
| YouTube&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Instagram&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Telegram&lt;br /&gt;
| HAPP&lt;br /&gt;
| Статические IP-сети + DNS&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| ChatGPT / OpenAI&lt;br /&gt;
| HAPP&lt;br /&gt;
| DNS / nftset&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Discord&lt;br /&gt;
| Direct WAN&lt;br /&gt;
| Исключён из selective routing&lt;br /&gt;
| Голос через HAPP отключён&lt;br /&gt;
|-&lt;br /&gt;
| Остальной трафик&lt;br /&gt;
| Direct WAN&lt;br /&gt;
| Main routing table&lt;br /&gt;
| Работает&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
Закрытые ключи WireGuard не должны публиковаться в Wiki, Git или конфигурационных&lt;br /&gt;
примерах.&lt;br /&gt;
&lt;br /&gt;
В документации допускается указывать:&lt;br /&gt;
&lt;br /&gt;
* IP-адреса;&lt;br /&gt;
* порты;&lt;br /&gt;
* имена интерфейсов;&lt;br /&gt;
* публичные ключи при необходимости;&lt;br /&gt;
* архитектуру сети.&lt;br /&gt;
&lt;br /&gt;
Не следует публиковать:&lt;br /&gt;
&lt;br /&gt;
* WireGuard PrivateKey;&lt;br /&gt;
* API keys;&lt;br /&gt;
* HAPP/VLESS credentials;&lt;br /&gt;
* токены;&lt;br /&gt;
* пароли.&lt;br /&gt;
&lt;br /&gt;
== Дальнейшее развитие ==&lt;br /&gt;
&lt;br /&gt;
Возможные следующие этапы:&lt;br /&gt;
&lt;br /&gt;
# Добавление новых сервисов через dnsmasq/nftset.&lt;br /&gt;
# Автоматическая диагностика новых destination IP.&lt;br /&gt;
# Разделение динамических nftables sets по сервисам.&lt;br /&gt;
# Статистика трафика отдельно для каждого сервиса.&lt;br /&gt;
# Web-интерфейс состояния gateway.&lt;br /&gt;
# Автоматическое тестирование HAPP-серверов.&lt;br /&gt;
# Мониторинг WireGuard-клиентов.&lt;br /&gt;
# Безопасная автоматизация добавления и удаления WireGuard-пользователей.&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA]]&lt;br /&gt;
[[Категория:Infrastructure]]&lt;br /&gt;
[[Категория:VPN]]&lt;br /&gt;
[[Категория:WireGuard]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Networking]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=148</id>
		<title>Toonel</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=148"/>
		<updated>2026-09-08T20:54:53Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;cd $HOME&lt;br /&gt;
&lt;br /&gt;
git clone -b feature/windows-bridge http://gitlab.ramba-art.ru/Gans/ramba-ai-pilot.git&lt;br /&gt;
&lt;br /&gt;
cd ramba-ai-pilot&lt;br /&gt;
git branch --show-current&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=147</id>
		<title>Toonel</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=147"/>
		<updated>2026-09-08T20:25:24Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[Interface]&lt;br /&gt;
PrivateKey = cGxkPcBKvRMgIWJcTkBiJNWZ2bPrdxjkgb+oKuileUc=&lt;br /&gt;
Address = 10.77.0.2/24&lt;br /&gt;
&lt;br /&gt;
[Peer]&lt;br /&gt;
PublicKey = Q7P81P89NaA9vh23Q/w4Bpnoy4ih01g4xKimDWIxD2g=&lt;br /&gt;
AllowedIPs = 10.77.0.1/32&lt;br /&gt;
Endpoint = 195.138.232.82:51820&lt;br /&gt;
PersistentKeepalive = 25&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ZtBK1EoHIPWwzutScj8M8XveoQrLOX2dhegt5/wwaRg=&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[Interface]&lt;br /&gt;
PrivateKey = &amp;lt;НОВЫЙ WINDOWS PRIVATE KEY&amp;gt;&lt;br /&gt;
Address = 10.77.0.2/24&lt;br /&gt;
&lt;br /&gt;
[Peer]&lt;br /&gt;
PublicKey = Q7P8lP89NaA9vH23Q/w4Bpnoy4ihO1g4xKimDWIxD2g=&lt;br /&gt;
AllowedIPs = 10.77.0.1/32&lt;br /&gt;
Endpoint = 195.138.232.82:51820&lt;br /&gt;
PersistentKeepalive = 25&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=146</id>
		<title>Toonel</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Toonel&amp;diff=146"/>
		<updated>2026-09-08T20:20:58Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «[Interface] PrivateKey = cGxkPcBKvRMgIWJcTkBiJNWZ2bPrdxjkgb+oKuileUc= Address = 10.77.0.2/24  [Peer] PublicKey = Q7P81P89NaA9vh23Q/w4Bpnoy4ih01g4xKimDWIxD2g= AllowedIPs = 10.77.0.1/32 Endpoint = 195.138.232.82:51820 PersistentKeepalive = 25   ZtBK1EoHIPWwzutScj8M8XveoQrLOX2dhegt5/wwaRg=»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[Interface]&lt;br /&gt;
PrivateKey = cGxkPcBKvRMgIWJcTkBiJNWZ2bPrdxjkgb+oKuileUc=&lt;br /&gt;
Address = 10.77.0.2/24&lt;br /&gt;
&lt;br /&gt;
[Peer]&lt;br /&gt;
PublicKey = Q7P81P89NaA9vh23Q/w4Bpnoy4ih01g4xKimDWIxD2g=&lt;br /&gt;
AllowedIPs = 10.77.0.1/32&lt;br /&gt;
Endpoint = 195.138.232.82:51820&lt;br /&gt;
PersistentKeepalive = 25&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
ZtBK1EoHIPWwzutScj8M8XveoQrLOX2dhegt5/wwaRg=&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_AI_Router&amp;diff=144</id>
		<title>RAMBA AI Router</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_AI_Router&amp;diff=144"/>
		<updated>2026-09-07T22:05:04Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-title&amp;quot;&amp;gt;RAMBA AI Router&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-subtitle&amp;quot;&amp;gt;&lt;br /&gt;
Локальный интеллектуальный маршрутизатор LLM для инфраструктуры RAMBA ART&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;RAMBA AI Router&#039;&#039;&#039; — собственный локальный маршрутизатор языковых моделей RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
Router принимает запрос пользователя, анализирует его тип и контекст, выбирает подходящую локальную LLM, при необходимости повышает уровень модели, проверяет ответ через Verifier и использует постоянную память между диалогами.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Текущая стабильная версия:&#039;&#039;&#039; &#039;&#039;&#039;v4.7 — Semantic Long-Term Memory&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Release:   v4.7&lt;br /&gt;
Commit:    11b18b2&lt;br /&gt;
Backend:   Ollama&lt;br /&gt;
API:       FastAPI / Uvicorn&lt;br /&gt;
Storage:   SQLite&lt;br /&gt;
Inference: NVIDIA GPU&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
= Назначение проекта =&lt;br /&gt;
&lt;br /&gt;
RAMBA AI Router создаётся как центральный интеллектуальный слой локальной AI-инфраструктуры RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
Основная идея проекта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Пользователь&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
     │&lt;br /&gt;
     ├── анализ запроса&lt;br /&gt;
     ├── выбор модели&lt;br /&gt;
     ├── история диалога&lt;br /&gt;
     ├── долговременная память&lt;br /&gt;
     ├── escalation&lt;br /&gt;
     └── verification&lt;br /&gt;
              │&lt;br /&gt;
              ▼&lt;br /&gt;
         Local LLM&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Router позволяет использовать несколько моделей одновременно, не заставляя пользователя вручную выбирать модель для каждого запроса.&lt;br /&gt;
&lt;br /&gt;
Основные задачи:&lt;br /&gt;
&lt;br /&gt;
* автоматический выбор подходящей LLM;&lt;br /&gt;
* минимизация задержки ответа;&lt;br /&gt;
* рациональное использование GPU;&lt;br /&gt;
* сохранение контекста разговора;&lt;br /&gt;
* постоянная память между сессиями;&lt;br /&gt;
* автоматическое повышение уровня модели для сложных запросов;&lt;br /&gt;
* проверка потенциально ненадёжных ответов;&lt;br /&gt;
* создание основы для будущего AI Agent.&lt;br /&gt;
&lt;br /&gt;
= Инфраструктура =&lt;br /&gt;
&lt;br /&gt;
RAMBA AI Router работает в локальной инфраструктуре RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
Основной AI-хост:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Host: depo&lt;br /&gt;
Platform: Proxmox VE&lt;br /&gt;
CPU: Xeon E5-2678 v3&lt;br /&gt;
GPU: NVIDIA GeForce GTX 1080&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Локальные модели обслуживаются через:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Ollama&lt;br /&gt;
http://127.0.0.1:11434&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Router реализован на:&lt;br /&gt;
&lt;br /&gt;
* Python;&lt;br /&gt;
* FastAPI;&lt;br /&gt;
* Uvicorn;&lt;br /&gt;
* SQLite;&lt;br /&gt;
* Ollama API.&lt;br /&gt;
&lt;br /&gt;
= Модели =&lt;br /&gt;
&lt;br /&gt;
В Router используются несколько специализированных моделей.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Роль&lt;br /&gt;
! Модель&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;FAST&#039;&#039;&#039;&lt;br /&gt;
| &amp;lt;code&amp;gt;gemma3:4b&amp;lt;/code&amp;gt;&lt;br /&gt;
| Быстрые повседневные запросы&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;INFRA&#039;&#039;&#039;&lt;br /&gt;
| &amp;lt;code&amp;gt;qwen3:8b&amp;lt;/code&amp;gt;&lt;br /&gt;
| Linux, Proxmox, Docker, сети, инфраструктура&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;SMART&#039;&#039;&#039;&lt;br /&gt;
| &amp;lt;code&amp;gt;qwen3.5:9b&amp;lt;/code&amp;gt;&lt;br /&gt;
| Более сложный анализ и рассуждение&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Общая идея:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                 Request&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
              RAMBA Router&lt;br /&gt;
                    │&lt;br /&gt;
        ┌───────────┼───────────┐&lt;br /&gt;
        │           │           │&lt;br /&gt;
        ▼           ▼           ▼&lt;br /&gt;
      FAST        INFRA       SMART&lt;br /&gt;
   Gemma 3 4B   Qwen3 8B   Qwen3.5 9B&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой подход позволяет не использовать самую тяжёлую модель для каждого простого запроса.&lt;br /&gt;
&lt;br /&gt;
= Архитектура =&lt;br /&gt;
&lt;br /&gt;
Текущая архитектура RAMBA AI Router v4.7:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                         Пользователь&lt;br /&gt;
                              │&lt;br /&gt;
                              ▼&lt;br /&gt;
                    ┌─────────────────┐&lt;br /&gt;
                    │ RAMBA AI Router │&lt;br /&gt;
                    │      v4.7       │&lt;br /&gt;
                    └────────┬────────┘&lt;br /&gt;
                             │&lt;br /&gt;
                 ┌───────────┴───────────┐&lt;br /&gt;
                 │                       │&lt;br /&gt;
                 ▼                       ▼&lt;br /&gt;
          Session Memory          Long-Term Memory&lt;br /&gt;
              v4.6                     v4.7&lt;br /&gt;
                 │                       │&lt;br /&gt;
           messages_json             memory_facts&lt;br /&gt;
                 │                       │&lt;br /&gt;
                 └───────────┬───────────┘&lt;br /&gt;
                             │&lt;br /&gt;
                             ▼&lt;br /&gt;
                    Context + Routing&lt;br /&gt;
                             │&lt;br /&gt;
              ┌──────────────┼──────────────┐&lt;br /&gt;
              │              │              │&lt;br /&gt;
              ▼              ▼              ▼&lt;br /&gt;
             FAST           INFRA          SMART&lt;br /&gt;
          Gemma 3 4B      Qwen3 8B     Qwen3.5 9B&lt;br /&gt;
              │              │              │&lt;br /&gt;
              └──────────────┼──────────────┘&lt;br /&gt;
                             │&lt;br /&gt;
                             ▼&lt;br /&gt;
                         Escalation&lt;br /&gt;
                             │&lt;br /&gt;
                             ▼&lt;br /&gt;
                          Verifier&lt;br /&gt;
                             │&lt;br /&gt;
                             ▼&lt;br /&gt;
                      Финальный ответ&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Принцип работы =&lt;br /&gt;
&lt;br /&gt;
Обработка одного сообщения в актуальной версии выглядит примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
1. Получение /chat запроса&lt;br /&gt;
2. Определение session_id&lt;br /&gt;
3. Загрузка Session Memory&lt;br /&gt;
4. Поиск Long-Term Memory&lt;br /&gt;
5. Анализ запроса&lt;br /&gt;
6. Выбор роли модели&lt;br /&gt;
7. Выбор FAST / INFRA / SMART&lt;br /&gt;
8. Формирование prompt&lt;br /&gt;
9. Добавление истории разговора&lt;br /&gt;
10. Добавление релевантной долговременной памяти&lt;br /&gt;
11. Вызов Ollama&lt;br /&gt;
12. Анализ результата&lt;br /&gt;
13. При необходимости Escalation&lt;br /&gt;
14. При необходимости Verifier&lt;br /&gt;
15. Сохранение Session Memory&lt;br /&gt;
16. Возврат ответа&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= История развития =&lt;br /&gt;
&lt;br /&gt;
== Router v1 ==&lt;br /&gt;
&lt;br /&gt;
Первая версия Router была proof-of-concept.&lt;br /&gt;
&lt;br /&gt;
Основная задача заключалась в том, чтобы доказать сам принцип:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;один API может автоматически направлять разные запросы в разные локальные модели.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Маршрутизация в основном основывалась на простых правилах и ключевых словах.&lt;br /&gt;
&lt;br /&gt;
Архитектура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Request&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
Keyword Rules&lt;br /&gt;
   │&lt;br /&gt;
   ├── FAST&lt;br /&gt;
   ├── INFRA&lt;br /&gt;
   └── SMART&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Главный результат v1 — подтверждение жизнеспособности идеи локального multi-model Router.&lt;br /&gt;
&lt;br /&gt;
== Router v2 ==&lt;br /&gt;
&lt;br /&gt;
Во второй версии была улучшена логика классификации запросов.&lt;br /&gt;
&lt;br /&gt;
Вместо одного простого совпадения ключевых слов Router начал учитывать несколько признаков запроса.&lt;br /&gt;
&lt;br /&gt;
Появилась более стабильная специализация моделей.&lt;br /&gt;
&lt;br /&gt;
Основная проблема всё ещё сохранялась:&lt;br /&gt;
&lt;br /&gt;
* Router практически не понимал контекст;&lt;br /&gt;
* follow-up сообщения могли классифицироваться неправильно;&lt;br /&gt;
* история разговора не являлась частью маршрутизации.&lt;br /&gt;
&lt;br /&gt;
== Router v3 ==&lt;br /&gt;
&lt;br /&gt;
Router v3 стал заметным архитектурным шагом вперёд.&lt;br /&gt;
&lt;br /&gt;
Основным изменением стала &#039;&#039;&#039;score-based routing&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Каждая роль могла получать собственный score.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Запрос:&lt;br /&gt;
&amp;quot;Как пробросить GPU в Proxmox?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
FAST   = 0&lt;br /&gt;
INFRA  = 8&lt;br /&gt;
SMART  = 2&lt;br /&gt;
&lt;br /&gt;
Результат:&lt;br /&gt;
INFRA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволило отказаться от жёсткой схемы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
нашли одно слово → выбрали модель&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
в пользу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
несколько признаков&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
score каждого класса&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
лучший маршрут&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В поколении v3 были заложены основы дальнейшего Router v4.&lt;br /&gt;
&lt;br /&gt;
= Router v4 =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA AI Router v4&#039;&#039;&#039; — текущее поколение системы.&lt;br /&gt;
&lt;br /&gt;
Если v1–v3 в основном решали задачу выбора модели, то серия v4 постепенно превратила Router в полноценный интеллектуальный middleware.&lt;br /&gt;
&lt;br /&gt;
Основные возможности поколения v4:&lt;br /&gt;
&lt;br /&gt;
* context-aware routing;&lt;br /&gt;
* session affinity;&lt;br /&gt;
* hysteresis;&lt;br /&gt;
* история диалога;&lt;br /&gt;
* persistent session memory;&lt;br /&gt;
* escalation;&lt;br /&gt;
* Verifier;&lt;br /&gt;
* Semantic Long-Term Memory;&lt;br /&gt;
* диагностический API;&lt;br /&gt;
* SQLite persistence.&lt;br /&gt;
&lt;br /&gt;
== Версии Router v4 ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Версия&lt;br /&gt;
! Основное изменение&lt;br /&gt;
! Статус&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.1&#039;&#039;&#039;&lt;br /&gt;
| Развитие новой архитектуры Router v4&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.2&#039;&#039;&#039;&lt;br /&gt;
| Улучшение контекстной маршрутизации&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.3&#039;&#039;&#039;&lt;br /&gt;
| Стабилизация routing logic&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.4&#039;&#039;&#039;&lt;br /&gt;
| Escalation&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.5&#039;&#039;&#039;&lt;br /&gt;
| Verifier и дальнейшее развитие маршрутизации&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.6&#039;&#039;&#039;&lt;br /&gt;
| Persistent Context / Session Memory&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.7&#039;&#039;&#039;&lt;br /&gt;
| Semantic Long-Term Memory&lt;br /&gt;
| &#039;&#039;&#039;Текущая стабильная версия&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Context-Aware Routing =&lt;br /&gt;
&lt;br /&gt;
Одной из ключевых проблем ранних версий были короткие follow-up сообщения.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Пользователь:&lt;br /&gt;
В Proxmox vfio-pci не захватывает GTX 1080.&lt;br /&gt;
&lt;br /&gt;
Router:&lt;br /&gt;
INFRA&lt;br /&gt;
&lt;br /&gt;
Пользователь:&lt;br /&gt;
А как проверить?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если анализировать только вторую фразу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
А как проверить?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
она почти не содержит информации для классификации.&lt;br /&gt;
&lt;br /&gt;
Router v4 учитывает историю разговора и может сохранить прежнюю специализацию.&lt;br /&gt;
&lt;br /&gt;
Таким образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Proxmox / GPU passthrough&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
      INFRA&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
&amp;quot;А как проверить?&amp;quot;&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
      INFRA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Session Affinity и Hysteresis =&lt;br /&gt;
&lt;br /&gt;
В Router v4 используется концепция session affinity.&lt;br /&gt;
&lt;br /&gt;
Если разговор уже уверенно ведётся одной специализированной моделью, Router не должен переключаться между моделями из-за каждого короткого сообщения.&lt;br /&gt;
&lt;br /&gt;
Hysteresis снижает число ненужных переключений.&lt;br /&gt;
&lt;br /&gt;
Упрощённо:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Current role = INFRA&lt;br /&gt;
&lt;br /&gt;
Новый score:&lt;br /&gt;
&lt;br /&gt;
FAST   3&lt;br /&gt;
INFRA  4&lt;br /&gt;
&lt;br /&gt;
Разница небольшая&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
оставить INFRA&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это делает разговор стабильнее.&lt;br /&gt;
&lt;br /&gt;
= Escalation =&lt;br /&gt;
&lt;br /&gt;
Escalation позволяет автоматически повысить уровень модели, если первоначально выбранная модель не подходит для запроса.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Request&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
FAST&lt;br /&gt;
   │&lt;br /&gt;
   ├── ответ достаточный → вернуть&lt;br /&gt;
   │&lt;br /&gt;
   └── требуется усиление&lt;br /&gt;
             │&lt;br /&gt;
             ▼&lt;br /&gt;
           SMART&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Или:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
INFRA&lt;br /&gt;
  │&lt;br /&gt;
  └── сложный анализ&lt;br /&gt;
           │&lt;br /&gt;
           ▼&lt;br /&gt;
         SMART&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом Router может начинать с более дешёвой и быстрой модели, а более мощную использовать только тогда, когда это действительно требуется.&lt;br /&gt;
&lt;br /&gt;
= Verifier =&lt;br /&gt;
&lt;br /&gt;
Verifier используется как дополнительная проверка ответа.&lt;br /&gt;
&lt;br /&gt;
Его задача — снизить риск выдачи явно слабого, противоречивого или потенциально ненадёжного результата.&lt;br /&gt;
&lt;br /&gt;
Упрощённая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Primary Model&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
    Answer&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
   Verifier&lt;br /&gt;
      │&lt;br /&gt;
      ├── OK&lt;br /&gt;
      │&lt;br /&gt;
      └── требуется correction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Verifier является частью поколения Router v4.&lt;br /&gt;
&lt;br /&gt;
= Persistent Session Memory — v4.6 =&lt;br /&gt;
&lt;br /&gt;
Версия &#039;&#039;&#039;v4.6&#039;&#039;&#039; добавила постоянное хранение истории сессий.&lt;br /&gt;
&lt;br /&gt;
До этого часть session state зависела от жизни процесса Router.&lt;br /&gt;
&lt;br /&gt;
Основная SQLite-база:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/home/artem/ramba-router/ramba-context.db&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для session memory используется таблица:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
sessions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основные поля:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
session_id&lt;br /&gt;
role&lt;br /&gt;
model&lt;br /&gt;
messages_json&lt;br /&gt;
created_at&lt;br /&gt;
updated_at&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Архитектура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Пользователь&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
 session_id&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
RAMBA Router&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
SQLite sessions&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
messages_json&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
LLM Context&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате история диалога переживает перезапуск процесса Uvicorn.&lt;br /&gt;
&lt;br /&gt;
После рестарта Router может загрузить session state из SQLite.&lt;br /&gt;
&lt;br /&gt;
= Semantic Long-Term Memory — v4.7 =&lt;br /&gt;
&lt;br /&gt;
Версия &#039;&#039;&#039;v4.7&#039;&#039;&#039; добавила второй независимый механизм памяти.&lt;br /&gt;
&lt;br /&gt;
Если Session Memory хранит историю конкретного разговора, Long-Term Memory хранит отдельные знания.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
На сервере depo установлена NVIDIA GeForce GTX 1080.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой факт не относится к одной конкретной session_id.&lt;br /&gt;
&lt;br /&gt;
Он может использоваться:&lt;br /&gt;
&lt;br /&gt;
* завтра;&lt;br /&gt;
* после restart Router;&lt;br /&gt;
* в новой сессии;&lt;br /&gt;
* в разговоре с другим session_id.&lt;br /&gt;
&lt;br /&gt;
== Два уровня памяти ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Возможность&lt;br /&gt;
! Session Memory&lt;br /&gt;
! Long-Term Memory&lt;br /&gt;
|-&lt;br /&gt;
| Версия&lt;br /&gt;
| v4.6&lt;br /&gt;
| v4.7&lt;br /&gt;
|-&lt;br /&gt;
| Привязана к session_id&lt;br /&gt;
| Да&lt;br /&gt;
| Нет&lt;br /&gt;
|-&lt;br /&gt;
| Хранит историю диалога&lt;br /&gt;
| Да&lt;br /&gt;
| Нет&lt;br /&gt;
|-&lt;br /&gt;
| Хранит отдельные знания&lt;br /&gt;
| Нет&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| SQLite persistence&lt;br /&gt;
| Да&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Переживает restart&lt;br /&gt;
| Да&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Работает между сессиями&lt;br /&gt;
| Нет&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Tags&lt;br /&gt;
| Нет&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Importance&lt;br /&gt;
| Нет&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Статистика использования&lt;br /&gt;
| Нет&lt;br /&gt;
| Да&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Архитектурно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                RAMBA Router&lt;br /&gt;
                     │&lt;br /&gt;
          ┌──────────┴──────────┐&lt;br /&gt;
          │                     │&lt;br /&gt;
          ▼                     ▼&lt;br /&gt;
    Session Memory        Long-Term Memory&lt;br /&gt;
          │                     │&lt;br /&gt;
    current dialog          knowledge&lt;br /&gt;
          │                     │&lt;br /&gt;
          └──────────┬──────────┘&lt;br /&gt;
                     ▼&lt;br /&gt;
                 LLM Context&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Таблица memory_facts =&lt;br /&gt;
&lt;br /&gt;
Для долговременной памяти используется отдельная SQLite-таблица:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
CREATE TABLE memory_facts (&lt;br /&gt;
    id INTEGER PRIMARY KEY AUTOINCREMENT,&lt;br /&gt;
    scope TEXT NOT NULL,&lt;br /&gt;
    fact TEXT NOT NULL,&lt;br /&gt;
    tags TEXT,&lt;br /&gt;
    importance REAL NOT NULL DEFAULT 0.5,&lt;br /&gt;
    created_at TEXT NOT NULL,&lt;br /&gt;
    updated_at TEXT NOT NULL,&lt;br /&gt;
    last_used_at TEXT,&lt;br /&gt;
    use_count INTEGER NOT NULL DEFAULT 0&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поля:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Поле&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;id&amp;lt;/code&amp;gt;&lt;br /&gt;
| Уникальный ID факта&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scope&amp;lt;/code&amp;gt;&lt;br /&gt;
| Область действия&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;fact&amp;lt;/code&amp;gt;&lt;br /&gt;
| Текст знания&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;tags&amp;lt;/code&amp;gt;&lt;br /&gt;
| Поисковые теги&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;importance&amp;lt;/code&amp;gt;&lt;br /&gt;
| Важность&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;created_at&amp;lt;/code&amp;gt;&lt;br /&gt;
| Время создания&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;updated_at&amp;lt;/code&amp;gt;&lt;br /&gt;
| Время изменения&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;last_used_at&amp;lt;/code&amp;gt;&lt;br /&gt;
| Последнее использование&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;use_count&amp;lt;/code&amp;gt;&lt;br /&gt;
| Количество использований&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Пример Memory Fact =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;fact&amp;quot;: &amp;quot;На сервере depo установлена видеокарта NVIDIA GeForce GTX 1080&amp;quot;,&lt;br /&gt;
  &amp;quot;scope&amp;quot;: &amp;quot;global&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [&lt;br /&gt;
    &amp;quot;depo&amp;quot;,&lt;br /&gt;
    &amp;quot;gpu&amp;quot;,&lt;br /&gt;
    &amp;quot;nvidia&amp;quot;,&lt;br /&gt;
    &amp;quot;gtx1080&amp;quot;&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;importance&amp;quot;: 0.9&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Memory Retrieval =&lt;br /&gt;
&lt;br /&gt;
Перед вызовом LLM Router выполняет поиск релевантной долговременной памяти.&lt;br /&gt;
&lt;br /&gt;
Функция:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
retrieve_memories()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Упрощённая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
User message&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
retrieve_memories()&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
memory_facts&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
relevance score&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
top memories&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
System Context&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
LLM&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В версии v4.7 retrieval основан на:&lt;br /&gt;
&lt;br /&gt;
* совпадениях слов;&lt;br /&gt;
* совпадениях тегов;&lt;br /&gt;
* importance.&lt;br /&gt;
&lt;br /&gt;
Количество одновременно добавляемых фактов ограничено:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
MAX_MEMORY_FACTS = 5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это защищает prompt от чрезмерного разрастания.&lt;br /&gt;
&lt;br /&gt;
Нерелевантная память не добавляется.&lt;br /&gt;
&lt;br /&gt;
= Memory API =&lt;br /&gt;
&lt;br /&gt;
Версия v4.7 предоставляет отдельное API управления памятью.&lt;br /&gt;
&lt;br /&gt;
== Добавление факта ==&lt;br /&gt;
&lt;br /&gt;
Endpoint:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
POST /memory&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;fact&amp;quot;: &amp;quot;На сервере depo установлена видеокарта NVIDIA GeForce GTX 1080&amp;quot;,&lt;br /&gt;
  &amp;quot;scope&amp;quot;: &amp;quot;global&amp;quot;,&lt;br /&gt;
  &amp;quot;tags&amp;quot;: [&amp;quot;depo&amp;quot;, &amp;quot;gpu&amp;quot;, &amp;quot;nvidia&amp;quot;, &amp;quot;gtx1080&amp;quot;],&lt;br /&gt;
  &amp;quot;importance&amp;quot;: 0.9&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Просмотр памяти ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
GET /memory&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Удаление памяти ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
DELETE /memory/{id}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Почему память пока управляемая =&lt;br /&gt;
&lt;br /&gt;
В v4.7 модель &#039;&#039;&#039;не записывает новые факты автоматически&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Это намеренное решение.&lt;br /&gt;
&lt;br /&gt;
Если сразу разрешить LLM сохранять любые данные из разговора, могут быстро появиться:&lt;br /&gt;
&lt;br /&gt;
* случайные факты;&lt;br /&gt;
* ошибочные утверждения;&lt;br /&gt;
* временная информация;&lt;br /&gt;
* дубликаты;&lt;br /&gt;
* противоречащие друг другу записи;&lt;br /&gt;
* слишком большой объём памяти.&lt;br /&gt;
&lt;br /&gt;
Поэтому v4.7 сначала реализует прозрачный жизненный цикл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
explicit add&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
SQLite&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
retrieval&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
usage statistics&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
explicit delete&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Автоматическое извлечение памяти будет добавляться отдельным этапом.&lt;br /&gt;
&lt;br /&gt;
= Использование Long-Term Memory в /chat =&lt;br /&gt;
&lt;br /&gt;
При поступлении нового сообщения выполняется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/chat&lt;br /&gt;
  │&lt;br /&gt;
  ├── get_session()&lt;br /&gt;
  │&lt;br /&gt;
  ├── load Session Memory&lt;br /&gt;
  │&lt;br /&gt;
  ├── retrieve Long-Term Memory&lt;br /&gt;
  │&lt;br /&gt;
  ├── route request&lt;br /&gt;
  │&lt;br /&gt;
  ├── build prompt&lt;br /&gt;
  │&lt;br /&gt;
  ├── ask Ollama&lt;br /&gt;
  │&lt;br /&gt;
  ├── escalation / verifier&lt;br /&gt;
  │&lt;br /&gt;
  ├── save session&lt;br /&gt;
  │&lt;br /&gt;
  └── response&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ API v4.7 содержит диагностическое поле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;memory_used&amp;quot;: [...]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет увидеть, какие факты были реально добавлены в запрос модели.&lt;br /&gt;
&lt;br /&gt;
= Production-проверка v4.7 =&lt;br /&gt;
&lt;br /&gt;
После реализации v4.7 был выполнен отдельный production-тест.&lt;br /&gt;
&lt;br /&gt;
В Long-Term Memory был добавлен факт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
На сервере depo установлена видеокарта NVIDIA GeForce GTX 1080.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Затем была создана новая сессия.&lt;br /&gt;
&lt;br /&gt;
Запрос:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Какая видеокарта установлена на сервере depo?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Router нашёл memory fact и ответил:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
NVIDIA GeForce GTX 1080.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого процесс Router был полностью перезапущен.&lt;br /&gt;
&lt;br /&gt;
После restart была создана ещё одна новая сессия.&lt;br /&gt;
&lt;br /&gt;
Запрос:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Что за GPU стоит на depo?&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
NVIDIA GeForce GTX 1080.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
history_messages = 0&lt;br /&gt;
memory_used       = memory #1&lt;br /&gt;
use_count         = 2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом доказано:&lt;br /&gt;
&lt;br /&gt;
* ответ не зависел от Session Memory;&lt;br /&gt;
* память работала в новой сессии;&lt;br /&gt;
* память пережила restart Router;&lt;br /&gt;
* SQLite persistence работает;&lt;br /&gt;
* retrieval правильно нашёл нужный факт.&lt;br /&gt;
&lt;br /&gt;
= Тестирование =&lt;br /&gt;
&lt;br /&gt;
Для каждой версии Router используется regression suite.&lt;br /&gt;
&lt;br /&gt;
Для v4.7:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
test-router-v4.7.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяются:&lt;br /&gt;
&lt;br /&gt;
* базовая маршрутизация;&lt;br /&gt;
* score routing;&lt;br /&gt;
* context routing;&lt;br /&gt;
* session affinity;&lt;br /&gt;
* hysteresis;&lt;br /&gt;
* escalation;&lt;br /&gt;
* verifier;&lt;br /&gt;
* session history;&lt;br /&gt;
* persistent session storage;&lt;br /&gt;
* Long-Term Memory;&lt;br /&gt;
* add memory;&lt;br /&gt;
* list memory;&lt;br /&gt;
* retrieve memory;&lt;br /&gt;
* no-match retrieval;&lt;br /&gt;
* use_count;&lt;br /&gt;
* last_used_at;&lt;br /&gt;
* delete memory;&lt;br /&gt;
* SQLite persistence;&lt;br /&gt;
* HTTP Memory API.&lt;br /&gt;
&lt;br /&gt;
Финальный результат regression suite:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
=== v4.7 MEMORY REGRESSION OK ===&lt;br /&gt;
&lt;br /&gt;
🎉 ALL TESTS PASSED&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Memory regression выполняется на временной SQLite-базе и не изменяет production memory.&lt;br /&gt;
&lt;br /&gt;
= Health API =&lt;br /&gt;
&lt;br /&gt;
Для диагностики используется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
GET /health&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример v4.7:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;router&amp;quot;: &amp;quot;ok&amp;quot;,&lt;br /&gt;
  &amp;quot;version&amp;quot;: &amp;quot;4.7&amp;quot;,&lt;br /&gt;
  &amp;quot;ollama_loaded_models&amp;quot;: [&lt;br /&gt;
    &amp;quot;gemma3:4b&amp;quot;&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;sessions&amp;quot;: 2,&lt;br /&gt;
  &amp;quot;sessions_memory&amp;quot;: 0,&lt;br /&gt;
  &amp;quot;sessions_persistent&amp;quot;: 2,&lt;br /&gt;
  &amp;quot;memory_facts&amp;quot;: 1&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
memory_facts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
показывает количество долговременных фактов.&lt;br /&gt;
&lt;br /&gt;
= Файлы проекта =&lt;br /&gt;
&lt;br /&gt;
Основные файлы текущей версии:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/home/artem/ramba-router/router_v47.py&lt;br /&gt;
/home/artem/ramba-router/test-router-v4.7.py&lt;br /&gt;
/home/artem/ramba-router/ramba-context.db&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Исторические версии Router сохранены отдельно и доступны через Git history и release tags.&lt;br /&gt;
&lt;br /&gt;
= Production endpoints =&lt;br /&gt;
&lt;br /&gt;
Текущий Router v4.7:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
127.0.0.1:8003&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Дополнительно оставлена резервная контрольная версия v4.5:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
127.0.0.1:8002&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она используется как fallback при разработке новых версий.&lt;br /&gt;
&lt;br /&gt;
= Git workflow =&lt;br /&gt;
&lt;br /&gt;
Разработка каждой крупной возможности ведётся в отдельной feature-ветке.&lt;br /&gt;
&lt;br /&gt;
Для v4.7 использовалась:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
feature/semantic-memory-v4.7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной commit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
18563ba Add semantic long-term memory for router v4.7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После успешных тестов feature-ветка была объединена с main.&lt;br /&gt;
&lt;br /&gt;
Merge commit:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
11b18b2 Merge branch &#039;feature/semantic-memory-v4.7&#039; into &#039;main&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Релиз зафиксирован тегом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
v4.7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На момент релиза:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HEAD -&amp;gt; main&lt;br /&gt;
origin/main&lt;br /&gt;
tag: v4.7&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
указывали на один релизный commit.&lt;br /&gt;
&lt;br /&gt;
= Релизы =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Версия&lt;br /&gt;
! Основное изменение&lt;br /&gt;
! Статус&lt;br /&gt;
|-&lt;br /&gt;
| v1&lt;br /&gt;
| Первый keyword router&lt;br /&gt;
| Историческая&lt;br /&gt;
|-&lt;br /&gt;
| v2&lt;br /&gt;
| Улучшенная классификация&lt;br /&gt;
| Историческая&lt;br /&gt;
|-&lt;br /&gt;
| v3&lt;br /&gt;
| Score-based routing&lt;br /&gt;
| Историческая&lt;br /&gt;
|-&lt;br /&gt;
| v4.1–v4.3&lt;br /&gt;
| Context-aware архитектура&lt;br /&gt;
| Стабильные этапы&lt;br /&gt;
|-&lt;br /&gt;
| v4.4&lt;br /&gt;
| Escalation&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| v4.5&lt;br /&gt;
| Verifier&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| v4.6&lt;br /&gt;
| Persistent Session Memory&lt;br /&gt;
| Готово&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;v4.7&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Semantic Long-Term Memory&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Current Stable&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Ограничения текущей версии =&lt;br /&gt;
&lt;br /&gt;
Версия v4.7 уже имеет persistent long-term memory, но это всё ещё первая управляемая реализация.&lt;br /&gt;
&lt;br /&gt;
Текущие ограничения:&lt;br /&gt;
&lt;br /&gt;
* память записывается через API;&lt;br /&gt;
* отсутствует automatic memory extraction;&lt;br /&gt;
* отсутствует автоматическое обновление фактов;&lt;br /&gt;
* нет автоматической дедупликации;&lt;br /&gt;
* нет memory consolidation;&lt;br /&gt;
* retrieval основан на словах и тегах;&lt;br /&gt;
* embeddings пока не используются;&lt;br /&gt;
* vector database отсутствует;&lt;br /&gt;
* нет confidence-модели для автоматически полученных фактов.&lt;br /&gt;
&lt;br /&gt;
Это сделано намеренно.&lt;br /&gt;
&lt;br /&gt;
Для текущего оборудования с GTX 1080 приоритетными являются:&lt;br /&gt;
&lt;br /&gt;
* прозрачность;&lt;br /&gt;
* стабильность;&lt;br /&gt;
* низкие накладные расходы;&lt;br /&gt;
* простая диагностика;&lt;br /&gt;
* контроль над содержимым памяти.&lt;br /&gt;
&lt;br /&gt;
= Следующий этап =&lt;br /&gt;
&lt;br /&gt;
Следующее поколение RAMBA AI Router должно добавить автоматическое извлечение и управление памятью.&lt;br /&gt;
&lt;br /&gt;
Предварительная архитектура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Conversation&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Memory Extractor&lt;br /&gt;
     │&lt;br /&gt;
     ├── ignore&lt;br /&gt;
     │&lt;br /&gt;
     ├── create fact&lt;br /&gt;
     │&lt;br /&gt;
     ├── update fact&lt;br /&gt;
     │&lt;br /&gt;
     └── merge duplicate&lt;br /&gt;
              │&lt;br /&gt;
              ▼&lt;br /&gt;
         memory_facts&lt;br /&gt;
              │&lt;br /&gt;
              ▼&lt;br /&gt;
      Memory Retrieval&lt;br /&gt;
              │&lt;br /&gt;
              ▼&lt;br /&gt;
             LLM&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основные задачи следующего этапа:&lt;br /&gt;
&lt;br /&gt;
* Automatic Memory Extraction;&lt;br /&gt;
* классификация полезности факта;&lt;br /&gt;
* защита от случайного запоминания;&lt;br /&gt;
* confidence;&lt;br /&gt;
* дедупликация;&lt;br /&gt;
* обновление изменившихся знаний;&lt;br /&gt;
* consolidation;&lt;br /&gt;
* conflict detection;&lt;br /&gt;
* подготовка к embeddings.&lt;br /&gt;
&lt;br /&gt;
После стабилизации жизненного цикла памяти можно переходить к:&lt;br /&gt;
&lt;br /&gt;
* semantic embeddings;&lt;br /&gt;
* vector retrieval;&lt;br /&gt;
* RAG;&lt;br /&gt;
* внешним knowledge base;&lt;br /&gt;
* tool calling;&lt;br /&gt;
* AI Agent.&lt;br /&gt;
&lt;br /&gt;
= Перспективная архитектура =&lt;br /&gt;
&lt;br /&gt;
Долгосрочная цель проекта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                         User&lt;br /&gt;
                           │&lt;br /&gt;
                           ▼&lt;br /&gt;
                  ┌─────────────────┐&lt;br /&gt;
                  │ RAMBA AI Agent  │&lt;br /&gt;
                  └────────┬────────┘&lt;br /&gt;
                           │&lt;br /&gt;
                           ▼&lt;br /&gt;
                  ┌─────────────────┐&lt;br /&gt;
                  │  RAMBA Router   │&lt;br /&gt;
                  └────────┬────────┘&lt;br /&gt;
                           │&lt;br /&gt;
             ┌─────────────┼─────────────┐&lt;br /&gt;
             │             │             │&lt;br /&gt;
             ▼             ▼             ▼&lt;br /&gt;
          Memory          RAG           Tools&lt;br /&gt;
             │             │             │&lt;br /&gt;
             └─────────────┼─────────────┘&lt;br /&gt;
                           │&lt;br /&gt;
                           ▼&lt;br /&gt;
                  Model Orchestration&lt;br /&gt;
                           │&lt;br /&gt;
              ┌────────────┼────────────┐&lt;br /&gt;
              │            │            │&lt;br /&gt;
              ▼            ▼            ▼&lt;br /&gt;
             FAST        INFRA        SMART&lt;br /&gt;
                           │&lt;br /&gt;
                           ▼&lt;br /&gt;
                      Local GPU&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В такой архитектуре Router становится не конечным приложением, а центральным AI orchestration layer.&lt;br /&gt;
&lt;br /&gt;
= Статус проекта =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Статус&lt;br /&gt;
! Версия&lt;br /&gt;
|-&lt;br /&gt;
| Ollama&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| NVIDIA GPU inference&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| FAST / Gemma 3 4B&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| INFRA / Qwen3 8B&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| SMART / Qwen3.5 9B&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| —&lt;br /&gt;
|-&lt;br /&gt;
| Score-based Routing&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v3&lt;br /&gt;
|-&lt;br /&gt;
| Context-Aware Routing&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4&lt;br /&gt;
|-&lt;br /&gt;
| Session Affinity&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4&lt;br /&gt;
|-&lt;br /&gt;
| Hysteresis&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4&lt;br /&gt;
|-&lt;br /&gt;
| Escalation&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4.4&lt;br /&gt;
|-&lt;br /&gt;
| Verifier&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4.5&lt;br /&gt;
|-&lt;br /&gt;
| Session Memory&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4.6&lt;br /&gt;
|-&lt;br /&gt;
| Persistent Context&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| v4.6&lt;br /&gt;
|-&lt;br /&gt;
| Semantic Long-Term Memory&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;v4.7&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Memory API&lt;br /&gt;
| &#039;&#039;&#039;Готово&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;v4.7&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Automatic Memory Extraction&lt;br /&gt;
| Планируется&lt;br /&gt;
| Следующий этап&lt;br /&gt;
|-&lt;br /&gt;
| Memory Consolidation&lt;br /&gt;
| Планируется&lt;br /&gt;
| Следующий этап&lt;br /&gt;
|-&lt;br /&gt;
| Embeddings&lt;br /&gt;
| Планируется&lt;br /&gt;
| Позднее&lt;br /&gt;
|-&lt;br /&gt;
| Vector Search&lt;br /&gt;
| Планируется&lt;br /&gt;
| Позднее&lt;br /&gt;
|-&lt;br /&gt;
| RAG&lt;br /&gt;
| Планируется&lt;br /&gt;
| Позднее&lt;br /&gt;
|-&lt;br /&gt;
| Tool Calling&lt;br /&gt;
| Планируется&lt;br /&gt;
| Позднее&lt;br /&gt;
|-&lt;br /&gt;
| RAMBA AI Agent&lt;br /&gt;
| Планируется&lt;br /&gt;
| Будущий этап&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Итог =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA AI Router v4.7&#039;&#039;&#039; — текущая стабильная версия локального интеллектуального маршрутизатора RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
Проект прошёл путь:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Keyword Router&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Score Routing&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Context Routing&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Escalation&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Verifier&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Persistent Session Memory&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Semantic Long-Term Memory&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Текущая система уже умеет:&lt;br /&gt;
&lt;br /&gt;
* автоматически выбирать локальную модель;&lt;br /&gt;
* учитывать специализацию запроса;&lt;br /&gt;
* сохранять роль в контексте разговора;&lt;br /&gt;
* избегать ненужного переключения моделей;&lt;br /&gt;
* повышать уровень модели при необходимости;&lt;br /&gt;
* проверять ответ;&lt;br /&gt;
* сохранять историю сессий в SQLite;&lt;br /&gt;
* восстанавливать сессии после restart;&lt;br /&gt;
* хранить отдельные долгосрочные знания;&lt;br /&gt;
* находить релевантные факты;&lt;br /&gt;
* использовать знания в совершенно новой сессии;&lt;br /&gt;
* сохранять долговременную память после restart Router.&lt;br /&gt;
&lt;br /&gt;
Ключевой результат v4.7:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA AI получил настоящий persistent knowledge layer, независимый от конкретного диалога.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Production-проверка подтвердила полный цикл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Memory Fact&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
SQLite&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Router Restart&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
New Session&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Memory Retrieval&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Correct LLM Answer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следующий этап проекта — автоматическое извлечение, обновление и консолидация памяти с последующим переходом к semantic retrieval, RAG и полноценному RAMBA AI Agent.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Happ-gateway&amp;diff=143</id>
		<title>Happ-gateway</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Happ-gateway&amp;diff=143"/>
		<updated>2026-09-02T10:41:34Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= HAPP Gateway — централизованный прокси-шлюз RAMBA ART =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;HAPP Gateway&#039;&#039;&#039; — отдельный сетевой шлюз в инфраструктуре RAMBA ART, предназначенный для централизованного доступа внутренних сервисов к внешним ресурсам через VLESS/HAPP.&lt;br /&gt;
&lt;br /&gt;
Шлюз используется, в частности, для работы Telegram-ботов и сервисов, которым требуется стабильный SOCKS5/HTTP-прокси.&lt;br /&gt;
&lt;br /&gt;
Основная идея заключается в том, что настройки HAPP и VLESS не требуется устанавливать отдельно на каждый сервер или контейнер. В инфраструктуре работает один выделенный LXC-контейнер, предоставляющий прокси остальным узлам локальной сети.&lt;br /&gt;
&lt;br /&gt;
== Общая архитектура ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                         Интернет&lt;br /&gt;
                            │&lt;br /&gt;
                            │ VLESS&lt;br /&gt;
                            ▼&lt;br /&gt;
                    ┌─────────────────┐&lt;br /&gt;
                    │   HAPP Server   │&lt;br /&gt;
                    │  лучший сервер  │&lt;br /&gt;
                    └────────┬────────┘&lt;br /&gt;
                             │&lt;br /&gt;
                             │&lt;br /&gt;
                    ┌────────▼────────┐&lt;br /&gt;
                    │  happ-gateway   │&lt;br /&gt;
                    │  LXC CT 502     │&lt;br /&gt;
                    │ 192.168.1.52    │&lt;br /&gt;
                    │                 │&lt;br /&gt;
                    │ HAPP CLI / Xray │&lt;br /&gt;
                    └────────┬────────┘&lt;br /&gt;
                             │&lt;br /&gt;
               ┌─────────────┴─────────────┐&lt;br /&gt;
               │                           │&lt;br /&gt;
               ▼                           ▼&lt;br /&gt;
       SOCKS5 proxy                  HTTP proxy&lt;br /&gt;
    192.168.1.52:11080           192.168.1.52:11081&lt;br /&gt;
               │                           │&lt;br /&gt;
               └─────────────┬─────────────┘&lt;br /&gt;
                             │&lt;br /&gt;
                  локальная сеть RAMBA ART&lt;br /&gt;
                             │&lt;br /&gt;
              ┌──────────────┼──────────────┐&lt;br /&gt;
              ▼              ▼              ▼&lt;br /&gt;
         Telegram Bot    OpenAI API     другие сервисы&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Параметры шлюза ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Контейнер&lt;br /&gt;
| CT 502&lt;br /&gt;
|-&lt;br /&gt;
| Hostname&lt;br /&gt;
| &amp;lt;code&amp;gt;happ-gateway&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| &amp;lt;code&amp;gt;192.168.1.52&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| ОС&lt;br /&gt;
| Debian&lt;br /&gt;
|-&lt;br /&gt;
| SOCKS5 для LAN&lt;br /&gt;
| &amp;lt;code&amp;gt;192.168.1.52:11080&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| HTTP Proxy для LAN&lt;br /&gt;
| &amp;lt;code&amp;gt;192.168.1.52:11081&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Внутренний SOCKS5&lt;br /&gt;
| &amp;lt;code&amp;gt;127.0.0.1:10808&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Внутренний HTTP Proxy&lt;br /&gt;
| &amp;lt;code&amp;gt;127.0.0.1:10809&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| HAPP subscription&lt;br /&gt;
| &amp;lt;code&amp;gt;ramba&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Часовой пояс&lt;br /&gt;
| &amp;lt;code&amp;gt;Europe/Moscow&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== HAPP CLI ==&lt;br /&gt;
&lt;br /&gt;
Для управления подпиской используется консольный клиент HAPP.&lt;br /&gt;
&lt;br /&gt;
Конфигурация хранится в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/root/.config/happ-cli&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Просмотр доступных серверов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
happ --home /root/.config/happ-cli list&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обновление подписки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
happ --home /root/.config/happ-cli sub update ramba&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запуск конкретного сервера в режиме локального proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
happ --home /root/.config/happ-cli \&lt;br /&gt;
  connect &amp;quot;Швеция&amp;quot; \&lt;br /&gt;
  --mode proxy \&lt;br /&gt;
  --socks 10808 \&lt;br /&gt;
  --http 10809&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Важно: сервер выбирается &#039;&#039;&#039;по текстовому тегу страны, а не по его номеру&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Это было сделано после обнаружения особенности HAPP: после обновления подписки порядковые номера серверов могут изменяться.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
до обновления:&lt;br /&gt;
&lt;br /&gt;
#32 → Нидерланды&lt;br /&gt;
&lt;br /&gt;
после обновления:&lt;br /&gt;
&lt;br /&gt;
#32 → Финляндия&lt;br /&gt;
#33 → Нидерланды&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому конфигурация вида:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
connect 32&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
небезопасна.&lt;br /&gt;
&lt;br /&gt;
Используется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
connect &amp;quot;Швеция&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом изменение порядка серверов в подписке не приводит к подключению к другой стране.&lt;br /&gt;
&lt;br /&gt;
== Основной systemd-сервис ==&lt;br /&gt;
&lt;br /&gt;
HAPP запускается автоматически через systemd.&lt;br /&gt;
&lt;br /&gt;
Файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/happ-gateway.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конфигурация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=HAPP VLESS Proxy Gateway&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=root&lt;br /&gt;
Environment=HOME=/root&lt;br /&gt;
ExecStart=/usr/local/bin/happ --home /root/.config/happ-cli connect &amp;quot;Швеция&amp;quot; --mode proxy --socks 10808 --http 10809&lt;br /&gt;
Restart=always&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Управление:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status happ-gateway.service&lt;br /&gt;
systemctl restart happ-gateway.service&lt;br /&gt;
systemctl stop happ-gateway.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Просмотр журнала:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u happ-gateway.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Публикация proxy в локальную сеть ==&lt;br /&gt;
&lt;br /&gt;
Сам HAPP создаёт локальные proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SOCKS5: 127.0.0.1:10808&lt;br /&gt;
HTTP:   127.0.0.1:10809&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для использования другими машинами инфраструктуры proxy публикуются в LAN.&lt;br /&gt;
&lt;br /&gt;
В рабочей конфигурации используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SOCKS5:&lt;br /&gt;
192.168.1.52:11080&lt;br /&gt;
&lt;br /&gt;
HTTP:&lt;br /&gt;
192.168.1.52:11081&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет другим контейнерам использовать HAPP Gateway без установки HAPP/Xray на каждом из них.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl --proxy socks5h://192.168.1.52:11080 \&lt;br /&gt;
  https://api.ipify.org&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Параметр &amp;lt;code&amp;gt;socks5h&amp;lt;/code&amp;gt; важен: DNS-разрешение выполняется через proxy, а не локальной машиной.&lt;br /&gt;
&lt;br /&gt;
== Проверка внешнего IP ==&lt;br /&gt;
&lt;br /&gt;
Непосредственно на HAPP Gateway:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -sS --max-time 15 \&lt;br /&gt;
  --proxy socks5h://127.0.0.1:10808 \&lt;br /&gt;
  https://api.ipify.org&lt;br /&gt;
echo&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Во время настройки при использовании сервера Швеции был получен внешний IP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
87.251.85.130&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Внешний IP не является постоянным и может измениться при переключении HAPP-сервера.&lt;br /&gt;
&lt;br /&gt;
== Автоматический выбор лучшего сервера ==&lt;br /&gt;
&lt;br /&gt;
Для повышения стабильности был реализован собственный механизм автоматического тестирования HAPP-серверов.&lt;br /&gt;
&lt;br /&gt;
Скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/local/sbin/happ-autoselect.sh&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он периодически проверяет доступные серверы и выбирает наиболее быстрый рабочий сервер.&lt;br /&gt;
&lt;br /&gt;
=== Почему не используется обычный ping ===&lt;br /&gt;
&lt;br /&gt;
ICMP ping не всегда отражает реальное качество proxy-соединения.&lt;br /&gt;
&lt;br /&gt;
Для Telegram-ботов значительно важнее фактическое время выполнения HTTPS-запроса через:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
клиент&lt;br /&gt;
  ↓&lt;br /&gt;
HAPP&lt;br /&gt;
  ↓&lt;br /&gt;
VLESS&lt;br /&gt;
  ↓&lt;br /&gt;
удалённый сервер&lt;br /&gt;
  ↓&lt;br /&gt;
Telegram API&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому каждый сервер тестируется реальным HTTPS-запросом через временный SOCKS5 proxy.&lt;br /&gt;
&lt;br /&gt;
Тестовая цель:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://api.telegram.org&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Алгоритм проверки ===&lt;br /&gt;
&lt;br /&gt;
Для каждой страны выполняются три запроса.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
HAPP candidate&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
127.0.0.1:12080&lt;br /&gt;
      │&lt;br /&gt;
      │ SOCKS5&lt;br /&gt;
      ▼&lt;br /&gt;
api.telegram.org&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Из трёх результатов рассчитывается &#039;&#039;&#039;медиана времени ответа&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Использование медианы позволяет уменьшить влияние единичного скачка задержки.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
0.19 s&lt;br /&gt;
0.21 s&lt;br /&gt;
0.85 s&lt;br /&gt;
&lt;br /&gt;
median = 0.21 s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сервер считается рабочим, если успешно выполнено не менее двух из трёх запросов.&lt;br /&gt;
&lt;br /&gt;
=== Серверы с ошибками ===&lt;br /&gt;
&lt;br /&gt;
Если сервер не обеспечивает стабильное соединение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
test 1: TIMEOUT/ERROR&lt;br /&gt;
test 2: TIMEOUT/ERROR&lt;br /&gt;
test 3: TIMEOUT/ERROR&lt;br /&gt;
&lt;br /&gt;
REJECTED&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
он исключается из текущего выбора.&lt;br /&gt;
&lt;br /&gt;
При тестировании, например, некоторые серверы Польши, Эстонии, Франции и Сингапура не обеспечивали соединение с Telegram API и автоматически отбрасывались.&lt;br /&gt;
&lt;br /&gt;
Это не означает, что сервер навсегда исключён: при следующей проверке он тестируется снова.&lt;br /&gt;
&lt;br /&gt;
== Защита от постоянного переключения серверов ==&lt;br /&gt;
&lt;br /&gt;
Выбирать сервер только по минимальной задержке недостаточно.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
текущий сервер: 220 ms&lt;br /&gt;
другой сервер:  215 ms&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Переключение ради 5 ms не имеет практического смысла и приводит к ненужным перезапускам HAPP.&lt;br /&gt;
&lt;br /&gt;
Поэтому используется порог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
15 %&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Новый сервер выбирается только если он быстрее текущего как минимум на 15%.&lt;br /&gt;
&lt;br /&gt;
Логика:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
лучший сервер&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
быстрее текущего ≥ 15% ?&lt;br /&gt;
      │&lt;br /&gt;
   ┌──┴──┐&lt;br /&gt;
   │     │&lt;br /&gt;
  НЕТ    ДА&lt;br /&gt;
   │     │&lt;br /&gt;
   ▼     ▼&lt;br /&gt;
ничего  изменить&lt;br /&gt;
не      сервер&lt;br /&gt;
делать     │&lt;br /&gt;
           ▼&lt;br /&gt;
      restart HAPP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Результаты тестирования ==&lt;br /&gt;
&lt;br /&gt;
Во время настройки были получены, например, следующие значения:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Сервер&lt;br /&gt;
! Медиана&lt;br /&gt;
! Результат&lt;br /&gt;
|-&lt;br /&gt;
| Швеция&lt;br /&gt;
| ~0.20–0.22 s&lt;br /&gt;
| &#039;&#039;&#039;Лучший&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Финляндия&lt;br /&gt;
| ~0.24–0.25 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Нидерланды&lt;br /&gt;
| ~0.25–0.28 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Литва&lt;br /&gt;
| ~0.27–0.29 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Казахстан&lt;br /&gt;
| ~0.64–0.71 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Канада&lt;br /&gt;
| ~0.83–0.84 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Дубай&lt;br /&gt;
| ~0.95–0.96 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Бразилия&lt;br /&gt;
| ~1.50 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Япония&lt;br /&gt;
| ~1.65 s&lt;br /&gt;
| Работает&lt;br /&gt;
|-&lt;br /&gt;
| Германия&lt;br /&gt;
| ~1.5–2.1 s&lt;br /&gt;
| Работает нестабильно&lt;br /&gt;
|-&lt;br /&gt;
| США&lt;br /&gt;
| ~2.4 s&lt;br /&gt;
| Высокая задержка&lt;br /&gt;
|-&lt;br /&gt;
| Польша&lt;br /&gt;
| TIMEOUT&lt;br /&gt;
| Отклонён&lt;br /&gt;
|-&lt;br /&gt;
| Эстония&lt;br /&gt;
| TIMEOUT&lt;br /&gt;
| Отклонён&lt;br /&gt;
|-&lt;br /&gt;
| Франция&lt;br /&gt;
| TIMEOUT&lt;br /&gt;
| Отклонён&lt;br /&gt;
|-&lt;br /&gt;
| Сингапур&lt;br /&gt;
| TIMEOUT&lt;br /&gt;
| Отклонён&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На момент настройки наиболее быстрым маршрутом оказался сервер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
🇸🇪 Швеция&lt;br /&gt;
swsq2.aquafinas.org:443&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== systemd timer автоматической проверки ==&lt;br /&gt;
&lt;br /&gt;
Для автоматического запуска используется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/happ-autoselect.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=HAPP automatic best server selector&lt;br /&gt;
After=network-online.target happ-gateway.service&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=oneshot&lt;br /&gt;
ExecStart=/usr/local/sbin/happ-autoselect.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таймер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/happ-autoselect.timer&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Benchmark HAPP servers every hour&lt;br /&gt;
&lt;br /&gt;
[Timer]&lt;br /&gt;
OnBootSec=5min&lt;br /&gt;
OnUnitActiveSec=1h&lt;br /&gt;
RandomizedDelaySec=2min&lt;br /&gt;
Persistent=true&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=timers.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Активация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now happ-autoselect.timer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status happ-autoselect.timer --no-pager&lt;br /&gt;
systemctl list-timers --all | grep happ&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом benchmark выполняется приблизительно один раз в час.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;RandomizedDelaySec=2min&amp;lt;/code&amp;gt; добавляет небольшой случайный сдвиг времени запуска.&lt;br /&gt;
&lt;br /&gt;
== Важное решение: не обновлять подписку каждый час ==&lt;br /&gt;
&lt;br /&gt;
Изначально &amp;lt;code&amp;gt;happ-autoselect.sh&amp;lt;/code&amp;gt; перед каждым benchmark выполнял:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
happ --home /root/.config/happ-cli sub update ramba&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Во время тестирования обновление подписки один раз завершилось ошибкой.&lt;br /&gt;
&lt;br /&gt;
В результате список серверов временно не был доступен для скрипта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
WARNING: subscription update failed&lt;br /&gt;
Skipping США: not found&lt;br /&gt;
Skipping Литва: not found&lt;br /&gt;
...&lt;br /&gt;
ERROR: no working servers found&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основной HAPP Gateway при этом продолжил работать на текущем сервере.&lt;br /&gt;
&lt;br /&gt;
После анализа было принято решение &#039;&#039;&#039;разделить две независимые операции&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
# обновление подписки;&lt;br /&gt;
# benchmark серверов.&lt;br /&gt;
&lt;br /&gt;
Часовой benchmark больше не выполняет &amp;lt;code&amp;gt;sub update&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Он работает с уже имеющейся локальной подпиской.&lt;br /&gt;
&lt;br /&gt;
Это делает автоматический выбор сервера безопаснее: временная недоступность сервера подписки не влияет на уже работающий proxy.&lt;br /&gt;
&lt;br /&gt;
== Отказоустойчивость ==&lt;br /&gt;
&lt;br /&gt;
Система построена по принципу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
не удалось провести benchmark&lt;br /&gt;
             │&lt;br /&gt;
             ▼&lt;br /&gt;
     НЕ менять сервер&lt;br /&gt;
             │&lt;br /&gt;
             ▼&lt;br /&gt;
оставить работающий HAPP&lt;br /&gt;
на текущем сервере&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть ошибка системы мониторинга не должна ломать рабочее соединение.&lt;br /&gt;
&lt;br /&gt;
Это особенно важно для сервисов, которые постоянно используют шлюз.&lt;br /&gt;
&lt;br /&gt;
== Просмотр логов автоматического выбора ==&lt;br /&gt;
&lt;br /&gt;
Последние события:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -t happ-autoselect -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Наблюдение в реальном времени:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -t happ-autoselect -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Типичный успешный результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Best server: Швеция (0.217001s)&lt;br /&gt;
Current Швеция: 0.217001s&lt;br /&gt;
Improvement: 0.0%&lt;br /&gt;
Already using best server: Швеция&lt;br /&gt;
Keeping current server: Швеция&lt;br /&gt;
=== HAPP benchmark finished ===&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если другой сервер значительно быстрее:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Best server: Швеция (0.202160s)&lt;br /&gt;
Improvement: 18.4%&lt;br /&gt;
Switching ...&lt;br /&gt;
Switch successful&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Настройка часового пояса ==&lt;br /&gt;
&lt;br /&gt;
Первоначально контейнер использовал UTC:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Local time: 07:50 UTC&lt;br /&gt;
Time zone: Etc/UTC&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для удобства администрирования установлен московский часовой пояс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
timedatectl set-timezone Europe/Moscow&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
timedatectl&lt;br /&gt;
date&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После настройки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Local time: 10:50 MSK&lt;br /&gt;
Universal time: 07:50 UTC&lt;br /&gt;
Time zone: Europe/Moscow (MSK, +0300)&lt;br /&gt;
System clock synchronized: yes&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После изменения timezone systemd автоматически начал отображать время таймеров и журналов в MSK.&lt;br /&gt;
&lt;br /&gt;
== Использование HAPP Gateway приложениями ==&lt;br /&gt;
&lt;br /&gt;
Для приложений в локальной сети рекомендуется использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SOCKS5:&lt;br /&gt;
&lt;br /&gt;
socks5://192.168.1.52:11080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
или при использовании curl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
socks5h://192.168.1.52:11080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
HTTP Proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://192.168.1.52:11081&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом приложение не знает ничего о VLESS, Xray, подписках и конкретном внешнем сервере.&lt;br /&gt;
&lt;br /&gt;
Для него HAPP Gateway является обычным proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Приложение&lt;br /&gt;
     │&lt;br /&gt;
     │ SOCKS5&lt;br /&gt;
     ▼&lt;br /&gt;
192.168.1.52:11080&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
HAPP Gateway&lt;br /&gt;
     │&lt;br /&gt;
     │ VLESS&lt;br /&gt;
     ▼&lt;br /&gt;
лучший внешний сервер&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Интернет&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Итоговая схема ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    RAMBA ART LAN&lt;br /&gt;
                         │&lt;br /&gt;
       ┌─────────────────┼─────────────────┐&lt;br /&gt;
       │                 │                 │&lt;br /&gt;
       ▼                 ▼                 ▼&lt;br /&gt;
 Telegram Bot       Kuzya 2.0        другие сервисы&lt;br /&gt;
       │                 │                 │&lt;br /&gt;
       └─────────────────┼─────────────────┘&lt;br /&gt;
                         │&lt;br /&gt;
                         │ SOCKS5&lt;br /&gt;
                         ▼&lt;br /&gt;
                 192.168.1.52:11080&lt;br /&gt;
                         │&lt;br /&gt;
                ┌────────▼────────┐&lt;br /&gt;
                │  HAPP Gateway   │&lt;br /&gt;
                │     CT 502      │&lt;br /&gt;
                │                 │&lt;br /&gt;
                │ HAPP CLI + Xray │&lt;br /&gt;
                └────────┬────────┘&lt;br /&gt;
                         │&lt;br /&gt;
                         │ VLESS&lt;br /&gt;
                         ▼&lt;br /&gt;
                 выбранный сервер&lt;br /&gt;
                         │&lt;br /&gt;
                         ▼&lt;br /&gt;
                      Internet&lt;br /&gt;
&lt;br /&gt;
Каждый час:&lt;br /&gt;
&lt;br /&gt;
happ-autoselect.timer&lt;br /&gt;
          │&lt;br /&gt;
          ▼&lt;br /&gt;
happ-autoselect.sh&lt;br /&gt;
          │&lt;br /&gt;
          ▼&lt;br /&gt;
проверка серверов&lt;br /&gt;
через Telegram HTTPS&lt;br /&gt;
          │&lt;br /&gt;
          ▼&lt;br /&gt;
расчёт median&lt;br /&gt;
          │&lt;br /&gt;
          ▼&lt;br /&gt;
лучший быстрее ≥15% ?&lt;br /&gt;
       ┌──┴───┐&lt;br /&gt;
       │      │&lt;br /&gt;
      НЕТ     ДА&lt;br /&gt;
       │      │&lt;br /&gt;
       ▼      ▼&lt;br /&gt;
 оставить   изменить&lt;br /&gt;
 текущий    сервер&lt;br /&gt;
             │&lt;br /&gt;
             ▼&lt;br /&gt;
       restart HAPP&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние ==&lt;br /&gt;
&lt;br /&gt;
На момент завершения настройки:&lt;br /&gt;
&lt;br /&gt;
* HAPP Gateway работает в отдельном LXC-контейнере;&lt;br /&gt;
* SOCKS5 и HTTP proxy доступны другим узлам LAN;&lt;br /&gt;
* основной HAPP управляется через systemd;&lt;br /&gt;
* сервер задаётся по стабильному текстовому тегу страны;&lt;br /&gt;
* реализован автоматический benchmark серверов;&lt;br /&gt;
* benchmark выполняется примерно раз в час;&lt;br /&gt;
* проверяется реальная доступность Telegram API через proxy;&lt;br /&gt;
* используется медиана трёх измерений;&lt;br /&gt;
* неработающие серверы автоматически отбрасываются;&lt;br /&gt;
* переключение выполняется только при выигрыше не менее 15%;&lt;br /&gt;
* ошибка benchmark не отключает рабочий proxy;&lt;br /&gt;
* обновление HAPP-подписки отделено от механизма автоматического выбора;&lt;br /&gt;
* системное время контейнера отображается в MSK;&lt;br /&gt;
* HAPP Gateway готов для использования Telegram-ботами и другими сервисами RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA ART]]&lt;br /&gt;
[[Категория:Инфраструктура]]&lt;br /&gt;
[[Категория:Linux]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Сеть]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_Matrix&amp;diff=142</id>
		<title>RAMBA Matrix</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_Matrix&amp;diff=142"/>
		<updated>2026-09-02T10:37:23Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-title&amp;quot;&amp;gt;RAMBA Matrix&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-subtitle&amp;quot;&amp;gt;&lt;br /&gt;
Корпоративный мессенджер RAMBA ART на базе открытого протокола Matrix&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;RAMBA Matrix&#039;&#039;&#039; — собственная коммуникационная платформа RAMBA ART на базе открытого протокола Matrix.&lt;br /&gt;
&lt;br /&gt;
Система предоставляет обмен сообщениями, групповые комнаты, сквозное шифрование, веб- и мобильные клиенты, а также аудио- и видеозвонки.&lt;br /&gt;
&lt;br /&gt;
Основная задача проекта — получить независимый корпоративный мессенджер, полностью размещённый на собственной инфраструктуре.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Назначение проекта ==&lt;br /&gt;
&lt;br /&gt;
RAMBA Matrix создавался как собственная альтернатива внешним корпоративным мессенджерам.&lt;br /&gt;
&lt;br /&gt;
Основные требования:&lt;br /&gt;
&lt;br /&gt;
* собственный сервер сообщений;&lt;br /&gt;
* хранение данных на инфраструктуре RAMBA ART;&lt;br /&gt;
* Android и iOS;&lt;br /&gt;
* веб-клиент;&lt;br /&gt;
* сквозное шифрование;&lt;br /&gt;
* личные и групповые комнаты;&lt;br /&gt;
* аудио- и видеозвонки;&lt;br /&gt;
* собственные Matrix ID;&lt;br /&gt;
* закрытая регистрация;&lt;br /&gt;
* возможность резервного копирования;&lt;br /&gt;
* возможность дальнейшего масштабирования;&lt;br /&gt;
* ориентация примерно на 1000 зарегистрированных пользователей.&lt;br /&gt;
&lt;br /&gt;
Matrix ID пользователей имеют вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
@username:ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
@ivan_ivanov:ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Архитектура RAMBA Matrix ==&lt;br /&gt;
&lt;br /&gt;
Общая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                         INTERNET&lt;br /&gt;
                            │&lt;br /&gt;
                            │ HTTPS&lt;br /&gt;
                            ▼&lt;br /&gt;
                  ┌──────────────────┐&lt;br /&gt;
                  │     BrainyCP     │&lt;br /&gt;
                  │      Nginx       │&lt;br /&gt;
                  │  Reverse Proxy   │&lt;br /&gt;
                  │       SSL        │&lt;br /&gt;
                  └────────┬─────────┘&lt;br /&gt;
                           │&lt;br /&gt;
                           │ HTTP&lt;br /&gt;
                           ▼&lt;br /&gt;
                ┌─────────────────────┐&lt;br /&gt;
                │      ramba-chat     │&lt;br /&gt;
                │                     │&lt;br /&gt;
                │      Dendrite       │&lt;br /&gt;
                │     PostgreSQL      │&lt;br /&gt;
                │       Coturn        │&lt;br /&gt;
                └─────────┬───────────┘&lt;br /&gt;
                          │&lt;br /&gt;
                          │&lt;br /&gt;
                ┌─────────┴───────────┐&lt;br /&gt;
                │                     │&lt;br /&gt;
                ▼                     ▼&lt;br /&gt;
           Media Store          TURN Relay&lt;br /&gt;
                │&lt;br /&gt;
                ▼&lt;br /&gt;
              OMV/NFS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Публичный веб-клиент Element работает отдельно и подключается к Matrix homeserver через HTTPS.&lt;br /&gt;
&lt;br /&gt;
== Домены ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Назначение&lt;br /&gt;
! Адрес&lt;br /&gt;
|-&lt;br /&gt;
| Matrix Server Name&lt;br /&gt;
| &amp;lt;code&amp;gt;ramba-art.ru&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Homeserver&lt;br /&gt;
| &amp;lt;code&amp;gt;chat.ramba-art.ru&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Element Web&lt;br /&gt;
| &amp;lt;code&amp;gt;element.ramba-art.ru&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
При этом серверное имя Matrix остаётся:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Благодаря этому пользовательские ID не содержат технический поддомен `chat`.&lt;br /&gt;
&lt;br /&gt;
== Компоненты системы ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Dendrite&#039;&#039;&#039;&lt;br /&gt;
| Matrix homeserver&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;PostgreSQL&#039;&#039;&#039;&lt;br /&gt;
| Основная база данных&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Element Web&#039;&#039;&#039;&lt;br /&gt;
| Веб-клиент Matrix&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Element Mobile&#039;&#039;&#039;&lt;br /&gt;
| Клиенты Android и iOS&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Coturn&#039;&#039;&#039;&lt;br /&gt;
| STUN/TURN для WebRTC&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;BrainyCP / Nginx&#039;&#039;&#039;&lt;br /&gt;
| Reverse proxy и SSL&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;OMV / NFS&#039;&#039;&#039;&lt;br /&gt;
| Хранилище медиафайлов&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Proxmox VE&#039;&#039;&#039;&lt;br /&gt;
| Виртуализация и резервное копирование VM&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Почему выбран Matrix ==&lt;br /&gt;
&lt;br /&gt;
Matrix — открытый федеративный протокол для обмена сообщениями в реальном времени.&lt;br /&gt;
&lt;br /&gt;
Основные преимущества:&lt;br /&gt;
&lt;br /&gt;
* открытая спецификация;&lt;br /&gt;
* отсутствие привязки к одному поставщику;&lt;br /&gt;
* собственный сервер;&lt;br /&gt;
* собственный домен;&lt;br /&gt;
* поддержка E2EE;&lt;br /&gt;
* федерация;&lt;br /&gt;
* множество клиентских приложений;&lt;br /&gt;
* интеграции и боты;&lt;br /&gt;
* возможность работы полностью на собственной инфраструктуре.&lt;br /&gt;
&lt;br /&gt;
Недостатки:&lt;br /&gt;
&lt;br /&gt;
* инфраструктура сложнее обычного SaaS-мессенджера;&lt;br /&gt;
* необходимо обслуживать серверную часть;&lt;br /&gt;
* требуется отдельная настройка TURN для звонков;&lt;br /&gt;
* необходимо резервировать БД и media store;&lt;br /&gt;
* клиенты Matrix требуют корректного управления ключами шифрования.&lt;br /&gt;
&lt;br /&gt;
== Почему Dendrite ==&lt;br /&gt;
&lt;br /&gt;
В качестве Matrix homeserver используется &#039;&#039;&#039;Dendrite&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Dendrite написан на Go и может работать в компактной монолитной конфигурации.&lt;br /&gt;
&lt;br /&gt;
Для RAMBA ART это позволило разместить Matrix homeserver на одной виртуальной машине без большого количества отдельных сервисов.&lt;br /&gt;
&lt;br /&gt;
Преимущества:&lt;br /&gt;
&lt;br /&gt;
* компактная архитектура;&lt;br /&gt;
* написан на Go;&lt;br /&gt;
* сравнительно небольшое потребление ресурсов;&lt;br /&gt;
* поддержка PostgreSQL;&lt;br /&gt;
* поддержка Matrix Client API;&lt;br /&gt;
* федерация;&lt;br /&gt;
* E2EE;&lt;br /&gt;
* media API;&lt;br /&gt;
* интеграция с TURN.&lt;br /&gt;
&lt;br /&gt;
Особенность выбранной архитектуры — Dendrite работает как единый монолитный процесс.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL используется для постоянного хранения данных Matrix.&lt;br /&gt;
&lt;br /&gt;
В базе находятся:&lt;br /&gt;
&lt;br /&gt;
* события комнат;&lt;br /&gt;
* пользователи;&lt;br /&gt;
* состояния комнат;&lt;br /&gt;
* устройства;&lt;br /&gt;
* ключи;&lt;br /&gt;
* данные федерации;&lt;br /&gt;
* служебные данные homeserver.&lt;br /&gt;
&lt;br /&gt;
PostgreSQL должен размещаться на локальном быстром диске VM.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Dendrite&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
PostgreSQL&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
Local SSD / VM Disk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Размещать активную БД PostgreSQL на NFS не рекомендуется.&lt;br /&gt;
&lt;br /&gt;
== Element ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Element&#039;&#039;&#039; используется как основной клиент RAMBA Matrix.&lt;br /&gt;
&lt;br /&gt;
Поддерживаются:&lt;br /&gt;
&lt;br /&gt;
* Element Web;&lt;br /&gt;
* Element для Android;&lt;br /&gt;
* Element для iOS;&lt;br /&gt;
* desktop-клиенты.&lt;br /&gt;
&lt;br /&gt;
Веб-клиент доступен через:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://element.ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Он заранее настроен на homeserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://chat.ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Поэтому обычному пользователю не требуется вручную указывать сервер.&lt;br /&gt;
&lt;br /&gt;
== Reverse Proxy ==&lt;br /&gt;
&lt;br /&gt;
Публичный HTTPS-трафик проходит через BrainyCP.&lt;br /&gt;
&lt;br /&gt;
Схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Client&lt;br /&gt;
  │&lt;br /&gt;
  │ HTTPS&lt;br /&gt;
  ▼&lt;br /&gt;
BrainyCP / Nginx&lt;br /&gt;
  │&lt;br /&gt;
  │ proxy_pass&lt;br /&gt;
  ▼&lt;br /&gt;
Dendrite&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет:&lt;br /&gt;
&lt;br /&gt;
* централизованно управлять SSL;&lt;br /&gt;
* не публиковать Dendrite напрямую;&lt;br /&gt;
* использовать единый внешний веб-уровень;&lt;br /&gt;
* независимо переносить backend между VM или узлами Proxmox.&lt;br /&gt;
&lt;br /&gt;
Основные proxy-заголовки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
proxy_set_header Host $host;&lt;br /&gt;
proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После изменения конфигурации Nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nginx -t&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix .well-known ==&lt;br /&gt;
&lt;br /&gt;
Чтобы пользователи имели ID:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
@user:ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
а физический homeserver находился на `chat.ramba-art.ru`, используется Matrix delegation.&lt;br /&gt;
&lt;br /&gt;
=== Server discovery ===&lt;br /&gt;
&lt;br /&gt;
Адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://ramba-art.ru/.well-known/matrix/server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;m.server&amp;quot;: &amp;quot;chat.ramba-art.ru:443&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Client discovery ===&lt;br /&gt;
&lt;br /&gt;
Адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://ramba-art.ru/.well-known/matrix/client&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;m.homeserver&amp;quot;: {&lt;br /&gt;
    &amp;quot;base_url&amp;quot;: &amp;quot;https://chat.ramba-art.ru&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s https://ramba-art.ru/.well-known/matrix/server&lt;br /&gt;
curl -s https://ramba-art.ru/.well-known/matrix/client&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка Matrix API ==&lt;br /&gt;
&lt;br /&gt;
Основная проверка homeserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s \&lt;br /&gt;
https://chat.ramba-art.ru/_matrix/client/versions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При исправной конфигурации сервер возвращает JSON со списком поддерживаемых версий Matrix Client API.&lt;br /&gt;
&lt;br /&gt;
== Dendrite ==&lt;br /&gt;
&lt;br /&gt;
Рабочая конфигурация находится в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/opt/dendrite/dendrite.yaml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основные файлы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/opt/dendrite/&lt;br /&gt;
├── dendrite&lt;br /&gt;
├── dendrite.yaml&lt;br /&gt;
├── matrix_key.pem&lt;br /&gt;
└── media/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ключевой параметр:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;yaml&amp;quot;&amp;gt;&lt;br /&gt;
global:&lt;br /&gt;
  server_name: ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`server_name` после ввода системы в эксплуатацию менять не следует.&lt;br /&gt;
&lt;br /&gt;
Он является частью Matrix ID пользователей и идентичности homeserver.&lt;br /&gt;
&lt;br /&gt;
== Systemd ==&lt;br /&gt;
&lt;br /&gt;
Dendrite запускается как системная служба.&lt;br /&gt;
&lt;br /&gt;
Управление:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start dendrite&lt;br /&gt;
systemctl stop dendrite&lt;br /&gt;
systemctl restart dendrite&lt;br /&gt;
systemctl status dendrite&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Просмотр журнала:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u dendrite -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последние записи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u dendrite -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Регистрация пользователей ==&lt;br /&gt;
&lt;br /&gt;
RAMBA Matrix работает как закрытая корпоративная система.&lt;br /&gt;
&lt;br /&gt;
Публичная регистрация пользователей отключена.&lt;br /&gt;
&lt;br /&gt;
Пользовательские записи создаются администратором.&lt;br /&gt;
&lt;br /&gt;
Общая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Администратор&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Создание аккаунта&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
@username:ramba-art.ru&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Первый вход пользователя&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой вариант позволяет контролировать доступ к системе и предотвращает автоматическую регистрацию посторонних пользователей.&lt;br /&gt;
&lt;br /&gt;
== Сквозное шифрование ==&lt;br /&gt;
&lt;br /&gt;
Matrix поддерживает End-to-End Encryption.&lt;br /&gt;
&lt;br /&gt;
В зашифрованной комнате сообщение шифруется на клиенте отправителя и расшифровывается на устройстве получателя.&lt;br /&gt;
&lt;br /&gt;
Упрощённая схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Client A&lt;br /&gt;
   │&lt;br /&gt;
   │ encrypted event&lt;br /&gt;
   ▼&lt;br /&gt;
Matrix Server&lt;br /&gt;
   │&lt;br /&gt;
   │ encrypted event&lt;br /&gt;
   ▼&lt;br /&gt;
Client B&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Homeserver хранит зашифрованное содержимое и не должен обладать ключами для расшифровки сообщений пользователей.&lt;br /&gt;
&lt;br /&gt;
Для пользователей особенно важно настроить восстановление ключей и не терять данные безопасного хранилища.&lt;br /&gt;
&lt;br /&gt;
== Media Store ==&lt;br /&gt;
&lt;br /&gt;
Matrix хранит загружаемые изображения, документы, видео и другие вложения отдельно от основной PostgreSQL БД.&lt;br /&gt;
&lt;br /&gt;
Для RAMBA Matrix media store вынесен на отдельное хранилище.&lt;br /&gt;
&lt;br /&gt;
Схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Dendrite VM&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
Media directory&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
NFS&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
OMV Storage&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет не увеличивать системный диск VM по мере роста количества вложений.&lt;br /&gt;
&lt;br /&gt;
PostgreSQL при этом остаётся на локальном диске.&lt;br /&gt;
&lt;br /&gt;
== Права на NFS ==&lt;br /&gt;
&lt;br /&gt;
При использовании NFS необходимо обеспечить правильные UID/GID пользователя, под которым работает Dendrite.&lt;br /&gt;
&lt;br /&gt;
После монтирования следует проверить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mount | grep matrix&lt;br /&gt;
ls -ld /matrix-media&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И тест записи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
touch /matrix-media/test&lt;br /&gt;
rm /matrix-media/test&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тест необходимо выполнять от имени пользователя Dendrite.&lt;br /&gt;
&lt;br /&gt;
== Coturn ==&lt;br /&gt;
&lt;br /&gt;
Coturn используется для STUN/TURN и обеспечивает работу звонков в сложных NAT-сценариях.&lt;br /&gt;
&lt;br /&gt;
Без TURN два клиента могут успешно обмениваться сообщениями, но не иметь возможности установить аудио- или видеосоединение.&lt;br /&gt;
&lt;br /&gt;
Архитектура звонка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Element A&lt;br /&gt;
    │&lt;br /&gt;
    │ WebRTC&lt;br /&gt;
    ▼&lt;br /&gt;
STUN / TURN&lt;br /&gt;
    │&lt;br /&gt;
    ▼&lt;br /&gt;
 Coturn&lt;br /&gt;
    │&lt;br /&gt;
    │ Relay&lt;br /&gt;
    ▼&lt;br /&gt;
Element B&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== TURN-порты ==&lt;br /&gt;
&lt;br /&gt;
В инфраструктуре используется ограниченный диапазон relay-портов:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Порт&lt;br /&gt;
! Протокол&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| 3478&lt;br /&gt;
| TCP / UDP&lt;br /&gt;
| STUN / TURN&lt;br /&gt;
|-&lt;br /&gt;
| 5349&lt;br /&gt;
| TCP&lt;br /&gt;
| TURN over TLS&lt;br /&gt;
|-&lt;br /&gt;
| 49152–49252&lt;br /&gt;
| UDP&lt;br /&gt;
| TURN Relay&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Этот диапазон должен быть разрешён firewall и корректно проброшен через NAT.&lt;br /&gt;
&lt;br /&gt;
== Пример конфигурации Coturn ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
listening-port=3478&lt;br /&gt;
tls-listening-port=5349&lt;br /&gt;
&lt;br /&gt;
use-auth-secret&lt;br /&gt;
realm=ramba-art.ru&lt;br /&gt;
&lt;br /&gt;
fingerprint&lt;br /&gt;
lt-cred-mech&lt;br /&gt;
&lt;br /&gt;
min-port=49152&lt;br /&gt;
max-port=49252&lt;br /&gt;
&lt;br /&gt;
no-multicast-peers&lt;br /&gt;
no-cli&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также должны быть корректно настроены:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
listening-ip=&lt;br /&gt;
relay-ip=&lt;br /&gt;
external-ip=&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конкретные значения зависят от текущей сетевой архитектуры.&lt;br /&gt;
&lt;br /&gt;
== TURN в Dendrite ==&lt;br /&gt;
&lt;br /&gt;
В конфигурации Dendrite указываются URI TURN-сервера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;yaml&amp;quot;&amp;gt;&lt;br /&gt;
client_api:&lt;br /&gt;
  turn:&lt;br /&gt;
    turn_user_lifetime: &amp;quot;5m&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    turn_uris:&lt;br /&gt;
      - &amp;quot;turn:turn.ramba-art.ru:3478?transport=udp&amp;quot;&lt;br /&gt;
      - &amp;quot;turn:turn.ramba-art.ru:3478?transport=tcp&amp;quot;&lt;br /&gt;
      - &amp;quot;turns:turn.ramba-art.ru:5349?transport=tcp&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    turn_shared_secret: &amp;quot;SECRET&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`turn_shared_secret` должен совпадать с `static-auth-secret` Coturn.&lt;br /&gt;
&lt;br /&gt;
Секреты не следует публиковать в Wiki.&lt;br /&gt;
&lt;br /&gt;
== Проверка TURN ==&lt;br /&gt;
&lt;br /&gt;
Проверка выдачи временных TURN credentials:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s \&lt;br /&gt;
https://chat.ramba-art.ru/_matrix/client/v3/voip/turnServer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В рабочем состоянии сервер возвращает:&lt;br /&gt;
&lt;br /&gt;
* username;&lt;br /&gt;
* password;&lt;br /&gt;
* TTL;&lt;br /&gt;
* список TURN URI.&lt;br /&gt;
&lt;br /&gt;
== Тестирование звонков ==&lt;br /&gt;
&lt;br /&gt;
Для корректной проверки необходимо использовать два независимых устройства.&lt;br /&gt;
&lt;br /&gt;
Желательно:&lt;br /&gt;
&lt;br /&gt;
* одно устройство через Wi-Fi;&lt;br /&gt;
* второе через мобильную сеть.&lt;br /&gt;
&lt;br /&gt;
Это заставляет WebRTC проходить через реальные NAT-сценарии.&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
# текстовые сообщения;&lt;br /&gt;
# зашифрованный личный чат;&lt;br /&gt;
# аудиозвонок;&lt;br /&gt;
# видеозвонок;&lt;br /&gt;
# входящий вызов;&lt;br /&gt;
# работу после переключения сети.&lt;br /&gt;
&lt;br /&gt;
Успешный звонок через разные сети подтверждает работу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Element&lt;br /&gt;
   +&lt;br /&gt;
Dendrite&lt;br /&gt;
   +&lt;br /&gt;
WebRTC&lt;br /&gt;
   +&lt;br /&gt;
STUN&lt;br /&gt;
   +&lt;br /&gt;
TURN&lt;br /&gt;
   +&lt;br /&gt;
NAT&lt;br /&gt;
   +&lt;br /&gt;
Firewall&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Element Web ==&lt;br /&gt;
&lt;br /&gt;
Element Web работает на отдельном домене:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://element.ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример основных параметров `config.json`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;default_server_config&amp;quot;: {&lt;br /&gt;
    &amp;quot;m.homeserver&amp;quot;: {&lt;br /&gt;
      &amp;quot;base_url&amp;quot;: &amp;quot;https://chat.ramba-art.ru&amp;quot;,&lt;br /&gt;
      &amp;quot;server_name&amp;quot;: &amp;quot;ramba-art.ru&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  },&lt;br /&gt;
&lt;br /&gt;
  &amp;quot;disable_custom_urls&amp;quot;: true,&lt;br /&gt;
  &amp;quot;disable_guests&amp;quot;: true,&lt;br /&gt;
  &amp;quot;brand&amp;quot;: &amp;quot;RAMBA Chat&amp;quot;,&lt;br /&gt;
  &amp;quot;default_theme&amp;quot;: &amp;quot;dark&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Благодаря этому пользователю достаточно открыть Element и войти под своим RAMBA Matrix аккаунтом.&lt;br /&gt;
&lt;br /&gt;
== Мобильные клиенты ==&lt;br /&gt;
&lt;br /&gt;
На мобильных устройствах используются Matrix-совместимые клиенты.&lt;br /&gt;
&lt;br /&gt;
Для подключения используется homeserver:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://chat.ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Либо автоматическое обнаружение через:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После входа рекомендуется сразу настроить:&lt;br /&gt;
&lt;br /&gt;
* подтверждение устройства;&lt;br /&gt;
* безопасное хранилище;&lt;br /&gt;
* восстановление ключей;&lt;br /&gt;
* PIN/Face ID клиента;&lt;br /&gt;
* push-уведомления.&lt;br /&gt;
&lt;br /&gt;
== Федерация ==&lt;br /&gt;
&lt;br /&gt;
Matrix поддерживает обмен событиями между независимыми homeserver.&lt;br /&gt;
&lt;br /&gt;
Для федерации используется server name:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и delegation на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
chat.ramba-art.ru&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Базовая проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s \&lt;br /&gt;
https://ramba-art.ru/.well-known/matrix/server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При проблемах с федерацией необходимо проверять:&lt;br /&gt;
&lt;br /&gt;
* DNS;&lt;br /&gt;
* TLS;&lt;br /&gt;
* `.well-known`;&lt;br /&gt;
* доступность `chat.ramba-art.ru`;&lt;br /&gt;
* Nginx;&lt;br /&gt;
* журнал Dendrite.&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
Matrix нельзя считать защищённым только потому, что существует snapshot VM.&lt;br /&gt;
&lt;br /&gt;
Необходимо резервировать отдельно:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Требуется backup&lt;br /&gt;
|-&lt;br /&gt;
| PostgreSQL&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| dendrite.yaml&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| matrix_key.pem&lt;br /&gt;
| &#039;&#039;&#039;Обязательно&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Media Store&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Coturn config&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| Element config.json&lt;br /&gt;
| Да&lt;br /&gt;
|-&lt;br /&gt;
| BrainyCP / Nginx vhost&lt;br /&gt;
| Да&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Особенно критичен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
matrix_key.pem&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это identity key Matrix homeserver. Его потеря может привести к серьёзным проблемам с федерацией и идентичностью сервера.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL backup ==&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
sudo -u postgres \&lt;br /&gt;
pg_dump dendrite \&lt;br /&gt;
&amp;gt; /root/dendrite-$(date +%F).sql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lh /root/dendrite-*.sql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для production рекомендуется автоматизировать резервное копирование и периодически тестировать восстановление.&lt;br /&gt;
&lt;br /&gt;
== Backup конфигурации ==&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
tar -czf /root/ramba-matrix-config-$(date +%F).tar.gz \&lt;br /&gt;
    /opt/dendrite/dendrite.yaml \&lt;br /&gt;
    /opt/dendrite/matrix_key.pem \&lt;br /&gt;
    /etc/turnserver.conf \&lt;br /&gt;
    /etc/systemd/system/dendrite.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Файл с `matrix_key.pem` должен храниться в защищённом месте.&lt;br /&gt;
&lt;br /&gt;
== Proxmox Backup ==&lt;br /&gt;
&lt;br /&gt;
Виртуальная машина RAMBA Matrix также резервируется средствами Proxmox.&lt;br /&gt;
&lt;br /&gt;
Схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
RAMBA Matrix VM&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Proxmox VE&lt;br /&gt;
      │&lt;br /&gt;
      ▼&lt;br /&gt;
Proxmox Backup Server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Backup VM полезен для быстрого полного восстановления, но не заменяет логический dump PostgreSQL.&lt;br /&gt;
&lt;br /&gt;
== Мониторинг ==&lt;br /&gt;
&lt;br /&gt;
Минимальный набор проверок:&lt;br /&gt;
&lt;br /&gt;
=== Dendrite ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status dendrite&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== PostgreSQL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status postgresql&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Coturn ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status coturn&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Matrix API ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s \&lt;br /&gt;
https://chat.ramba-art.ru/_matrix/client/versions&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== TURN ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s \&lt;br /&gt;
https://chat.ramba-art.ru/_matrix/client/v3/voip/turnServer&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Media storage ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
df -h&lt;br /&gt;
mount | grep matrix&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Диагностика ==&lt;br /&gt;
&lt;br /&gt;
=== Dendrite не запускается ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status dendrite&lt;br /&gt;
journalctl -u dendrite -n 100 --no-pager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Matrix API недоступен ===&lt;br /&gt;
&lt;br /&gt;
Проверяем цепочку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Client&lt;br /&gt;
  │&lt;br /&gt;
  ▼&lt;br /&gt;
DNS&lt;br /&gt;
  │&lt;br /&gt;
  ▼&lt;br /&gt;
BrainyCP&lt;br /&gt;
  │&lt;br /&gt;
  ▼&lt;br /&gt;
Nginx&lt;br /&gt;
  │&lt;br /&gt;
  ▼&lt;br /&gt;
Dendrite&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем внешний адрес:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -Iv https://chat.ramba-art.ru/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И backend непосредственно из LAN:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -I http://MATRIX_BACKEND_IP:8008/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Звонок соединяется без аудио ===&lt;br /&gt;
&lt;br /&gt;
В первую очередь проверяем:&lt;br /&gt;
&lt;br /&gt;
* Coturn;&lt;br /&gt;
* relay UDP range;&lt;br /&gt;
* NAT;&lt;br /&gt;
* `external-ip`;&lt;br /&gt;
* firewall;&lt;br /&gt;
* TURN credentials.&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ss -tulpn | grep turnserver&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Не загружаются медиа ===&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mount | grep matrix&lt;br /&gt;
df -h&lt;br /&gt;
ls -ld /matrix-media&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также необходимо проверить права пользователя Dendrite на NFS.&lt;br /&gt;
&lt;br /&gt;
== Производительность ==&lt;br /&gt;
&lt;br /&gt;
Основная нагрузка Matrix распределяется между:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
CPU&lt;br /&gt;
 │&lt;br /&gt;
 ├── Dendrite&lt;br /&gt;
 ├── PostgreSQL&lt;br /&gt;
 └── Federation&lt;br /&gt;
&lt;br /&gt;
RAM&lt;br /&gt;
 │&lt;br /&gt;
 ├── Dendrite&lt;br /&gt;
 └── PostgreSQL&lt;br /&gt;
&lt;br /&gt;
Disk&lt;br /&gt;
 │&lt;br /&gt;
 ├── PostgreSQL&lt;br /&gt;
 └── Media&lt;br /&gt;
&lt;br /&gt;
Network&lt;br /&gt;
 │&lt;br /&gt;
 ├── Federation&lt;br /&gt;
 ├── Media&lt;br /&gt;
 └── TURN&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для небольшого и среднего deployment особенно важны:&lt;br /&gt;
&lt;br /&gt;
* быстрый локальный диск PostgreSQL;&lt;br /&gt;
* достаточный объём RAM;&lt;br /&gt;
* стабильное сетевое подключение;&lt;br /&gt;
* отдельное пространство для media store.&lt;br /&gt;
&lt;br /&gt;
== Масштабирование ==&lt;br /&gt;
&lt;br /&gt;
Текущая архитектура намеренно проста:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
1 VM&lt;br /&gt;
 │&lt;br /&gt;
 ├── Dendrite&lt;br /&gt;
 ├── PostgreSQL&lt;br /&gt;
 └── Coturn&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
По мере роста можно отдельно масштабировать:&lt;br /&gt;
&lt;br /&gt;
* PostgreSQL;&lt;br /&gt;
* media store;&lt;br /&gt;
* TURN;&lt;br /&gt;
* reverse proxy;&lt;br /&gt;
* мониторинг;&lt;br /&gt;
* резервное копирование.&lt;br /&gt;
&lt;br /&gt;
Media Store уже удобно отделять от системного диска через NFS.&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
Для RAMBA Matrix рекомендуется:&lt;br /&gt;
&lt;br /&gt;
* держать публичную регистрацию отключённой;&lt;br /&gt;
* использовать E2EE;&lt;br /&gt;
* не публиковать PostgreSQL;&lt;br /&gt;
* не публиковать внутренний порт Dendrite;&lt;br /&gt;
* не хранить секреты в Wiki;&lt;br /&gt;
* регулярно менять административные пароли;&lt;br /&gt;
* ограничивать SSH;&lt;br /&gt;
* резервировать `matrix_key.pem`;&lt;br /&gt;
* хранить backup вне основной VM;&lt;br /&gt;
* обновлять Dendrite, PostgreSQL, Element и Coturn;&lt;br /&gt;
* проверять журналы после обновлений.&lt;br /&gt;
&lt;br /&gt;
== Полезные команды ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Задача&lt;br /&gt;
! Команда&lt;br /&gt;
|-&lt;br /&gt;
| Статус Dendrite&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status dendrite&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Перезапуск Dendrite&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart dendrite&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Логи Dendrite&lt;br /&gt;
| &amp;lt;code&amp;gt;journalctl -u dendrite -f&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Статус PostgreSQL&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status postgresql&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Статус Coturn&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status coturn&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить Matrix API&lt;br /&gt;
| &amp;lt;code&amp;gt;curl -s https://chat.ramba-art.ru/_matrix/client/versions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить TURN&lt;br /&gt;
| &amp;lt;code&amp;gt;curl -s https://chat.ramba-art.ru/_matrix/client/v3/voip/turnServer&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить NFS&lt;br /&gt;
| &amp;lt;code&amp;gt;mount | grep matrix&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить диск&lt;br /&gt;
| &amp;lt;code&amp;gt;df -h&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Итоговая схема ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                        USERS&lt;br /&gt;
                          │&lt;br /&gt;
             ┌────────────┴────────────┐&lt;br /&gt;
             │                         │&lt;br /&gt;
             ▼                         ▼&lt;br /&gt;
       Element Web               Element Mobile&lt;br /&gt;
             │                         │&lt;br /&gt;
             └────────────┬────────────┘&lt;br /&gt;
                          │&lt;br /&gt;
                          │ HTTPS&lt;br /&gt;
                          ▼&lt;br /&gt;
                 ┌─────────────────┐&lt;br /&gt;
                 │     BrainyCP    │&lt;br /&gt;
                 │      Nginx      │&lt;br /&gt;
                 │       SSL       │&lt;br /&gt;
                 └────────┬────────┘&lt;br /&gt;
                          │&lt;br /&gt;
                          ▼&lt;br /&gt;
                 ┌─────────────────┐&lt;br /&gt;
                 │    Dendrite     │&lt;br /&gt;
                 └──────┬─────┬────┘&lt;br /&gt;
                        │     │&lt;br /&gt;
                        │     └──────────────┐&lt;br /&gt;
                        ▼                    ▼&lt;br /&gt;
                  PostgreSQL              Coturn&lt;br /&gt;
                        │                    │&lt;br /&gt;
                        │                    ▼&lt;br /&gt;
                        │               TURN Relay&lt;br /&gt;
                        │&lt;br /&gt;
                        ▼&lt;br /&gt;
                   Local Disk&lt;br /&gt;
&lt;br /&gt;
                    Media API&lt;br /&gt;
                        │&lt;br /&gt;
                        ▼&lt;br /&gt;
                    OMV / NFS&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Результат ==&lt;br /&gt;
&lt;br /&gt;
RAMBA Matrix представляет собой полностью самостоятельную коммуникационную платформу, работающую на инфраструктуре RAMBA ART.&lt;br /&gt;
&lt;br /&gt;
Система обеспечивает:&lt;br /&gt;
&lt;br /&gt;
* собственные Matrix ID;&lt;br /&gt;
* личные и групповые чаты;&lt;br /&gt;
* E2EE;&lt;br /&gt;
* Android и iOS;&lt;br /&gt;
* Element Web;&lt;br /&gt;
* голосовые звонки;&lt;br /&gt;
* видеозвонки;&lt;br /&gt;
* собственное хранение данных;&lt;br /&gt;
* резервное копирование;&lt;br /&gt;
* федерацию;&lt;br /&gt;
* возможность дальнейшего масштабирования.&lt;br /&gt;
&lt;br /&gt;
При этом публичный веб-уровень, Matrix backend, база данных и media store разделены между отдельными компонентами инфраструктуры.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
&lt;br /&gt;
* [[BrainyCP]]&lt;br /&gt;
* [[Proxmox VE]]&lt;br /&gt;
* [[Proxmox Backup Server]]&lt;br /&gt;
* [[OpenMediaVault]]&lt;br /&gt;
* [[RAMBA Wiki]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
== Внешние ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [https://matrix.org/ Matrix.org]&lt;br /&gt;
* [https://spec.matrix.org/ Matrix Specification]&lt;br /&gt;
* [https://github.com/element-hq/dendrite Dendrite]&lt;br /&gt;
* [https://element.io/ Element]&lt;br /&gt;
* [https://github.com/coturn/coturn Coturn]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Matrix]]&lt;br /&gt;
[[Категория:RAMBA Matrix]]&lt;br /&gt;
[[Категория:Мессенджеры]]&lt;br /&gt;
[[Категория:Linux]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Сетевая инфраструктура]]&lt;br /&gt;
[[Категория:RAMBA ART]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Minecraft_%D0%B2_2026_%D0%B3%D0%BE%D0%B4%D1%83&amp;diff=141</id>
		<title>Minecraft в 2026 году</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Minecraft_%D0%B2_2026_%D0%B3%D0%BE%D0%B4%D1%83&amp;diff=141"/>
		<updated>2026-09-02T10:30:44Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-title&amp;quot;&amp;gt;Minecraft Java Server&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-subtitle&amp;quot;&amp;gt;&lt;br /&gt;
Установка и эксплуатация выделенного сервера Minecraft на Ubuntu 24.04 LTS&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Minecraft Java Server&#039;&#039;&#039; — выделенный сервер для Minecraft Java Edition.&lt;br /&gt;
&lt;br /&gt;
В этой статье рассматривается установка сервера на &#039;&#039;&#039;Ubuntu 24.04 LTS&#039;&#039;&#039; с отдельным системным пользователем, автоматическим запуском через systemd, RCON-управлением и резервным копированием.&lt;br /&gt;
&lt;br /&gt;
Конфигурация подходит для виртуальной машины, физического сервера или LXC-контейнера.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Архитектура ==&lt;br /&gt;
&lt;br /&gt;
Базовая схема сервера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                    Игроки&lt;br /&gt;
                       │&lt;br /&gt;
                       │ TCP :25565&lt;br /&gt;
                       ▼&lt;br /&gt;
               ┌───────────────┐&lt;br /&gt;
               │   Minecraft   │&lt;br /&gt;
               │ Java Server   │&lt;br /&gt;
               └───────┬───────┘&lt;br /&gt;
                       │&lt;br /&gt;
              ┌────────┴────────┐&lt;br /&gt;
              │                 │&lt;br /&gt;
              ▼                 ▼&lt;br /&gt;
          systemd              RCON&lt;br /&gt;
                                  │&lt;br /&gt;
                                  ▼&lt;br /&gt;
                               mcrcon&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В production-конфигурации Minecraft запускается не вручную, а как системная служба.&lt;br /&gt;
&lt;br /&gt;
== Системные требования ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Минимально&lt;br /&gt;
! Рекомендуется&lt;br /&gt;
|-&lt;br /&gt;
| CPU&lt;br /&gt;
| 2 vCPU&lt;br /&gt;
| 4+ производительных ядра&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 4 ГБ&lt;br /&gt;
| 8 ГБ и более&lt;br /&gt;
|-&lt;br /&gt;
| Диск&lt;br /&gt;
| 20 ГБ&lt;br /&gt;
| 50+ ГБ SSD&lt;br /&gt;
|-&lt;br /&gt;
| ОС&lt;br /&gt;
| Ubuntu 24.04 LTS&lt;br /&gt;
| Ubuntu 24.04 LTS&lt;br /&gt;
|-&lt;br /&gt;
| Сеть&lt;br /&gt;
| 25565/TCP&lt;br /&gt;
| Статический IP или NAT&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
При большой дальности прорисовки, большом количестве игроков или тяжёлых модификациях требования к CPU и RAM могут значительно возрастать.&lt;br /&gt;
&lt;br /&gt;
== Подготовка системы ==&lt;br /&gt;
&lt;br /&gt;
Обновляем систему:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
apt upgrade -y&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Устанавливаем необходимые инструменты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y \&lt;br /&gt;
    wget \&lt;br /&gt;
    curl \&lt;br /&gt;
    git \&lt;br /&gt;
    nano \&lt;br /&gt;
    unzip \&lt;br /&gt;
    build-essential&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем время и часовой пояс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
timedatectl&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При необходимости:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
timedatectl set-timezone Europe/Moscow&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Установка Java ==&lt;br /&gt;
&lt;br /&gt;
Версия Java зависит от версии Minecraft.&lt;br /&gt;
&lt;br /&gt;
Перед установкой рекомендуется проверить требования конкретной версии сервера.&lt;br /&gt;
&lt;br /&gt;
Для современных версий Minecraft обычно используется Java 21:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt install -y openjdk-21-jdk&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
java -version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
openjdk version &amp;quot;21&amp;quot;&lt;br /&gt;
OpenJDK Runtime Environment&lt;br /&gt;
OpenJDK 64-Bit Server VM&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка установленной Java ===&lt;br /&gt;
&lt;br /&gt;
Путь до Java:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
which java&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обычно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/usr/bin/java&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Создание пользователя Minecraft ==&lt;br /&gt;
&lt;br /&gt;
Minecraft не следует запускать от имени root.&lt;br /&gt;
&lt;br /&gt;
Создаём отдельного системного пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
useradd \&lt;br /&gt;
    --system \&lt;br /&gt;
    --create-home \&lt;br /&gt;
    --user-group \&lt;br /&gt;
    --home-dir /opt/minecraft \&lt;br /&gt;
    --shell /bin/bash \&lt;br /&gt;
    minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
id minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Переходим под него:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
su - minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Домашним каталогом пользователя будет:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/opt/minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Структура каталогов ==&lt;br /&gt;
&lt;br /&gt;
Создаём:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p ~/server&lt;br /&gt;
mkdir -p ~/backups&lt;br /&gt;
mkdir -p ~/tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Структура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/opt/minecraft/&lt;br /&gt;
├── server/&lt;br /&gt;
│   ├── server.jar&lt;br /&gt;
│   ├── server.properties&lt;br /&gt;
│   ├── eula.txt&lt;br /&gt;
│   ├── world/&lt;br /&gt;
│   └── logs/&lt;br /&gt;
│&lt;br /&gt;
├── backups/&lt;br /&gt;
│&lt;br /&gt;
└── tools/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Назначение:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;server&#039;&#039;&#039; — сервер Minecraft;&lt;br /&gt;
* &#039;&#039;&#039;backups&#039;&#039;&#039; — резервные копии;&lt;br /&gt;
* &#039;&#039;&#039;tools&#039;&#039;&#039; — вспомогательные утилиты.&lt;br /&gt;
&lt;br /&gt;
== Установка mcrcon ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;mcrcon&#039;&#039;&#039; используется для отправки команд Minecraft через RCON.&lt;br /&gt;
&lt;br /&gt;
Клонируем проект:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/Tiiffi/mcrcon.git ~/tools/mcrcon&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Компилируем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd ~/tools/mcrcon&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
./mcrcon -v&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Установка Minecraft Server ==&lt;br /&gt;
&lt;br /&gt;
Переходим:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/minecraft/server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Актуальный файл &#039;&#039;&#039;server.jar&#039;&#039;&#039; необходимо скачивать с официального сайта Minecraft/Mojang.&lt;br /&gt;
&lt;br /&gt;
После получения ссылки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
wget -O server.jar \&lt;br /&gt;
&#039;https://piston-data.mojang.com/.../server.jar&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lh server.jar&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Первый запуск ==&lt;br /&gt;
&lt;br /&gt;
Первый запуск нужен для генерации конфигурации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
java -Xms2G -Xmx4G -jar server.jar nogui&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сервер остановится, поскольку EULA ещё не принята.&lt;br /&gt;
&lt;br /&gt;
После запуска появятся:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
eula.txt&lt;br /&gt;
server.properties&lt;br /&gt;
logs/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Принятие EULA ==&lt;br /&gt;
&lt;br /&gt;
Открываем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano eula.txt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Меняем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
eula=false&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
eula=true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохраняем файл.&lt;br /&gt;
&lt;br /&gt;
== Базовая настройка server.properties ==&lt;br /&gt;
&lt;br /&gt;
Открываем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano server.properties&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основные параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;properties&amp;quot;&amp;gt;&lt;br /&gt;
server-port=25565&lt;br /&gt;
&lt;br /&gt;
max-players=100&lt;br /&gt;
&lt;br /&gt;
online-mode=true&lt;br /&gt;
&lt;br /&gt;
enable-command-block=false&lt;br /&gt;
&lt;br /&gt;
view-distance=10&lt;br /&gt;
simulation-distance=10&lt;br /&gt;
&lt;br /&gt;
motd=RAMBA-ART Minecraft Server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для публичного сервера рекомендуется оставлять:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;properties&amp;quot;&amp;gt;&lt;br /&gt;
online-mode=true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это включает проверку учётных записей Mojang/Microsoft.&lt;br /&gt;
&lt;br /&gt;
== Настройка RCON ==&lt;br /&gt;
&lt;br /&gt;
В `server.properties`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;properties&amp;quot;&amp;gt;&lt;br /&gt;
enable-rcon=true&lt;br /&gt;
rcon.port=25575&lt;br /&gt;
rcon.password=CHANGE_THIS_PASSWORD&lt;br /&gt;
broadcast-rcon-to-ops=true&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После изменения сервер необходимо перезапустить.&lt;br /&gt;
&lt;br /&gt;
=== Безопасность RCON ===&lt;br /&gt;
&lt;br /&gt;
RCON не рекомендуется публиковать напрямую в Интернет.&lt;br /&gt;
&lt;br /&gt;
Предпочтительная схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
mcrcon&lt;br /&gt;
   │&lt;br /&gt;
   │ 127.0.0.1:25575&lt;br /&gt;
   ▼&lt;br /&gt;
Minecraft Server&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
То есть порт `25575` должен использоваться только локально либо через защищённую административную сеть/VPN.&lt;br /&gt;
&lt;br /&gt;
== Проверка ручного запуска ==&lt;br /&gt;
&lt;br /&gt;
Запускаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/minecraft/server&lt;br /&gt;
&lt;br /&gt;
java -Xms4G -Xmx6G \&lt;br /&gt;
    -jar server.jar \&lt;br /&gt;
    nogui&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если сервер успешно загрузился, в консоли появится сообщение примерно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Done (...)! For help, type &amp;quot;help&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После проверки останавливаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
stop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Создание systemd-службы ==&lt;br /&gt;
&lt;br /&gt;
Выходим из пользователя Minecraft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
exit&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/minecraft.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Содержимое:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Minecraft Java Server&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
&lt;br /&gt;
User=minecraft&lt;br /&gt;
Group=minecraft&lt;br /&gt;
&lt;br /&gt;
WorkingDirectory=/opt/minecraft/server&lt;br /&gt;
&lt;br /&gt;
ExecStart=/usr/bin/java \&lt;br /&gt;
    -Xms4G \&lt;br /&gt;
    -Xmx6G \&lt;br /&gt;
    -jar /opt/minecraft/server/server.jar \&lt;br /&gt;
    nogui&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=10&lt;br /&gt;
&lt;br /&gt;
SuccessExitStatus=0 143&lt;br /&gt;
&lt;br /&gt;
LimitNOFILE=65535&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Применяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Управление сервером ==&lt;br /&gt;
&lt;br /&gt;
Запуск:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Остановка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl stop minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перезапуск:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl restart minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Статус:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Логи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u minecraft -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последние 100 строк:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u minecraft -n 100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Подключение через RCON ==&lt;br /&gt;
&lt;br /&gt;
Под пользователем Minecraft:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
su - minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Подключение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
/opt/minecraft/tools/mcrcon/mcrcon \&lt;br /&gt;
    -H 127.0.0.1 \&lt;br /&gt;
    -P 25575 \&lt;br /&gt;
    -p &#039;CHANGE_THIS_PASSWORD&#039; \&lt;br /&gt;
    -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После подключения можно выполнять команды сервера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
list&lt;br /&gt;
say Server restart in 5 minutes&lt;br /&gt;
save-all&lt;br /&gt;
whitelist list&lt;br /&gt;
stop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выход из интерактивного режима mcrcon:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Q&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Настройка Firewall ==&lt;br /&gt;
&lt;br /&gt;
Для игроков требуется только:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
25565/TCP&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При использовании UFW:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ufw allow 25565/tcp&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ufw status&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RCON-порт 25575/TCP не следует открывать для всего Интернета.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Если сервер находится в LXC или VM под Proxmox, правила можно централизованно управлять через Proxmox Firewall.&lt;br /&gt;
&lt;br /&gt;
== Проверка порта Minecraft ==&lt;br /&gt;
&lt;br /&gt;
Проверяем локально:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ss -ltnp | grep 25565&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ожидаемый результат:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
LISTEN ... :25565&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также можно проверить процесс:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ps aux | grep &#039;[s]erver.jar&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
Для корректного backup мира желательно сначала заставить Minecraft записать данные на диск.&lt;br /&gt;
&lt;br /&gt;
Создаём конфигурационный файл для RCON:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/minecraft/.rcon.env&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Содержимое:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
RCON_HOST=127.0.0.1&lt;br /&gt;
RCON_PORT=25575&lt;br /&gt;
RCON_PASSWORD=&#039;CHANGE_THIS_PASSWORD&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ограничиваем доступ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown minecraft:minecraft /opt/minecraft/.rcon.env&lt;br /&gt;
chmod 600 /opt/minecraft/.rcon.env&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём backup-скрипт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/minecraft/tools/backup.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Содержимое:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
source /opt/minecraft/.rcon.env&lt;br /&gt;
&lt;br /&gt;
RCON=&amp;quot;/opt/minecraft/tools/mcrcon/mcrcon&amp;quot;&lt;br /&gt;
&lt;br /&gt;
BACKUP_DIR=&amp;quot;/opt/minecraft/backups&amp;quot;&lt;br /&gt;
SERVER_DIR=&amp;quot;/opt/minecraft/server&amp;quot;&lt;br /&gt;
&lt;br /&gt;
TIMESTAMP=&amp;quot;$(date +%F-%H-%M-%S)&amp;quot;&lt;br /&gt;
BACKUP_FILE=&amp;quot;${BACKUP_DIR}/minecraft-${TIMESTAMP}.tar.gz&amp;quot;&lt;br /&gt;
&lt;br /&gt;
$RCON \&lt;br /&gt;
    -H &amp;quot;$RCON_HOST&amp;quot; \&lt;br /&gt;
    -P &amp;quot;$RCON_PORT&amp;quot; \&lt;br /&gt;
    -p &amp;quot;$RCON_PASSWORD&amp;quot; \&lt;br /&gt;
    &amp;quot;save-off&amp;quot;&lt;br /&gt;
&lt;br /&gt;
$RCON \&lt;br /&gt;
    -H &amp;quot;$RCON_HOST&amp;quot; \&lt;br /&gt;
    -P &amp;quot;$RCON_PORT&amp;quot; \&lt;br /&gt;
    -p &amp;quot;$RCON_PASSWORD&amp;quot; \&lt;br /&gt;
    &amp;quot;save-all flush&amp;quot;&lt;br /&gt;
&lt;br /&gt;
tar \&lt;br /&gt;
    --exclude=&#039;./logs&#039; \&lt;br /&gt;
    -czf &amp;quot;$BACKUP_FILE&amp;quot; \&lt;br /&gt;
    -C &amp;quot;$SERVER_DIR&amp;quot; \&lt;br /&gt;
    .&lt;br /&gt;
&lt;br /&gt;
$RCON \&lt;br /&gt;
    -H &amp;quot;$RCON_HOST&amp;quot; \&lt;br /&gt;
    -P &amp;quot;$RCON_PORT&amp;quot; \&lt;br /&gt;
    -p &amp;quot;$RCON_PASSWORD&amp;quot; \&lt;br /&gt;
    &amp;quot;save-on&amp;quot;&lt;br /&gt;
&lt;br /&gt;
find &amp;quot;$BACKUP_DIR&amp;quot; \&lt;br /&gt;
    -type f \&lt;br /&gt;
    -name &#039;minecraft-*.tar.gz&#039; \&lt;br /&gt;
    -mtime +7 \&lt;br /&gt;
    -delete&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Делаем исполняемым:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x /opt/minecraft/tools/backup.sh&lt;br /&gt;
chown minecraft:minecraft /opt/minecraft/tools/backup.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестируем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
su - minecraft -c &#039;/opt/minecraft/tools/backup.sh&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ls -lh /opt/minecraft/backups/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Автоматическое резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
Переходим:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
su - minecraft&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Открываем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
crontab -e&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например, ежедневный backup в 04:00:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;cron&amp;quot;&amp;gt;&lt;br /&gt;
0 4 * * * /opt/minecraft/tools/backup.sh &amp;gt;&amp;gt; /opt/minecraft/backups/backup.log 2&amp;gt;&amp;amp;1&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
crontab -l&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Обновление Minecraft Server ==&lt;br /&gt;
&lt;br /&gt;
Перед обновлением:&lt;br /&gt;
&lt;br /&gt;
# создаём резервную копию;&lt;br /&gt;
# останавливаем сервер;&lt;br /&gt;
# сохраняем старый `server.jar`;&lt;br /&gt;
# устанавливаем новый;&lt;br /&gt;
# запускаем сервер;&lt;br /&gt;
# проверяем логи и совместимость мира.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl stop minecraft&lt;br /&gt;
&lt;br /&gt;
cp /opt/minecraft/server/server.jar \&lt;br /&gt;
   /opt/minecraft/server/server.jar.old&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После загрузки нового файла:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start minecraft&lt;br /&gt;
journalctl -u minecraft -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка ресурсов ==&lt;br /&gt;
&lt;br /&gt;
CPU и память:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
top&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
или:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
htop&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Память:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
free -h&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Диск:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
df -h&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Размер мира:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
du -sh /opt/minecraft/server/world*&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Java и Minecraft ==&lt;br /&gt;
&lt;br /&gt;
Требования Java меняются вместе с Minecraft.&lt;br /&gt;
&lt;br /&gt;
Общее правило:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Minecraft&lt;br /&gt;
! Java&lt;br /&gt;
|-&lt;br /&gt;
| 1.20.5 и новее&lt;br /&gt;
| Java 21&lt;br /&gt;
|-&lt;br /&gt;
| Старые версии&lt;br /&gt;
| Требования зависят от конкретного релиза&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Перед обновлением необходимо проверять требования именно для устанавливаемой версии Minecraft.&lt;br /&gt;
&lt;br /&gt;
Не стоит обновлять Java исключительно потому, что появилась более новая версия JDK.&lt;br /&gt;
&lt;br /&gt;
== Типичные проблемы ==&lt;br /&gt;
&lt;br /&gt;
=== Сервер не запускается ===&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status minecraft&lt;br /&gt;
journalctl -u minecraft -n 100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ошибка памяти ===&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
free -h&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При необходимости уменьшаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
-Xmx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Клиенты не подключаются ===&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ss -ltnp | grep 25565&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Затем:&lt;br /&gt;
&lt;br /&gt;
* Firewall;&lt;br /&gt;
* NAT;&lt;br /&gt;
* проброс портов;&lt;br /&gt;
* публичный IP;&lt;br /&gt;
* `server-port`;&lt;br /&gt;
* `server-ip`.&lt;br /&gt;
&lt;br /&gt;
Обычно `server-ip` рекомендуется оставлять пустым.&lt;br /&gt;
&lt;br /&gt;
=== RCON не работает ===&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
grep -E &#039;enable-rcon|rcon.port&#039; \&lt;br /&gt;
/opt/minecraft/server/server.properties&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ss -ltnp | grep 25575&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Рекомендации ==&lt;br /&gt;
&lt;br /&gt;
Для production-сервера рекомендуется:&lt;br /&gt;
&lt;br /&gt;
* запускать Minecraft от отдельного пользователя;&lt;br /&gt;
* использовать systemd;&lt;br /&gt;
* не открывать RCON в Интернет;&lt;br /&gt;
* выполнять ежедневные backup;&lt;br /&gt;
* хранить резервные копии вне основного сервера;&lt;br /&gt;
* использовать SSD;&lt;br /&gt;
* контролировать свободное место;&lt;br /&gt;
* регулярно проверять логи;&lt;br /&gt;
* делать backup перед обновлением;&lt;br /&gt;
* обновлять сервер только после проверки совместимости Java и Minecraft.&lt;br /&gt;
&lt;br /&gt;
== Полезные команды ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Задача&lt;br /&gt;
! Команда&lt;br /&gt;
|-&lt;br /&gt;
| Запуск&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl start minecraft&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Остановка&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl stop minecraft&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Перезапуск&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart minecraft&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Статус&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status minecraft&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Логи&lt;br /&gt;
| &amp;lt;code&amp;gt;journalctl -u minecraft -f&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить порт&lt;br /&gt;
| &amp;lt;code&amp;gt;ss -ltnp | grep 25565&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить Java&lt;br /&gt;
| &amp;lt;code&amp;gt;java -version&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить память&lt;br /&gt;
| &amp;lt;code&amp;gt;free -h&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить диск&lt;br /&gt;
| &amp;lt;code&amp;gt;df -h&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Итоговая архитектура ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
               Minecraft Client&lt;br /&gt;
                      │&lt;br /&gt;
                      │ TCP :25565&lt;br /&gt;
                      ▼&lt;br /&gt;
        ┌──────────────────────────┐&lt;br /&gt;
        │     Minecraft Server     │&lt;br /&gt;
        │                          │&lt;br /&gt;
        │        server.jar        │&lt;br /&gt;
        └────────────┬─────────────┘&lt;br /&gt;
                     │&lt;br /&gt;
        ┌────────────┼────────────┐&lt;br /&gt;
        │            │            │&lt;br /&gt;
        ▼            ▼            ▼&lt;br /&gt;
     systemd       mcrcon       backups&lt;br /&gt;
                      │&lt;br /&gt;
                      ▼&lt;br /&gt;
                localhost RCON&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой вариант удобен для постоянной эксплуатации, обновления, диагностики и восстановления сервера.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
&lt;br /&gt;
* [[Proxmox VE]]&lt;br /&gt;
* [[Linux]]&lt;br /&gt;
* [[Minecraft]]&lt;br /&gt;
* [[Резервное копирование]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
== Внешние ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.minecraft.net/ Официальный сайт Minecraft]&lt;br /&gt;
* [https://www.minecraft.net/download/server Minecraft Java Server]&lt;br /&gt;
* [https://github.com/Tiiffi/mcrcon mcrcon]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Minecraft]]&lt;br /&gt;
[[Категория:Linux]]&lt;br /&gt;
[[Категория:Ubuntu]]&lt;br /&gt;
[[Категория:Игровые серверы]]&lt;br /&gt;
[[Категория:Администрирование]]&lt;br /&gt;
[[Категория:RAMBA ART]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=BrainyCP&amp;diff=140</id>
		<title>BrainyCP</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=BrainyCP&amp;diff=140"/>
		<updated>2026-09-02T10:27:34Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-title&amp;quot;&amp;gt;BrainyCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-subtitle&amp;quot;&amp;gt;&lt;br /&gt;
Панель управления веб-инфраструктурой RAMBA ART&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;BrainyCP&#039;&#039;&#039; — панель управления Linux-сервером и веб-хостингом, используемая в инфраструктуре &#039;&#039;&#039;RAMBA ART&#039;&#039;&#039; для управления веб-сервисами, доменами, SSL-сертификатами и reverse proxy.&lt;br /&gt;
&lt;br /&gt;
В инфраструктуре RAMBA ART BrainyCP выполняет роль внешней точки входа для ряда внутренних сервисов, включая &#039;&#039;&#039;RAMBA Wiki&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
== Обзор ==&lt;br /&gt;
&lt;br /&gt;
BrainyCP позволяет выполнять большую часть повседневных операций с веб-сервером через графический интерфейс, сохраняя возможность ручного администрирования через SSH.&lt;br /&gt;
&lt;br /&gt;
Основные возможности:&lt;br /&gt;
&lt;br /&gt;
* управление доменами и сайтами;&lt;br /&gt;
* Nginx и Apache;&lt;br /&gt;
* PHP и PHP-FPM;&lt;br /&gt;
* MariaDB / MySQL;&lt;br /&gt;
* SSL-сертификаты Let&#039;s Encrypt;&lt;br /&gt;
* FTP;&lt;br /&gt;
* почтовые службы;&lt;br /&gt;
* резервное копирование;&lt;br /&gt;
* firewall;&lt;br /&gt;
* управление пользователями;&lt;br /&gt;
* reverse proxy;&lt;br /&gt;
* просмотр журналов и диагностика веб-сервисов.&lt;br /&gt;
&lt;br /&gt;
Официальный сайт: [https://brainycp.com/ brainycp.com]&lt;br /&gt;
&lt;br /&gt;
== BrainyCP в инфраструктуре RAMBA ART ==&lt;br /&gt;
&lt;br /&gt;
В нашей инфраструктуре BrainyCP используется не только как обычная hosting-панель.&lt;br /&gt;
&lt;br /&gt;
Он также выполняет функцию &#039;&#039;&#039;reverse proxy&#039;&#039;&#039; между Интернетом и внутренними сервисами.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
                         INTERNET&lt;br /&gt;
                            │&lt;br /&gt;
                            │ HTTPS :443&lt;br /&gt;
                            ▼&lt;br /&gt;
                    ┌─────────────────┐&lt;br /&gt;
                    │    BrainyCP     │&lt;br /&gt;
                    │  Reverse Proxy  │&lt;br /&gt;
                    └────────┬────────┘&lt;br /&gt;
                             │&lt;br /&gt;
              ┌──────────────┼──────────────┐&lt;br /&gt;
              │              │              │&lt;br /&gt;
              ▼              ▼              ▼&lt;br /&gt;
         RAMBA Wiki      RAMBA Matrix     ownCloud&lt;br /&gt;
              │              │              │&lt;br /&gt;
              ▼              ▼              ▼&lt;br /&gt;
        MediaWiki          Dendrite       ownCloud&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такой подход позволяет держать приложения на отдельных виртуальных машинах и LXC-контейнерах, а управление HTTPS выполнять централизованно.&lt;br /&gt;
&lt;br /&gt;
=== Пример: RAMBA Wiki ===&lt;br /&gt;
&lt;br /&gt;
Для Wiki используется схема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Пользователь&lt;br /&gt;
     │&lt;br /&gt;
     │ HTTPS&lt;br /&gt;
     ▼&lt;br /&gt;
wiki.ramba-art.ru&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
BrainyCP / Nginx&lt;br /&gt;
     │&lt;br /&gt;
     │ HTTP&lt;br /&gt;
     ▼&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
     │&lt;br /&gt;
     ▼&lt;br /&gt;
MediaWiki&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом, TLS завершается на BrainyCP, после чего запрос передаётся внутреннему серверу MediaWiki.&lt;br /&gt;
&lt;br /&gt;
== Системные требования ==&lt;br /&gt;
&lt;br /&gt;
Для отдельного сервера BrainyCP рекомендуется использовать чистую установку Linux.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Минимально&lt;br /&gt;
! Рекомендуется&lt;br /&gt;
|-&lt;br /&gt;
| ОС&lt;br /&gt;
| Поддерживаемая версия Linux&lt;br /&gt;
| Актуальная стабильная версия&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 2 ГБ&lt;br /&gt;
| 4 ГБ и более&lt;br /&gt;
|-&lt;br /&gt;
| Диск&lt;br /&gt;
| 20 ГБ&lt;br /&gt;
| SSD, 40+ ГБ&lt;br /&gt;
|-&lt;br /&gt;
| Сеть&lt;br /&gt;
| Интернет&lt;br /&gt;
| Статический IP&lt;br /&gt;
|-&lt;br /&gt;
| Доступ&lt;br /&gt;
| root&lt;br /&gt;
| SSH + root/sudo&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Перед установкой необходимо проверить актуальный список поддерживаемых ОС в документации BrainyCP.&lt;br /&gt;
&lt;br /&gt;
== Установка ==&lt;br /&gt;
&lt;br /&gt;
{{Warning|BrainyCP рекомендуется устанавливать на чистую систему. Наличие заранее настроенных Apache, Nginx, PHP или MariaDB может привести к конфликтам.}}&lt;br /&gt;
&lt;br /&gt;
Подключаемся к серверу по SSH.&lt;br /&gt;
&lt;br /&gt;
Обновляем систему:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
apt upgrade -y&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого запускаем официальный установщик BrainyCP:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -s https://core.brainycp.com/install.sh | bash&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Процесс установки может занять некоторое время.&lt;br /&gt;
&lt;br /&gt;
После завершения установщик покажет данные для доступа к панели.&lt;br /&gt;
&lt;br /&gt;
== Первый вход ==&lt;br /&gt;
&lt;br /&gt;
Панель управления доступна через HTTPS на управляющем порту BrainyCP.&lt;br /&gt;
&lt;br /&gt;
Пример:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://SERVER_IP:8000&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После первого входа рекомендуется:&lt;br /&gt;
&lt;br /&gt;
# изменить пароль администратора;&lt;br /&gt;
# проверить имя сервера;&lt;br /&gt;
# настроить часовой пояс;&lt;br /&gt;
# проверить сетевые параметры;&lt;br /&gt;
# установить обновления;&lt;br /&gt;
# настроить firewall;&lt;br /&gt;
# проверить доступность панели извне.&lt;br /&gt;
&lt;br /&gt;
== Домены и сайты ==&lt;br /&gt;
&lt;br /&gt;
Создание нового сайта выполняется через управление доменами BrainyCP.&lt;br /&gt;
&lt;br /&gt;
Обычно необходимо указать:&lt;br /&gt;
&lt;br /&gt;
* доменное имя;&lt;br /&gt;
* владельца;&lt;br /&gt;
* каталог сайта;&lt;br /&gt;
* версию PHP;&lt;br /&gt;
* используемый веб-сервер;&lt;br /&gt;
* параметры SSL.&lt;br /&gt;
&lt;br /&gt;
После создания домена BrainyCP автоматически формирует необходимую конфигурацию веб-сервера.&lt;br /&gt;
&lt;br /&gt;
== Веб-сервер ==&lt;br /&gt;
&lt;br /&gt;
BrainyCP поддерживает различные варианты конфигурации.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Режим&lt;br /&gt;
! Назначение&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Nginx&#039;&#039;&#039;&lt;br /&gt;
| Высокопроизводительная обработка HTTP/HTTPS и reverse proxy&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Apache&#039;&#039;&#039;&lt;br /&gt;
| Совместимость с приложениями, использующими Apache и .htaccess&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Nginx + Apache&#039;&#039;&#039;&lt;br /&gt;
| Nginx работает фронтендом, Apache обслуживает backend&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Для инфраструктуры RAMBA ART особенно важен &#039;&#039;&#039;Nginx&#039;&#039;&#039;, поскольку он используется в качестве reverse proxy.&lt;br /&gt;
&lt;br /&gt;
== Reverse Proxy ==&lt;br /&gt;
&lt;br /&gt;
Reverse proxy позволяет принимать запросы на публичном домене и перенаправлять их на внутренний сервер.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
location / {&lt;br /&gt;
    proxy_pass http://192.168.1.79:80;&lt;br /&gt;
&lt;br /&gt;
    proxy_set_header Host $host;&lt;br /&gt;
    proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
    proxy_set_header X-Forwarded-Proto $scheme;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В данном примере:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
wiki.ramba-art.ru&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
BrainyCP&lt;br /&gt;
        │&lt;br /&gt;
        ▼&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При изменении внутреннего IP сервиса достаточно изменить upstream на BrainyCP — публичный адрес сайта остаётся прежним.&lt;br /&gt;
&lt;br /&gt;
=== Проверка конфигурации ===&lt;br /&gt;
&lt;br /&gt;
После изменения Nginx обязательно проверяем конфигурацию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nginx -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При успешной проверке:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
syntax is ok&lt;br /&gt;
test is successful&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого применяем изменения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SSL / Let&#039;s Encrypt ==&lt;br /&gt;
&lt;br /&gt;
BrainyCP позволяет выпускать сертификаты Let&#039;s Encrypt для добавленных доменов.&lt;br /&gt;
&lt;br /&gt;
Перед выпуском сертификата необходимо убедиться, что:&lt;br /&gt;
&lt;br /&gt;
* DNS-запись домена указывает на сервер;&lt;br /&gt;
* порты 80 и 443 доступны;&lt;br /&gt;
* домен добавлен в BrainyCP;&lt;br /&gt;
* веб-сервер корректно отвечает на запросы.&lt;br /&gt;
&lt;br /&gt;
После выпуска сертификата рекомендуется проверить автоматическое продление.&lt;br /&gt;
&lt;br /&gt;
Для reverse proxy схема выглядит следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
CLIENT&lt;br /&gt;
  │&lt;br /&gt;
  │ HTTPS&lt;br /&gt;
  ▼&lt;br /&gt;
BrainyCP&lt;br /&gt;
  │&lt;br /&gt;
  │ TLS termination&lt;br /&gt;
  ▼&lt;br /&gt;
HTTP / HTTPS backend&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== PHP ==&lt;br /&gt;
&lt;br /&gt;
Для сайтов, размещённых непосредственно на BrainyCP, панель позволяет управлять версиями PHP и параметрами PHP-FPM.&lt;br /&gt;
&lt;br /&gt;
При диагностике полезно проверить установленные службы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl --type=service | grep -i php&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Конкретное имя PHP-FPM зависит от установленной версии PHP.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status php8.2-fpm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Базы данных ==&lt;br /&gt;
&lt;br /&gt;
BrainyCP предоставляет управление MariaDB/MySQL и позволяет создавать:&lt;br /&gt;
&lt;br /&gt;
* базы данных;&lt;br /&gt;
* пользователей;&lt;br /&gt;
* пароли;&lt;br /&gt;
* права доступа.&lt;br /&gt;
&lt;br /&gt;
Для графического администрирования может использоваться phpMyAdmin.&lt;br /&gt;
&lt;br /&gt;
Для production-систем рекомендуется:&lt;br /&gt;
&lt;br /&gt;
* создавать отдельного пользователя для каждого приложения;&lt;br /&gt;
* не использовать root-пользователя БД в приложениях;&lt;br /&gt;
* использовать уникальные пароли;&lt;br /&gt;
* регулярно выполнять резервное копирование.&lt;br /&gt;
&lt;br /&gt;
== MediaWiki за BrainyCP ==&lt;br /&gt;
&lt;br /&gt;
RAMBA Wiki работает на отдельном сервере MediaWiki, а BrainyCP используется как внешний reverse proxy.&lt;br /&gt;
&lt;br /&gt;
Это отличается от установки MediaWiki непосредственно внутрь hosting-окружения BrainyCP.&lt;br /&gt;
&lt;br /&gt;
=== Архитектура ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│          Internet            │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               │ HTTPS&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│           BrainyCP           │&lt;br /&gt;
│            Nginx             │&lt;br /&gt;
│       SSL termination        │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               │ HTTP&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│        MediaWiki LXC         │&lt;br /&gt;
│                              │&lt;br /&gt;
│ MediaWiki + Apache + PHP     │&lt;br /&gt;
│ MariaDB                      │&lt;br /&gt;
└──────────────────────────────┘&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Преимущество такой схемы — MediaWiki можно обновлять, переносить или восстанавливать независимо от reverse proxy.&lt;br /&gt;
&lt;br /&gt;
=== X-Forwarded-Proto ===&lt;br /&gt;
&lt;br /&gt;
При завершении HTTPS на reverse proxy backend должен понимать, что исходное соединение пользователя было защищённым.&lt;br /&gt;
&lt;br /&gt;
Nginx передаёт:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
proxy_set_header X-Forwarded-Proto $scheme;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
На стороне MediaWiki это необходимо учитывать в конфигурации, иначе могут возникать:&lt;br /&gt;
&lt;br /&gt;
* неправильные HTTP-ссылки;&lt;br /&gt;
* циклические redirect;&lt;br /&gt;
* проблемы с cookies;&lt;br /&gt;
* ошибки определения HTTPS.&lt;br /&gt;
&lt;br /&gt;
== Диагностика ==&lt;br /&gt;
&lt;br /&gt;
=== Nginx ===&lt;br /&gt;
&lt;br /&gt;
Проверка службы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверка конфигурации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nginx -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перезагрузка конфигурации:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Apache ===&lt;br /&gt;
&lt;br /&gt;
В зависимости от системы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status apache2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
или:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status httpd&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка HTTP ===&lt;br /&gt;
&lt;br /&gt;
Для проверки сайта непосредственно из консоли:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -I https://example.ru/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для подробной диагностики:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -Iv https://example.ru/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка backend ===&lt;br /&gt;
&lt;br /&gt;
Reverse proxy можно исключить из цепочки и проверить backend непосредственно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
curl -I http://BACKEND_IP/&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволяет быстро определить, где находится проблема:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
DNS&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
BrainyCP / Nginx&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
Backend&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
Application&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
Резервные копии рекомендуется хранить &#039;&#039;&#039;вне сервера BrainyCP&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Необходимо учитывать как минимум:&lt;br /&gt;
&lt;br /&gt;
* конфигурации веб-сервера;&lt;br /&gt;
* SSL-сертификаты;&lt;br /&gt;
* базы данных;&lt;br /&gt;
* файлы сайтов;&lt;br /&gt;
* конфигурацию BrainyCP.&lt;br /&gt;
&lt;br /&gt;
Если BrainyCP работает в виртуальной машине или LXC-контейнере, желательно дополнительно использовать резервное копирование на уровне гипервизора.&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
Основные рекомендации:&lt;br /&gt;
&lt;br /&gt;
* не публиковать управляющую панель без необходимости;&lt;br /&gt;
* использовать сложный пароль администратора;&lt;br /&gt;
* ограничить SSH;&lt;br /&gt;
* своевременно устанавливать обновления;&lt;br /&gt;
* использовать HTTPS;&lt;br /&gt;
* контролировать открытые порты;&lt;br /&gt;
* регулярно проверять журналы Nginx;&lt;br /&gt;
* хранить резервные копии отдельно;&lt;br /&gt;
* не использовать root для работы веб-приложений;&lt;br /&gt;
* перед изменением production-конфигурации сохранять рабочую версию.&lt;br /&gt;
&lt;br /&gt;
== Полезные команды ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Задача&lt;br /&gt;
! Команда&lt;br /&gt;
|-&lt;br /&gt;
| Проверить Nginx&lt;br /&gt;
| &amp;lt;code&amp;gt;nginx -t&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Статус Nginx&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl status nginx&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Применить конфигурацию&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl reload nginx&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Перезапустить Nginx&lt;br /&gt;
| &amp;lt;code&amp;gt;systemctl restart nginx&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить сайт&lt;br /&gt;
| &amp;lt;code&amp;gt;curl -I https://example.ru/&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Подробный HTTPS-тест&lt;br /&gt;
| &amp;lt;code&amp;gt;curl -Iv https://example.ru/&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Проверить порты&lt;br /&gt;
| &amp;lt;code&amp;gt;ss -tulpn&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Журнал Nginx&lt;br /&gt;
| &amp;lt;code&amp;gt;journalctl -u nginx&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Заключение ==&lt;br /&gt;
&lt;br /&gt;
BrainyCP удобно использовать не только как классическую hosting-панель, но и как центральный узел управления веб-инфраструктурой.&lt;br /&gt;
&lt;br /&gt;
В архитектуре &#039;&#039;&#039;RAMBA ART&#039;&#039;&#039; особенно полезна связка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
DNS&lt;br /&gt;
 │&lt;br /&gt;
 ▼&lt;br /&gt;
BrainyCP&lt;br /&gt;
 │&lt;br /&gt;
 ├── SSL&lt;br /&gt;
 ├── Nginx&lt;br /&gt;
 ├── Reverse Proxy&lt;br /&gt;
 │&lt;br /&gt;
 ▼&lt;br /&gt;
Внутренние сервисы RAMBA ART&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Она позволяет отделить публичный веб-уровень от серверов приложений и независимо обслуживать MediaWiki, Matrix, облачные и другие сервисы.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
&lt;br /&gt;
* [[Миграция RAMBA Wiki на MediaWiki 1.43]]&lt;br /&gt;
* [[Proxmox VE]]&lt;br /&gt;
* [[RAMBA Matrix]]&lt;br /&gt;
* [[RAMBA ART Infrastructure]]&lt;br /&gt;
&lt;br /&gt;
== Внешние ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [https://brainycp.com/ Официальный сайт BrainyCP]&lt;br /&gt;
* [https://docs.brainycp.com/ Документация BrainyCP]&lt;br /&gt;
&lt;br /&gt;
[[Категория:BrainyCP]]&lt;br /&gt;
[[Категория:Linux]]&lt;br /&gt;
[[Категория:Веб-инфраструктура]]&lt;br /&gt;
[[Категория:Администрирование]]&lt;br /&gt;
[[Категория:RAMBA ART]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=139</id>
		<title>Мониторинг</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%BE%D0%BD%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%BD%D0%B3&amp;diff=139"/>
		<updated>2026-09-02T09:10:00Z</updated>

		<summary type="html">&lt;p&gt;Artem: Содержимое страницы заменено на «&amp;lt;rambamonitor /&amp;gt;»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;rambamonitor /&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%B8%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D1%8F_RAMBA_Wiki_%D0%BD%D0%B0_MediaWiki_1_43&amp;diff=138</id>
		<title>Миграция RAMBA Wiki на MediaWiki 1 43</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%9C%D0%B8%D0%B3%D1%80%D0%B0%D1%86%D0%B8%D1%8F_RAMBA_Wiki_%D0%BD%D0%B0_MediaWiki_1_43&amp;diff=138"/>
		<updated>2026-09-02T08:57:38Z</updated>

		<summary type="html">&lt;p&gt;Artem: Artem переименовал страницу Миграция RAMBA Wiki на MediaWiki 1 43 в RAMBA Wiki Migration 1.43&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#перенаправление [[RAMBA Wiki Migration 1.43]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_Wiki_Migration_1.43&amp;diff=137</id>
		<title>RAMBA Wiki Migration 1.43</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_Wiki_Migration_1.43&amp;diff=137"/>
		<updated>2026-09-02T08:57:38Z</updated>

		<summary type="html">&lt;p&gt;Artem: Artem переименовал страницу Миграция RAMBA Wiki на MediaWiki 1 43 в RAMBA Wiki Migration 1.43&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2em; font-weight:700;&amp;quot;&amp;gt;🚀 Миграция RAMBA Wiki на MediaWiki 1.43&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top:8px; opacity:.85;&amp;quot;&amp;gt;&lt;br /&gt;
Переезд RAMBA Wiki со старого TurnKey Linux / MediaWiki 1.39 на новую инфраструктуру Debian 12 и MediaWiki 1.43 LTS.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE:Миграция RAMBA Wiki на MediaWiki 1.43}}&lt;br /&gt;
&lt;br /&gt;
== Общая информация ==&lt;br /&gt;
&lt;br /&gt;
В сентябре 2026 года была выполнена полная миграция &#039;&#039;&#039;RAMBA Wiki&#039;&#039;&#039; на новую платформу.&lt;br /&gt;
&lt;br /&gt;
Основной задачей было заменить устаревшую установку MediaWiki, сохранив:&lt;br /&gt;
&lt;br /&gt;
* все существующие статьи;&lt;br /&gt;
* историю изменений;&lt;br /&gt;
* пользователей и права доступа;&lt;br /&gt;
* загруженные изображения;&lt;br /&gt;
* оформление Wiki;&lt;br /&gt;
* мобильную версию;&lt;br /&gt;
* необходимые расширения;&lt;br /&gt;
* собственное расширение &#039;&#039;&#039;RambaGameMonitor&#039;&#039;&#039;;&lt;br /&gt;
* существующий публичный адрес &#039;&#039;&#039;wiki.ramba-art.ru&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Миграция выполнялась по схеме &#039;&#039;&#039;parallel migration&#039;&#039;&#039;: старая Wiki продолжала существовать во время подготовки новой системы и использовалась как аварийный вариант возврата.&lt;br /&gt;
&lt;br /&gt;
После полного тестирования трафик был переключён на новую Wiki, а старая система была сохранена в Proxmox Backup Server и удалена из рабочей инфраструктуры.&lt;br /&gt;
&lt;br /&gt;
== Исходная система ==&lt;br /&gt;
&lt;br /&gt;
До миграции RAMBA Wiki работала в контейнере Proxmox:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| &#039;&#039;&#039;115&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Имя&lt;br /&gt;
| &#039;&#039;&#039;WiKi&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Дистрибутив&lt;br /&gt;
| TurnKey MediaWiki 17.1 / Debian 11 Bullseye&lt;br /&gt;
|-&lt;br /&gt;
| MediaWiki&lt;br /&gt;
| &#039;&#039;&#039;1.39.2 LTS&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| PHP&lt;br /&gt;
| 7.4&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| 10.5&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| Apache 2.4&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| 192.168.1.11&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 512 MB&lt;br /&gt;
|-&lt;br /&gt;
| CPU&lt;br /&gt;
| 1 vCPU&lt;br /&gt;
|-&lt;br /&gt;
| Диск&lt;br /&gt;
| 8 GB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MediaWiki 1.39 к моменту миграции уже являлась устаревшей веткой, поэтому было принято решение не обновлять существующий TurnKey-контейнер на месте, а построить новую систему.&lt;br /&gt;
&lt;br /&gt;
== Новая архитектура ==&lt;br /&gt;
&lt;br /&gt;
Для новой RAMBA Wiki был создан отдельный LXC-контейнер:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| &#039;&#039;&#039;102&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Имя&lt;br /&gt;
| &#039;&#039;&#039;wiki-v2&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| ОС&lt;br /&gt;
| Debian 12 Bookworm&lt;br /&gt;
|-&lt;br /&gt;
| MediaWiki&lt;br /&gt;
| &#039;&#039;&#039;1.43.9 LTS&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| PHP&lt;br /&gt;
| 8.2&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| 10.11&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| Apache 2.4&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| &#039;&#039;&#039;192.168.1.79&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 2048 MB&lt;br /&gt;
|-&lt;br /&gt;
| Swap&lt;br /&gt;
| 512 MB&lt;br /&gt;
|-&lt;br /&gt;
| CPU&lt;br /&gt;
| 2 vCPU&lt;br /&gt;
|-&lt;br /&gt;
| RootFS&lt;br /&gt;
| 16 GB&lt;br /&gt;
|-&lt;br /&gt;
| Storage&lt;br /&gt;
| OMV-SSD1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Система работает как unprivileged LXC-контейнер.&lt;br /&gt;
&lt;br /&gt;
== Схема работы ==&lt;br /&gt;
&lt;br /&gt;
Публичный HTTPS завершается на reverse proxy BrainyCP.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
   │&lt;br /&gt;
   │ HTTPS :443&lt;br /&gt;
   ▼&lt;br /&gt;
wiki.ramba-art.ru&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
BrainyCP / nginx&lt;br /&gt;
CT 105&lt;br /&gt;
192.168.1.12&lt;br /&gt;
   │&lt;br /&gt;
   │ HTTP :80&lt;br /&gt;
   ▼&lt;br /&gt;
RAMBA Wiki&lt;br /&gt;
CT 102 — wiki-v2&lt;br /&gt;
192.168.1.79&lt;br /&gt;
   │&lt;br /&gt;
   ├── Apache&lt;br /&gt;
   ├── PHP 8.2&lt;br /&gt;
   ├── MediaWiki 1.43&lt;br /&gt;
   └── MariaDB 10.11&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TLS-сертификат обслуживается reverse proxy.&lt;br /&gt;
&lt;br /&gt;
Сам MediaWiki-контейнер не требует собственного HTTPS-сервера.&lt;br /&gt;
&lt;br /&gt;
== Создание нового контейнера ==&lt;br /&gt;
&lt;br /&gt;
Новая Wiki была развёрнута на чистом Debian 12.&lt;br /&gt;
&lt;br /&gt;
Основные установленные компоненты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apache2&lt;br /&gt;
mariadb-server&lt;br /&gt;
imagemagick&lt;br /&gt;
&lt;br /&gt;
php8.2&lt;br /&gt;
libapache2-mod-php8.2&lt;br /&gt;
php8.2-mysql&lt;br /&gt;
php8.2-intl&lt;br /&gt;
php8.2-mbstring&lt;br /&gt;
php8.2-xml&lt;br /&gt;
php8.2-curl&lt;br /&gt;
php8.2-gd&lt;br /&gt;
php8.2-zip&lt;br /&gt;
php8.2-apcu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для Apache были активированы необходимые модули:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
a2enmod rewrite&lt;br /&gt;
a2enmod headers&lt;br /&gt;
a2enmod expires&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основная директория MediaWiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Перенос базы данных ==&lt;br /&gt;
&lt;br /&gt;
База данных старой Wiki была экспортирована из CT 115 и импортирована в MariaDB нового CT 102.&lt;br /&gt;
&lt;br /&gt;
После импорта был выполнен штатный процесс обновления схемы базы данных MediaWiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/www/mediawiki&lt;br /&gt;
runuser -u www-data -- php maintenance/run.php update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обновление схемы прошло успешно.&lt;br /&gt;
&lt;br /&gt;
В результате были сохранены:&lt;br /&gt;
&lt;br /&gt;
* статьи;&lt;br /&gt;
* ревизии;&lt;br /&gt;
* категории;&lt;br /&gt;
* пользователи;&lt;br /&gt;
* права пользователей;&lt;br /&gt;
* служебные страницы MediaWiki;&lt;br /&gt;
* история изменений.&lt;br /&gt;
&lt;br /&gt;
== Перенос изображений ==&lt;br /&gt;
&lt;br /&gt;
Каталог загруженных файлов старой Wiki был перенесён в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki/images&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После переноса были восстановлены корректные права доступа для Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown -R www-data:www-data /var/www/mediawiki/images&lt;br /&gt;
find /var/www/mediawiki/images -type d -exec chmod 755 {} \;&lt;br /&gt;
find /var/www/mediawiki/images -type f -exec chmod 644 {} \;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также был перенесён логотип RAMBA Wiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki/resources/assets/ramba_b.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Короткие URL ==&lt;br /&gt;
&lt;br /&gt;
Для статей сохранена привычная структура адресов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Название_страницы&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В MediaWiki используется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgServer = &amp;quot;https://wiki.ramba-art.ru&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apache выполняет перенаправление запросов вида:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/wiki/Название&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на MediaWiki `index.php`.&lt;br /&gt;
&lt;br /&gt;
== Reverse Proxy ==&lt;br /&gt;
&lt;br /&gt;
Reverse proxy RAMBA Wiki находится в BrainyCP:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| 105&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| 192.168.1.12&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| nginx&lt;br /&gt;
|-&lt;br /&gt;
| Backend&lt;br /&gt;
| 192.168.1.79:80&lt;br /&gt;
|-&lt;br /&gt;
| Frontend&lt;br /&gt;
| HTTPS :443&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Основной upstream:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
location / {&lt;br /&gt;
    proxy_pass http://192.168.1.79:80;&lt;br /&gt;
&lt;br /&gt;
    proxy_http_version 1.1;&lt;br /&gt;
&lt;br /&gt;
    proxy_set_header Host $host;&lt;br /&gt;
    proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
&lt;br /&gt;
    proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
    proxy_set_header X-Forwarded-Host $host;&lt;br /&gt;
    proxy_set_header X-Forwarded-Port 443;&lt;br /&gt;
&lt;br /&gt;
    proxy_redirect off;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
До миграции upstream указывал на старый сервер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
192.168.1.11:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После проверки новой Wiki он был изменён на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволило переключить production без изменения DNS.&lt;br /&gt;
&lt;br /&gt;
== HTTPS за reverse proxy ==&lt;br /&gt;
&lt;br /&gt;
Поскольку HTTPS завершается на nginx, а между nginx и Apache используется HTTP, MediaWiki необходимо корректно сообщать исходный протокол запроса.&lt;br /&gt;
&lt;br /&gt;
В `LocalSettings.php` добавлена проверка доверенного reverse proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (&lt;br /&gt;
    ($_SERVER[&amp;quot;REMOTE_ADDR&amp;quot;] ?? &amp;quot;&amp;quot;) === &amp;quot;192.168.1.12&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
    ($_SERVER[&amp;quot;HTTP_X_FORWARDED_PROTO&amp;quot;] ?? &amp;quot;&amp;quot;) === &amp;quot;https&amp;quot;&lt;br /&gt;
) {&lt;br /&gt;
    $_SERVER[&amp;quot;HTTPS&amp;quot;] = &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заголовок `X-Forwarded-Proto` принимается только от reverse proxy RAMBA с адресом `192.168.1.12`.&lt;br /&gt;
&lt;br /&gt;
== Мобильная версия ==&lt;br /&gt;
&lt;br /&gt;
Для мобильного интерфейса используются:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MobileFrontend&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;MinervaNeue&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Конфигурация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadSkin( &#039;MinervaNeue&#039; );&lt;br /&gt;
&lt;br /&gt;
$wgDefaultMobileSkin = &#039;minerva&#039;;&lt;br /&gt;
&lt;br /&gt;
wfLoadExtension( &#039;MobileFrontend&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Расширение MobileFrontend установлено в версии, совместимой с MediaWiki 1.43.&lt;br /&gt;
&lt;br /&gt;
После миграции была дополнительно переработана главная страница RAMBA Wiki, чтобы карточки корректно отображались на небольших экранах.&lt;br /&gt;
&lt;br /&gt;
На мобильных устройствах карточки автоматически перестраиваются в один столбец.&lt;br /&gt;
&lt;br /&gt;
== Редактирование исходного кода ==&lt;br /&gt;
&lt;br /&gt;
Для работы с исходным кодом страниц используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;WikiEditor&#039; );&lt;br /&gt;
wfLoadExtension( &#039;CodeEditor&#039; );&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&lt;br /&gt;
$wgDefaultUserOptions[&#039;usebetatoolbar&#039;] = 1;&lt;br /&gt;
$wgWikiEditorRealtimePreview = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`SyntaxHighlight_GeSHi` используется для оформления команд, конфигурационных файлов и программного кода в технических статьях RAMBA Wiki.&lt;br /&gt;
&lt;br /&gt;
== Основные расширения ==&lt;br /&gt;
&lt;br /&gt;
После миграции были активированы необходимые стандартные расширения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;ParserFunctions&#039; );&lt;br /&gt;
wfLoadExtension( &#039;Cite&#039; );&lt;br /&gt;
wfLoadExtension( &#039;TemplateData&#039; );&lt;br /&gt;
wfLoadExtension( &#039;InputBox&#039; );&lt;br /&gt;
wfLoadExtension( &#039;ImageMap&#039; );&lt;br /&gt;
wfLoadExtension( &#039;Nuke&#039; );&lt;br /&gt;
wfLoadExtension( &#039;ReplaceText&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DynamicPageList3 ==&lt;br /&gt;
&lt;br /&gt;
Для существующих страниц RAMBA Wiki была сохранена поддержка DynamicPageList3.&lt;br /&gt;
&lt;br /&gt;
Установлен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
DynamicPageList3 3.5.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Активация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;DynamicPageList3&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После установки расширение было проверено на MediaWiki 1.43.&lt;br /&gt;
&lt;br /&gt;
== RambaGameMonitor ==&lt;br /&gt;
&lt;br /&gt;
Сохранено собственное расширение &#039;&#039;&#039;RambaGameMonitor&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Расширение предоставляет тег:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;rambamonitor /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
который позволяет отображать состояние игровых серверов непосредственно на страницах RAMBA Wiki.&lt;br /&gt;
&lt;br /&gt;
В текущей реализации выполняются запросы:&lt;br /&gt;
&lt;br /&gt;
* Rust — Source Engine Query / UDP;&lt;br /&gt;
* Minecraft Java Edition — Server List Ping / TCP.&lt;br /&gt;
&lt;br /&gt;
Пример результата:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Сервер&lt;br /&gt;
! Состояние&lt;br /&gt;
! Игроки&lt;br /&gt;
! Дополнительная информация&lt;br /&gt;
|-&lt;br /&gt;
| Rust&lt;br /&gt;
| Online / Offline&lt;br /&gt;
| текущие / максимум&lt;br /&gt;
| карта&lt;br /&gt;
|-&lt;br /&gt;
| Minecraft&lt;br /&gt;
| Online / Offline&lt;br /&gt;
| текущие / максимум&lt;br /&gt;
| версия&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
После переноса расширение было проверено непосредственно на MediaWiki 1.43 и PHP 8.2.&lt;br /&gt;
&lt;br /&gt;
== Отказ от устаревших компонентов ==&lt;br /&gt;
&lt;br /&gt;
Во время миграции была проведена ревизия расширений старой Wiki.&lt;br /&gt;
&lt;br /&gt;
Некоторые компоненты намеренно не переносились.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Решение&lt;br /&gt;
! Причина&lt;br /&gt;
|-&lt;br /&gt;
| GameQ&lt;br /&gt;
| Не переносить&lt;br /&gt;
| RambaGameMonitor больше не зависит от GameQ&lt;br /&gt;
|-&lt;br /&gt;
| LocalisationUpdate&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Устаревшее расширение&lt;br /&gt;
|-&lt;br /&gt;
| GoogleCodePrettify&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Заменено SyntaxHighlight&lt;br /&gt;
|-&lt;br /&gt;
| Renameuser&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Функциональность присутствует в современном MediaWiki&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Таким образом новая установка не является простой копией старого сервера — устаревшие компоненты были удалены.&lt;br /&gt;
&lt;br /&gt;
== Права доступа ==&lt;br /&gt;
&lt;br /&gt;
Анонимным пользователям разрешено чтение Wiki, но запрещено редактирование и самостоятельная регистрация.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;read&#039;] = true;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;edit&#039;] = false;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;createpage&#039;] = false;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;createaccount&#039;] = false;&lt;br /&gt;
&lt;br /&gt;
$wgGroupPermissions[&#039;user&#039;][&#039;edit&#039;] = true;&lt;br /&gt;
$wgGroupPermissions[&#039;user&#039;][&#039;createpage&#039;] = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для администратора Wiki дополнительно было назначено право:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
interface-admin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это необходимо для редактирования системных CSS/JS-страниц, включая:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
MediaWiki:Common.css&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
После миграции были сгенерированы новые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$wgSecretKey&lt;br /&gt;
$wgUpgradeKey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Старые значения больше не используются.&lt;br /&gt;
&lt;br /&gt;
Значения ключей в документации намеренно не публикуются.&lt;br /&gt;
&lt;br /&gt;
Пароль базы данных также не должен храниться в статьях Wiki или открытых конфигурационных примерах.&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
После успешного запуска production была создана полная резервная копия нового CT 102 в &#039;&#039;&#039;Proxmox Backup Server&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Идентификатор backup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
ct/102/2026-09-02T08:36:30Z&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Объём файловой системы на момент резервного копирования составлял приблизительно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
1.77 GiB&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После дедупликации и сжатия в PBS было передано около:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
568 MiB&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Так как используемое для rootfs NFS-хранилище не поддерживает необходимый тип snapshot, Proxmox автоматически переключил backup из режима `snapshot` в режим `suspend`.&lt;br /&gt;
&lt;br /&gt;
Контейнер был приостановлен приблизительно на две секунды.&lt;br /&gt;
&lt;br /&gt;
Backup завершился успешно.&lt;br /&gt;
&lt;br /&gt;
== Переключение production ==&lt;br /&gt;
&lt;br /&gt;
После проверки новой системы был изменён upstream nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
СТАРЫЙ:&lt;br /&gt;
192.168.1.11:80&lt;br /&gt;
&lt;br /&gt;
НОВЫЙ:&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перед применением конфигурации nginx была выполнена проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nginx -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После успешной проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Публичный запрос подтвердил:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://wiki.ramba-art.ru/&lt;br /&gt;
        ↓&lt;br /&gt;
HTTP 301&lt;br /&gt;
        ↓&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Заглавная_страница&lt;br /&gt;
        ↓&lt;br /&gt;
HTTP 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка после миграции ==&lt;br /&gt;
&lt;br /&gt;
После переключения production были протестированы:&lt;br /&gt;
&lt;br /&gt;
* открытие главной страницы;&lt;br /&gt;
* HTTPS;&lt;br /&gt;
* короткие URL;&lt;br /&gt;
* авторизация;&lt;br /&gt;
* редактирование статей;&lt;br /&gt;
* редактирование `MediaWiki:Common.css`;&lt;br /&gt;
* загрузка файлов;&lt;br /&gt;
* отображение изображений;&lt;br /&gt;
* мобильный интерфейс;&lt;br /&gt;
* MinervaNeue;&lt;br /&gt;
* DynamicPageList3;&lt;br /&gt;
* SyntaxHighlight;&lt;br /&gt;
* RambaGameMonitor;&lt;br /&gt;
* Apache;&lt;br /&gt;
* MariaDB.&lt;br /&gt;
&lt;br /&gt;
Финальная проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTP: 200&lt;br /&gt;
Redirects: 1&lt;br /&gt;
Final:&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Заглавная_страница&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Вывод старой системы из эксплуатации ==&lt;br /&gt;
&lt;br /&gt;
После успешной работы CT 102 старый контейнер CT 115 был остановлен.&lt;br /&gt;
&lt;br /&gt;
После остановки была повторно проверена публичная Wiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
CT 102: running&lt;br /&gt;
CT 115: stopped&lt;br /&gt;
wiki.ramba-art.ru: HTTP 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это подтвердило отсутствие зависимости production от старого контейнера.&lt;br /&gt;
&lt;br /&gt;
После этого была создана финальная резервная копия CT 115 в Proxmox Backup Server.&lt;br /&gt;
&lt;br /&gt;
Старый контейнер был удалён:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct destroy 115&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Proxmox подтвердил удаление старого диска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Logical volume &amp;quot;vm-115-disk-0&amp;quot; successfully removed.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После полного удаления CT 115 Wiki была проверена ещё раз:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTP: 200&lt;br /&gt;
Time: 0.262066s&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом старая установка полностью выведена из эксплуатации.&lt;br /&gt;
&lt;br /&gt;
== Итоговая конфигурация ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-grid&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;🌐 Production&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;wiki.ramba-art.ru&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MediaWiki 1.43.9 LTS&lt;br /&gt;
&lt;br /&gt;
Debian 12 Bookworm&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;📦 Контейнер&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CT &#039;&#039;&#039;102&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;wiki-v2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
192.168.1.79&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;🔀 Reverse Proxy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BrainyCP&lt;br /&gt;
&lt;br /&gt;
CT &#039;&#039;&#039;105&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
192.168.1.12&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;💾 Backup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Proxmox Backup Server&lt;br /&gt;
&lt;br /&gt;
Резервируются новая и архивная версии Wiki&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Результат ==&lt;br /&gt;
&lt;br /&gt;
Миграция RAMBA Wiki выполнена успешно.&lt;br /&gt;
&lt;br /&gt;
Старая архитектура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
TurnKey Linux&lt;br /&gt;
Debian 11&lt;br /&gt;
MediaWiki 1.39&lt;br /&gt;
PHP 7.4&lt;br /&gt;
CT 115&lt;br /&gt;
192.168.1.11&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
заменена на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Debian 12&lt;br /&gt;
MediaWiki 1.43.9 LTS&lt;br /&gt;
PHP 8.2&lt;br /&gt;
MariaDB 10.11&lt;br /&gt;
CT 102&lt;br /&gt;
192.168.1.79&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом были сохранены существующие данные Wiki и необходимые функции, удалены устаревшие компоненты, восстановлена мобильная версия, настроен reverse proxy и HTTPS, обновлены ключи безопасности и создана новая точка восстановления в Proxmox Backup Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA Wiki полностью переведена на новую инфраструктуру.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA Wiki]]&lt;br /&gt;
[[Категория:MediaWiki]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Инфраструктура RAMBA]]&lt;br /&gt;
[[Категория:Миграции]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=RAMBA_Wiki_Migration_1.43&amp;diff=136</id>
		<title>RAMBA Wiki Migration 1.43</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=RAMBA_Wiki_Migration_1.43&amp;diff=136"/>
		<updated>2026-09-02T08:52:27Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «__TOC__  &amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt; &amp;lt;div style=&amp;quot;font-size:2em; font-weight:700;&amp;quot;&amp;gt;🚀 Миграция RAMBA Wiki на MediaWiki 1.43&amp;lt;/div&amp;gt; &amp;lt;div style=&amp;quot;margin-top:8px; opacity:.85;&amp;quot;&amp;gt; Переезд RAMBA Wiki со старого TurnKey Linux / MediaWiki 1.39 на новую инфраструктуру Debian 12 и MediaWiki 1.43 LTS. &amp;lt;/div&amp;gt; &amp;lt;/div&amp;gt;  {{DISPLAYTITLE:Миграция RAMBA Wiki на MediaWiki 1.43}}  == Общая информация ==  В...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-header&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2em; font-weight:700;&amp;quot;&amp;gt;🚀 Миграция RAMBA Wiki на MediaWiki 1.43&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top:8px; opacity:.85;&amp;quot;&amp;gt;&lt;br /&gt;
Переезд RAMBA Wiki со старого TurnKey Linux / MediaWiki 1.39 на новую инфраструктуру Debian 12 и MediaWiki 1.43 LTS.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{DISPLAYTITLE:Миграция RAMBA Wiki на MediaWiki 1.43}}&lt;br /&gt;
&lt;br /&gt;
== Общая информация ==&lt;br /&gt;
&lt;br /&gt;
В сентябре 2026 года была выполнена полная миграция &#039;&#039;&#039;RAMBA Wiki&#039;&#039;&#039; на новую платформу.&lt;br /&gt;
&lt;br /&gt;
Основной задачей было заменить устаревшую установку MediaWiki, сохранив:&lt;br /&gt;
&lt;br /&gt;
* все существующие статьи;&lt;br /&gt;
* историю изменений;&lt;br /&gt;
* пользователей и права доступа;&lt;br /&gt;
* загруженные изображения;&lt;br /&gt;
* оформление Wiki;&lt;br /&gt;
* мобильную версию;&lt;br /&gt;
* необходимые расширения;&lt;br /&gt;
* собственное расширение &#039;&#039;&#039;RambaGameMonitor&#039;&#039;&#039;;&lt;br /&gt;
* существующий публичный адрес &#039;&#039;&#039;wiki.ramba-art.ru&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Миграция выполнялась по схеме &#039;&#039;&#039;parallel migration&#039;&#039;&#039;: старая Wiki продолжала существовать во время подготовки новой системы и использовалась как аварийный вариант возврата.&lt;br /&gt;
&lt;br /&gt;
После полного тестирования трафик был переключён на новую Wiki, а старая система была сохранена в Proxmox Backup Server и удалена из рабочей инфраструктуры.&lt;br /&gt;
&lt;br /&gt;
== Исходная система ==&lt;br /&gt;
&lt;br /&gt;
До миграции RAMBA Wiki работала в контейнере Proxmox:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| &#039;&#039;&#039;115&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Имя&lt;br /&gt;
| &#039;&#039;&#039;WiKi&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Дистрибутив&lt;br /&gt;
| TurnKey MediaWiki 17.1 / Debian 11 Bullseye&lt;br /&gt;
|-&lt;br /&gt;
| MediaWiki&lt;br /&gt;
| &#039;&#039;&#039;1.39.2 LTS&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| PHP&lt;br /&gt;
| 7.4&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| 10.5&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| Apache 2.4&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| 192.168.1.11&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 512 MB&lt;br /&gt;
|-&lt;br /&gt;
| CPU&lt;br /&gt;
| 1 vCPU&lt;br /&gt;
|-&lt;br /&gt;
| Диск&lt;br /&gt;
| 8 GB&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MediaWiki 1.39 к моменту миграции уже являлась устаревшей веткой, поэтому было принято решение не обновлять существующий TurnKey-контейнер на месте, а построить новую систему.&lt;br /&gt;
&lt;br /&gt;
== Новая архитектура ==&lt;br /&gt;
&lt;br /&gt;
Для новой RAMBA Wiki был создан отдельный LXC-контейнер:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| &#039;&#039;&#039;102&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| Имя&lt;br /&gt;
| &#039;&#039;&#039;wiki-v2&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| ОС&lt;br /&gt;
| Debian 12 Bookworm&lt;br /&gt;
|-&lt;br /&gt;
| MediaWiki&lt;br /&gt;
| &#039;&#039;&#039;1.43.9 LTS&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| PHP&lt;br /&gt;
| 8.2&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| 10.11&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| Apache 2.4&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| &#039;&#039;&#039;192.168.1.79&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| RAM&lt;br /&gt;
| 2048 MB&lt;br /&gt;
|-&lt;br /&gt;
| Swap&lt;br /&gt;
| 512 MB&lt;br /&gt;
|-&lt;br /&gt;
| CPU&lt;br /&gt;
| 2 vCPU&lt;br /&gt;
|-&lt;br /&gt;
| RootFS&lt;br /&gt;
| 16 GB&lt;br /&gt;
|-&lt;br /&gt;
| Storage&lt;br /&gt;
| OMV-SSD1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Система работает как unprivileged LXC-контейнер.&lt;br /&gt;
&lt;br /&gt;
== Схема работы ==&lt;br /&gt;
&lt;br /&gt;
Публичный HTTPS завершается на reverse proxy BrainyCP.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Internet&lt;br /&gt;
   │&lt;br /&gt;
   │ HTTPS :443&lt;br /&gt;
   ▼&lt;br /&gt;
wiki.ramba-art.ru&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
BrainyCP / nginx&lt;br /&gt;
CT 105&lt;br /&gt;
192.168.1.12&lt;br /&gt;
   │&lt;br /&gt;
   │ HTTP :80&lt;br /&gt;
   ▼&lt;br /&gt;
RAMBA Wiki&lt;br /&gt;
CT 102 — wiki-v2&lt;br /&gt;
192.168.1.79&lt;br /&gt;
   │&lt;br /&gt;
   ├── Apache&lt;br /&gt;
   ├── PHP 8.2&lt;br /&gt;
   ├── MediaWiki 1.43&lt;br /&gt;
   └── MariaDB 10.11&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TLS-сертификат обслуживается reverse proxy.&lt;br /&gt;
&lt;br /&gt;
Сам MediaWiki-контейнер не требует собственного HTTPS-сервера.&lt;br /&gt;
&lt;br /&gt;
== Создание нового контейнера ==&lt;br /&gt;
&lt;br /&gt;
Новая Wiki была развёрнута на чистом Debian 12.&lt;br /&gt;
&lt;br /&gt;
Основные установленные компоненты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apache2&lt;br /&gt;
mariadb-server&lt;br /&gt;
imagemagick&lt;br /&gt;
&lt;br /&gt;
php8.2&lt;br /&gt;
libapache2-mod-php8.2&lt;br /&gt;
php8.2-mysql&lt;br /&gt;
php8.2-intl&lt;br /&gt;
php8.2-mbstring&lt;br /&gt;
php8.2-xml&lt;br /&gt;
php8.2-curl&lt;br /&gt;
php8.2-gd&lt;br /&gt;
php8.2-zip&lt;br /&gt;
php8.2-apcu&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для Apache были активированы необходимые модули:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
a2enmod rewrite&lt;br /&gt;
a2enmod headers&lt;br /&gt;
a2enmod expires&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Основная директория MediaWiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Перенос базы данных ==&lt;br /&gt;
&lt;br /&gt;
База данных старой Wiki была экспортирована из CT 115 и импортирована в MariaDB нового CT 102.&lt;br /&gt;
&lt;br /&gt;
После импорта был выполнен штатный процесс обновления схемы базы данных MediaWiki.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /var/www/mediawiki&lt;br /&gt;
runuser -u www-data -- php maintenance/run.php update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обновление схемы прошло успешно.&lt;br /&gt;
&lt;br /&gt;
В результате были сохранены:&lt;br /&gt;
&lt;br /&gt;
* статьи;&lt;br /&gt;
* ревизии;&lt;br /&gt;
* категории;&lt;br /&gt;
* пользователи;&lt;br /&gt;
* права пользователей;&lt;br /&gt;
* служебные страницы MediaWiki;&lt;br /&gt;
* история изменений.&lt;br /&gt;
&lt;br /&gt;
== Перенос изображений ==&lt;br /&gt;
&lt;br /&gt;
Каталог загруженных файлов старой Wiki был перенесён в:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki/images&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После переноса были восстановлены корректные права доступа для Apache:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chown -R www-data:www-data /var/www/mediawiki/images&lt;br /&gt;
find /var/www/mediawiki/images -type d -exec chmod 755 {} \;&lt;br /&gt;
find /var/www/mediawiki/images -type f -exec chmod 644 {} \;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также был перенесён логотип RAMBA Wiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/var/www/mediawiki/resources/assets/ramba_b.png&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Короткие URL ==&lt;br /&gt;
&lt;br /&gt;
Для статей сохранена привычная структура адресов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Название_страницы&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В MediaWiki используется:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$wgScriptPath = &amp;quot;&amp;quot;;&lt;br /&gt;
$wgArticlePath = &amp;quot;/wiki/$1&amp;quot;;&lt;br /&gt;
$wgServer = &amp;quot;https://wiki.ramba-art.ru&amp;quot;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Apache выполняет перенаправление запросов вида:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
/wiki/Название&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на MediaWiki `index.php`.&lt;br /&gt;
&lt;br /&gt;
== Reverse Proxy ==&lt;br /&gt;
&lt;br /&gt;
Reverse proxy RAMBA Wiki находится в BrainyCP:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Параметр&lt;br /&gt;
! Значение&lt;br /&gt;
|-&lt;br /&gt;
| Proxmox CT&lt;br /&gt;
| 105&lt;br /&gt;
|-&lt;br /&gt;
| IP&lt;br /&gt;
| 192.168.1.12&lt;br /&gt;
|-&lt;br /&gt;
| Web-сервер&lt;br /&gt;
| nginx&lt;br /&gt;
|-&lt;br /&gt;
| Backend&lt;br /&gt;
| 192.168.1.79:80&lt;br /&gt;
|-&lt;br /&gt;
| Frontend&lt;br /&gt;
| HTTPS :443&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Основной upstream:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;nginx&amp;quot;&amp;gt;&lt;br /&gt;
location / {&lt;br /&gt;
    proxy_pass http://192.168.1.79:80;&lt;br /&gt;
&lt;br /&gt;
    proxy_http_version 1.1;&lt;br /&gt;
&lt;br /&gt;
    proxy_set_header Host $host;&lt;br /&gt;
    proxy_set_header X-Real-IP $remote_addr;&lt;br /&gt;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;&lt;br /&gt;
&lt;br /&gt;
    proxy_set_header X-Forwarded-Proto https;&lt;br /&gt;
    proxy_set_header X-Forwarded-Host $host;&lt;br /&gt;
    proxy_set_header X-Forwarded-Port 443;&lt;br /&gt;
&lt;br /&gt;
    proxy_redirect off;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
До миграции upstream указывал на старый сервер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
192.168.1.11:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После проверки новой Wiki он был изменён на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволило переключить production без изменения DNS.&lt;br /&gt;
&lt;br /&gt;
== HTTPS за reverse proxy ==&lt;br /&gt;
&lt;br /&gt;
Поскольку HTTPS завершается на nginx, а между nginx и Apache используется HTTP, MediaWiki необходимо корректно сообщать исходный протокол запроса.&lt;br /&gt;
&lt;br /&gt;
В `LocalSettings.php` добавлена проверка доверенного reverse proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (&lt;br /&gt;
    ($_SERVER[&amp;quot;REMOTE_ADDR&amp;quot;] ?? &amp;quot;&amp;quot;) === &amp;quot;192.168.1.12&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
    ($_SERVER[&amp;quot;HTTP_X_FORWARDED_PROTO&amp;quot;] ?? &amp;quot;&amp;quot;) === &amp;quot;https&amp;quot;&lt;br /&gt;
) {&lt;br /&gt;
    $_SERVER[&amp;quot;HTTPS&amp;quot;] = &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Заголовок `X-Forwarded-Proto` принимается только от reverse proxy RAMBA с адресом `192.168.1.12`.&lt;br /&gt;
&lt;br /&gt;
== Мобильная версия ==&lt;br /&gt;
&lt;br /&gt;
Для мобильного интерфейса используются:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MobileFrontend&#039;&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;MinervaNeue&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Конфигурация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadSkin( &#039;MinervaNeue&#039; );&lt;br /&gt;
&lt;br /&gt;
$wgDefaultMobileSkin = &#039;minerva&#039;;&lt;br /&gt;
&lt;br /&gt;
wfLoadExtension( &#039;MobileFrontend&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Расширение MobileFrontend установлено в версии, совместимой с MediaWiki 1.43.&lt;br /&gt;
&lt;br /&gt;
После миграции была дополнительно переработана главная страница RAMBA Wiki, чтобы карточки корректно отображались на небольших экранах.&lt;br /&gt;
&lt;br /&gt;
На мобильных устройствах карточки автоматически перестраиваются в один столбец.&lt;br /&gt;
&lt;br /&gt;
== Редактирование исходного кода ==&lt;br /&gt;
&lt;br /&gt;
Для работы с исходным кодом страниц используются:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;WikiEditor&#039; );&lt;br /&gt;
wfLoadExtension( &#039;CodeEditor&#039; );&lt;br /&gt;
wfLoadExtension( &#039;SyntaxHighlight_GeSHi&#039; );&lt;br /&gt;
&lt;br /&gt;
$wgDefaultUserOptions[&#039;usebetatoolbar&#039;] = 1;&lt;br /&gt;
$wgWikiEditorRealtimePreview = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`SyntaxHighlight_GeSHi` используется для оформления команд, конфигурационных файлов и программного кода в технических статьях RAMBA Wiki.&lt;br /&gt;
&lt;br /&gt;
== Основные расширения ==&lt;br /&gt;
&lt;br /&gt;
После миграции были активированы необходимые стандартные расширения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;ParserFunctions&#039; );&lt;br /&gt;
wfLoadExtension( &#039;Cite&#039; );&lt;br /&gt;
wfLoadExtension( &#039;TemplateData&#039; );&lt;br /&gt;
wfLoadExtension( &#039;InputBox&#039; );&lt;br /&gt;
wfLoadExtension( &#039;ImageMap&#039; );&lt;br /&gt;
wfLoadExtension( &#039;Nuke&#039; );&lt;br /&gt;
wfLoadExtension( &#039;ReplaceText&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DynamicPageList3 ==&lt;br /&gt;
&lt;br /&gt;
Для существующих страниц RAMBA Wiki была сохранена поддержка DynamicPageList3.&lt;br /&gt;
&lt;br /&gt;
Установлен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
DynamicPageList3 3.5.2&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Активация:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
wfLoadExtension( &#039;DynamicPageList3&#039; );&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После установки расширение было проверено на MediaWiki 1.43.&lt;br /&gt;
&lt;br /&gt;
== RambaGameMonitor ==&lt;br /&gt;
&lt;br /&gt;
Сохранено собственное расширение &#039;&#039;&#039;RambaGameMonitor&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Расширение предоставляет тег:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;rambamonitor /&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
который позволяет отображать состояние игровых серверов непосредственно на страницах RAMBA Wiki.&lt;br /&gt;
&lt;br /&gt;
В текущей реализации выполняются запросы:&lt;br /&gt;
&lt;br /&gt;
* Rust — Source Engine Query / UDP;&lt;br /&gt;
* Minecraft Java Edition — Server List Ping / TCP.&lt;br /&gt;
&lt;br /&gt;
Пример результата:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Сервер&lt;br /&gt;
! Состояние&lt;br /&gt;
! Игроки&lt;br /&gt;
! Дополнительная информация&lt;br /&gt;
|-&lt;br /&gt;
| Rust&lt;br /&gt;
| Online / Offline&lt;br /&gt;
| текущие / максимум&lt;br /&gt;
| карта&lt;br /&gt;
|-&lt;br /&gt;
| Minecraft&lt;br /&gt;
| Online / Offline&lt;br /&gt;
| текущие / максимум&lt;br /&gt;
| версия&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
После переноса расширение было проверено непосредственно на MediaWiki 1.43 и PHP 8.2.&lt;br /&gt;
&lt;br /&gt;
== Отказ от устаревших компонентов ==&lt;br /&gt;
&lt;br /&gt;
Во время миграции была проведена ревизия расширений старой Wiki.&lt;br /&gt;
&lt;br /&gt;
Некоторые компоненты намеренно не переносились.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Компонент&lt;br /&gt;
! Решение&lt;br /&gt;
! Причина&lt;br /&gt;
|-&lt;br /&gt;
| GameQ&lt;br /&gt;
| Не переносить&lt;br /&gt;
| RambaGameMonitor больше не зависит от GameQ&lt;br /&gt;
|-&lt;br /&gt;
| LocalisationUpdate&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Устаревшее расширение&lt;br /&gt;
|-&lt;br /&gt;
| GoogleCodePrettify&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Заменено SyntaxHighlight&lt;br /&gt;
|-&lt;br /&gt;
| Renameuser&lt;br /&gt;
| Не переносить&lt;br /&gt;
| Функциональность присутствует в современном MediaWiki&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Таким образом новая установка не является простой копией старого сервера — устаревшие компоненты были удалены.&lt;br /&gt;
&lt;br /&gt;
== Права доступа ==&lt;br /&gt;
&lt;br /&gt;
Анонимным пользователям разрешено чтение Wiki, но запрещено редактирование и самостоятельная регистрация.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;read&#039;] = true;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;edit&#039;] = false;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;createpage&#039;] = false;&lt;br /&gt;
$wgGroupPermissions[&#039;*&#039;][&#039;createaccount&#039;] = false;&lt;br /&gt;
&lt;br /&gt;
$wgGroupPermissions[&#039;user&#039;][&#039;edit&#039;] = true;&lt;br /&gt;
$wgGroupPermissions[&#039;user&#039;][&#039;createpage&#039;] = true;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для администратора Wiki дополнительно было назначено право:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
interface-admin&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это необходимо для редактирования системных CSS/JS-страниц, включая:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
MediaWiki:Common.css&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Безопасность ==&lt;br /&gt;
&lt;br /&gt;
После миграции были сгенерированы новые значения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
$wgSecretKey&lt;br /&gt;
$wgUpgradeKey&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Старые значения больше не используются.&lt;br /&gt;
&lt;br /&gt;
Значения ключей в документации намеренно не публикуются.&lt;br /&gt;
&lt;br /&gt;
Пароль базы данных также не должен храниться в статьях Wiki или открытых конфигурационных примерах.&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
После успешного запуска production была создана полная резервная копия нового CT 102 в &#039;&#039;&#039;Proxmox Backup Server&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Идентификатор backup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
ct/102/2026-09-02T08:36:30Z&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Объём файловой системы на момент резервного копирования составлял приблизительно:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
1.77 GiB&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После дедупликации и сжатия в PBS было передано около:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
568 MiB&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Так как используемое для rootfs NFS-хранилище не поддерживает необходимый тип snapshot, Proxmox автоматически переключил backup из режима `snapshot` в режим `suspend`.&lt;br /&gt;
&lt;br /&gt;
Контейнер был приостановлен приблизительно на две секунды.&lt;br /&gt;
&lt;br /&gt;
Backup завершился успешно.&lt;br /&gt;
&lt;br /&gt;
== Переключение production ==&lt;br /&gt;
&lt;br /&gt;
После проверки новой системы был изменён upstream nginx:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
СТАРЫЙ:&lt;br /&gt;
192.168.1.11:80&lt;br /&gt;
&lt;br /&gt;
НОВЫЙ:&lt;br /&gt;
192.168.1.79:80&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перед применением конфигурации nginx была выполнена проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nginx -t&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После успешной проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl reload nginx&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Публичный запрос подтвердил:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
https://wiki.ramba-art.ru/&lt;br /&gt;
        ↓&lt;br /&gt;
HTTP 301&lt;br /&gt;
        ↓&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Заглавная_страница&lt;br /&gt;
        ↓&lt;br /&gt;
HTTP 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка после миграции ==&lt;br /&gt;
&lt;br /&gt;
После переключения production были протестированы:&lt;br /&gt;
&lt;br /&gt;
* открытие главной страницы;&lt;br /&gt;
* HTTPS;&lt;br /&gt;
* короткие URL;&lt;br /&gt;
* авторизация;&lt;br /&gt;
* редактирование статей;&lt;br /&gt;
* редактирование `MediaWiki:Common.css`;&lt;br /&gt;
* загрузка файлов;&lt;br /&gt;
* отображение изображений;&lt;br /&gt;
* мобильный интерфейс;&lt;br /&gt;
* MinervaNeue;&lt;br /&gt;
* DynamicPageList3;&lt;br /&gt;
* SyntaxHighlight;&lt;br /&gt;
* RambaGameMonitor;&lt;br /&gt;
* Apache;&lt;br /&gt;
* MariaDB.&lt;br /&gt;
&lt;br /&gt;
Финальная проверка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTP: 200&lt;br /&gt;
Redirects: 1&lt;br /&gt;
Final:&lt;br /&gt;
https://wiki.ramba-art.ru/wiki/Заглавная_страница&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Вывод старой системы из эксплуатации ==&lt;br /&gt;
&lt;br /&gt;
После успешной работы CT 102 старый контейнер CT 115 был остановлен.&lt;br /&gt;
&lt;br /&gt;
После остановки была повторно проверена публичная Wiki:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
CT 102: running&lt;br /&gt;
CT 115: stopped&lt;br /&gt;
wiki.ramba-art.ru: HTTP 200&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это подтвердило отсутствие зависимости production от старого контейнера.&lt;br /&gt;
&lt;br /&gt;
После этого была создана финальная резервная копия CT 115 в Proxmox Backup Server.&lt;br /&gt;
&lt;br /&gt;
Старый контейнер был удалён:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pct destroy 115&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Proxmox подтвердил удаление старого диска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Logical volume &amp;quot;vm-115-disk-0&amp;quot; successfully removed.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После полного удаления CT 115 Wiki была проверена ещё раз:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
HTTP: 200&lt;br /&gt;
Time: 0.262066s&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом старая установка полностью выведена из эксплуатации.&lt;br /&gt;
&lt;br /&gt;
== Итоговая конфигурация ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-grid&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;🌐 Production&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;wiki.ramba-art.ru&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MediaWiki 1.43.9 LTS&lt;br /&gt;
&lt;br /&gt;
Debian 12 Bookworm&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;📦 Контейнер&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
CT &#039;&#039;&#039;102&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;wiki-v2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
192.168.1.79&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;🔀 Reverse Proxy&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
BrainyCP&lt;br /&gt;
&lt;br /&gt;
CT &#039;&#039;&#039;105&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
192.168.1.12&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;portal-card&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;💾 Backup&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Proxmox Backup Server&lt;br /&gt;
&lt;br /&gt;
Резервируются новая и архивная версии Wiki&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Результат ==&lt;br /&gt;
&lt;br /&gt;
Миграция RAMBA Wiki выполнена успешно.&lt;br /&gt;
&lt;br /&gt;
Старая архитектура:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
TurnKey Linux&lt;br /&gt;
Debian 11&lt;br /&gt;
MediaWiki 1.39&lt;br /&gt;
PHP 7.4&lt;br /&gt;
CT 115&lt;br /&gt;
192.168.1.11&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
заменена на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
Debian 12&lt;br /&gt;
MediaWiki 1.43.9 LTS&lt;br /&gt;
PHP 8.2&lt;br /&gt;
MariaDB 10.11&lt;br /&gt;
CT 102&lt;br /&gt;
192.168.1.79&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При этом были сохранены существующие данные Wiki и необходимые функции, удалены устаревшие компоненты, восстановлена мобильная версия, настроен reverse proxy и HTTPS, обновлены ключи безопасности и создана новая точка восстановления в Proxmox Backup Server.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;RAMBA Wiki полностью переведена на новую инфраструктуру.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[Категория:RAMBA Wiki]]&lt;br /&gt;
[[Категория:MediaWiki]]&lt;br /&gt;
[[Категория:Proxmox]]&lt;br /&gt;
[[Категория:Инфраструктура RAMBA]]&lt;br /&gt;
[[Категория:Миграции]]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=135</id>
		<title>Gitignore</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=135"/>
		<updated>2026-09-02T08:41:31Z</updated>

		<summary type="html">&lt;p&gt;Artem: /* Python.gitignore */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Python.gitignore ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ссылка на [https://github.com/github/gitignore/blob/main/Python.gitignore гитхаб]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore .gitignore file тут]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==0209==&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=127</id>
		<title>Unit for tg bot</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=127"/>
		<updated>2026-08-31T18:36:12Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Запуск Python-скрипта как службы systemd =&lt;br /&gt;
&lt;br /&gt;
В Linux Python-скрипт можно запустить как системную службу с помощью ‘’‘systemd’’’ .&lt;br /&gt;
&lt;br /&gt;
Это удобно для Telegram-ботов, веб-сервисов и других приложений, которые должны:&lt;br /&gt;
&lt;br /&gt;
* автоматически запускаться вместе с сервером;&lt;br /&gt;
* работать в фоновом режиме;&lt;br /&gt;
* автоматически перезапускаться после ошибки;&lt;br /&gt;
* управляться стандартными командами systemctl;&lt;br /&gt;
* сохранять журнал работы в journalctl.&lt;br /&gt;
&lt;br /&gt;
В этой статье рассмотрим два варианта запуска Python-приложения на примере Telegram-бота ‘’‘noProdaction’’’.&lt;br /&gt;
&lt;br /&gt;
TOC&lt;br /&gt;
&lt;br /&gt;
== Способ №1 — запуск через отдельный shell-скрипт ==&lt;br /&gt;
&lt;br /&gt;
В этом варианте systemd запускает вспомогательный shell-скрипт, который, в свою очередь, запускает Python-приложение.&lt;br /&gt;
&lt;br /&gt;
Схема запуска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemd&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
noProdaction.sh&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
python3&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Создание скрипта запуска ===&lt;br /&gt;
&lt;br /&gt;
Создаём каталог для скрипта запуска, если его ещё нет:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /opt/Python/Telegram/start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
exec /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
Сохраняем файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + O&lt;br /&gt;
Enter&lt;br /&gt;
Ctrl + X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Делаем его исполняемым:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x /opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|Использование exec позволяет заменить процесс shell непосредственно процессом Python. Благодаря этому systemd корректнее отслеживает PID приложения и управляет его завершением.}}&lt;br /&gt;
&lt;br /&gt;
=== Создание systemd unit ===&lt;br /&gt;
&lt;br /&gt;
Создаём unit-файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=root&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
ExecStart=/opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
Сохраняем файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + O&lt;br /&gt;
Enter&lt;br /&gt;
Ctrl + X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Активация службы ===&lt;br /&gt;
&lt;br /&gt;
После создания или изменения unit-файла необходимо перечитать конфигурацию systemd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем службу в автозагрузку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запускаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно выполнить обе команды сразу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка работы ===&lt;br /&gt;
&lt;br /&gt;
Проверяем состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При нормальной работе должна присутствовать строка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
● noprodaction.service - Telegram bot noProdaction&lt;br /&gt;
     Loaded: loaded (/etc/systemd/system/noprodaction.service; enabled)&lt;br /&gt;
     Active: active (running)&lt;br /&gt;
   Main PID: 173 (python3.11)&lt;br /&gt;
      Tasks: 2&lt;br /&gt;
     Memory: 34.1M&lt;br /&gt;
        CPU: 1.766s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Способ №2 — запуск Python напрямую из systemd ==&lt;br /&gt;
&lt;br /&gt;
{{Note|’’‘Рекомендуемый вариант.’’’ Если для запуска приложения не требуется выполнять дополнительные команды, создавать отдельный .sh-файл нет необходимости. Python можно запускать непосредственно из systemd.}}&lt;br /&gt;
&lt;br /&gt;
Схема становится проще:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemd&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
python3&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём unit-файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
&lt;br /&gt;
User=root&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
&lt;br /&gt;
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
После создания файла выполняем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Управление службой ==&lt;br /&gt;
&lt;br /&gt;
После создания unit-файла ботом можно управлять стандартными командами systemd.&lt;br /&gt;
&lt;br /&gt;
{| class=“wikitable”&lt;br /&gt;
! Действие&lt;br /&gt;
&lt;br /&gt;
! Команда&lt;br /&gt;
&lt;br /&gt;
Проверить состояние&lt;br /&gt;
&lt;br /&gt;
systemctl status noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Запустить&lt;br /&gt;
&lt;br /&gt;
systemctl start noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Остановить&lt;br /&gt;
&lt;br /&gt;
systemctl stop noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Перезапустить&lt;br /&gt;
&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Добавить в автозагрузку&lt;br /&gt;
&lt;br /&gt;
systemctl enable noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Убрать из автозагрузки&lt;br /&gt;
&lt;br /&gt;
systemctl disable noprodaction&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
== Просмотр логов ==&lt;br /&gt;
&lt;br /&gt;
Одно из преимуществ запуска через systemd — вывод Python-приложения автоматически попадает в системный журнал.&lt;br /&gt;
&lt;br /&gt;
Посмотреть последние записи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последние 100 строк:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -n 100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следить за журналом в реальном времени:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выйти из режима просмотра:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + C&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть журнал только с момента последней загрузки сервера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -b&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== После изменения Python-кода ==&lt;br /&gt;
&lt;br /&gt;
Если был изменён только код main.py или других файлов приложения, выполнять daemon-reload не требуется.&lt;br /&gt;
&lt;br /&gt;
Достаточно перезапустить приложение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если же был изменён сам файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
необходимо выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Автоматический перезапуск ==&lt;br /&gt;
&lt;br /&gt;
В нашем unit-файле используются параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это означает, что если Python-процесс аварийно завершится, systemd подождёт 5 секунд и попробует запустить его снова.&lt;br /&gt;
&lt;br /&gt;
Проверить количество перезапусков можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl show noprodaction.service -p NRestarts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка пути к Python ==&lt;br /&gt;
&lt;br /&gt;
Путь к Python может отличаться в зависимости от системы.&lt;br /&gt;
&lt;br /&gt;
Проверить его можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
which python3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Версию Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python3 --version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если конкретная версия Python не требуется, в unit-файле можно использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
ExecStart=/usr/bin/python3 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Запуск через Python Virtual Environment ==&lt;br /&gt;
&lt;br /&gt;
Если проект использует собственное виртуальное окружение Python, рекомендуется запускать Python непосредственно из него.&lt;br /&gt;
&lt;br /&gt;
Например, если виртуальное окружение находится здесь:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/Python/Telegram/noProdaction/venv/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то ExecStart будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
ExecStart=/opt/Python/Telegram/noProdaction/venv/bin/python /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Активировать venv командой source внутри systemd не требуется.&lt;br /&gt;
&lt;br /&gt;
== Рекомендуемый unit-файл ==&lt;br /&gt;
&lt;br /&gt;
Для обычного Python-приложения итоговый вариант может выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=root&lt;br /&gt;
&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
После создания:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и журнал:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Примечание по безопасности ==&lt;br /&gt;
&lt;br /&gt;
В примерах выше служба запускается от пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=root&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для собственного сервера это работает, однако большинству Python-приложений права root не нужны.&lt;br /&gt;
&lt;br /&gt;
Более безопасный вариант — создать отдельного системного пользователя для приложения и запускать службу от его имени.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
useradd --system --home /opt/Python/Telegram/noProdaction --shell /usr/sbin/nologin noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого необходимо выдать пользователю права на необходимые файлы приложения и заменить в unit-файле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=root&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Warning|Не храните токены Telegram-бота, API-ключи, пароли баз данных и другие секреты непосредственно в публичном unit-файле или исходном коде проекта. Для секретов лучше использовать отдельный файл окружения с ограниченными правами доступа.}}&lt;br /&gt;
&lt;br /&gt;
== Итог ==&lt;br /&gt;
&lt;br /&gt;
Для простого Python-приложения рекомендуется использовать ‘’‘Способ №2’’’:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             Загрузка Linux&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                 systemd&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
         noprodaction.service&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                Python&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                main.py&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
             Telegram Bot&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого приложение автоматически запускается вместе с системой, работает в фоне и при аварийном завершении автоматически запускается снова.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=126</id>
		<title>Unit for tg bot</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=126"/>
		<updated>2026-08-31T18:35:43Z</updated>

		<summary type="html">&lt;p&gt;Artem: /* Запуск Python-скрипта как службы systemd */Обновление статьи&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Запуск Python-скрипта как службы systemd =&lt;br /&gt;
&lt;br /&gt;
В Linux Python-скрипт можно запустить как системную службу с помощью ‘’‘systemd’’’.&lt;br /&gt;
&lt;br /&gt;
Это удобно для Telegram-ботов, веб-сервисов и других приложений, которые должны:&lt;br /&gt;
&lt;br /&gt;
* автоматически запускаться вместе с сервером;&lt;br /&gt;
* работать в фоновом режиме;&lt;br /&gt;
* автоматически перезапускаться после ошибки;&lt;br /&gt;
* управляться стандартными командами systemctl;&lt;br /&gt;
* сохранять журнал работы в journalctl.&lt;br /&gt;
&lt;br /&gt;
В этой статье рассмотрим два варианта запуска Python-приложения на примере Telegram-бота ‘’‘noProdaction’’’.&lt;br /&gt;
&lt;br /&gt;
TOC&lt;br /&gt;
&lt;br /&gt;
== Способ №1 — запуск через отдельный shell-скрипт ==&lt;br /&gt;
&lt;br /&gt;
В этом варианте systemd запускает вспомогательный shell-скрипт, который, в свою очередь, запускает Python-приложение.&lt;br /&gt;
&lt;br /&gt;
Схема запуска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemd&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
noProdaction.sh&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
python3&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Создание скрипта запуска ===&lt;br /&gt;
&lt;br /&gt;
Создаём каталог для скрипта запуска, если его ещё нет:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /opt/Python/Telegram/start&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
#!/bin/bash&lt;br /&gt;
&lt;br /&gt;
exec /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
Сохраняем файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + O&lt;br /&gt;
Enter&lt;br /&gt;
Ctrl + X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Делаем его исполняемым:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
chmod +x /opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Note|Использование exec позволяет заменить процесс shell непосредственно процессом Python. Благодаря этому systemd корректнее отслеживает PID приложения и управляет его завершением.}}&lt;br /&gt;
&lt;br /&gt;
=== Создание systemd unit ===&lt;br /&gt;
&lt;br /&gt;
Создаём unit-файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=root&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
ExecStart=/opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
Сохраняем файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + O&lt;br /&gt;
Enter&lt;br /&gt;
Ctrl + X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Активация службы ===&lt;br /&gt;
&lt;br /&gt;
После создания или изменения unit-файла необходимо перечитать конфигурацию systemd:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем службу в автозагрузку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Запускаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Можно выполнить обе команды сразу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверка работы ===&lt;br /&gt;
&lt;br /&gt;
Проверяем состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При нормальной работе должна присутствовать строка:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Active: active (running)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
● noprodaction.service - Telegram bot noProdaction&lt;br /&gt;
     Loaded: loaded (/etc/systemd/system/noprodaction.service; enabled)&lt;br /&gt;
     Active: active (running)&lt;br /&gt;
   Main PID: 173 (python3.11)&lt;br /&gt;
      Tasks: 2&lt;br /&gt;
     Memory: 34.1M&lt;br /&gt;
        CPU: 1.766s&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Способ №2 — запуск Python напрямую из systemd ==&lt;br /&gt;
&lt;br /&gt;
{{Note|’’‘Рекомендуемый вариант.’’’ Если для запуска приложения не требуется выполнять дополнительные команды, создавать отдельный .sh-файл нет необходимости. Python можно запускать непосредственно из systemd.}}&lt;br /&gt;
&lt;br /&gt;
Схема становится проще:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
systemd&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
python3&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём unit-файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano /etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
&lt;br /&gt;
User=root&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
&lt;br /&gt;
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
После создания файла выполняем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Управление службой ==&lt;br /&gt;
&lt;br /&gt;
После создания unit-файла ботом можно управлять стандартными командами systemd.&lt;br /&gt;
&lt;br /&gt;
{| class=“wikitable”&lt;br /&gt;
! Действие&lt;br /&gt;
&lt;br /&gt;
! Команда&lt;br /&gt;
&lt;br /&gt;
Проверить состояние&lt;br /&gt;
&lt;br /&gt;
systemctl status noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Запустить&lt;br /&gt;
&lt;br /&gt;
systemctl start noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Остановить&lt;br /&gt;
&lt;br /&gt;
systemctl stop noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Перезапустить&lt;br /&gt;
&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Добавить в автозагрузку&lt;br /&gt;
&lt;br /&gt;
systemctl enable noprodaction&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Убрать из автозагрузки&lt;br /&gt;
&lt;br /&gt;
systemctl disable noprodaction&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
== Просмотр логов ==&lt;br /&gt;
&lt;br /&gt;
Одно из преимуществ запуска через systemd — вывод Python-приложения автоматически попадает в системный журнал.&lt;br /&gt;
&lt;br /&gt;
Посмотреть последние записи:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Последние 100 строк:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -n 100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Следить за журналом в реальном времени:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выйти из режима просмотра:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + C&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Посмотреть журнал только с момента последней загрузки сервера:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -b&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== После изменения Python-кода ==&lt;br /&gt;
&lt;br /&gt;
Если был изменён только код main.py или других файлов приложения, выполнять daemon-reload не требуется.&lt;br /&gt;
&lt;br /&gt;
Достаточно перезапустить приложение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если же был изменён сам файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/etc/systemd/system/noprodaction.service&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
необходимо выполнить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl restart noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Автоматический перезапуск ==&lt;br /&gt;
&lt;br /&gt;
В нашем unit-файле используются параметры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это означает, что если Python-процесс аварийно завершится, systemd подождёт 5 секунд и попробует запустить его снова.&lt;br /&gt;
&lt;br /&gt;
Проверить количество перезапусков можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl show noprodaction.service -p NRestarts&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка пути к Python ==&lt;br /&gt;
&lt;br /&gt;
Путь к Python может отличаться в зависимости от системы.&lt;br /&gt;
&lt;br /&gt;
Проверить его можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
which python3&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/usr/bin/python3&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Версию Python:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
python3 --version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если конкретная версия Python не требуется, в unit-файле можно использовать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
ExecStart=/usr/bin/python3 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Запуск через Python Virtual Environment ==&lt;br /&gt;
&lt;br /&gt;
Если проект использует собственное виртуальное окружение Python, рекомендуется запускать Python непосредственно из него.&lt;br /&gt;
&lt;br /&gt;
Например, если виртуальное окружение находится здесь:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/Python/Telegram/noProdaction/venv/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то ExecStart будет выглядеть так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
ExecStart=/opt/Python/Telegram/noProdaction/venv/bin/python /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Активировать venv командой source внутри systemd не требуется.&lt;br /&gt;
&lt;br /&gt;
== Рекомендуемый unit-файл ==&lt;br /&gt;
&lt;br /&gt;
Для обычного Python-приложения итоговый вариант может выглядеть следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
[Unit]&lt;br /&gt;
Description=Telegram bot noProdaction&lt;br /&gt;
After=network-online.target&lt;br /&gt;
Wants=network-online.target&lt;br /&gt;
&lt;br /&gt;
[Service]&lt;br /&gt;
Type=simple&lt;br /&gt;
User=root&lt;br /&gt;
&lt;br /&gt;
WorkingDirectory=/opt/Python/Telegram/noProdaction/noprodaction-1&lt;br /&gt;
ExecStart=/usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&lt;br /&gt;
Restart=on-failure&lt;br /&gt;
RestartSec=5&lt;br /&gt;
&lt;br /&gt;
NoNewPrivileges=true&lt;br /&gt;
PrivateDevices=true&lt;br /&gt;
ProtectSystem=full&lt;br /&gt;
&lt;br /&gt;
[Install]&lt;br /&gt;
WantedBy=multi-user.target&lt;br /&gt;
После создания:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl daemon-reload&lt;br /&gt;
systemctl enable --now noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status noprodaction.service&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и журнал:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
journalctl -u noprodaction.service -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Примечание по безопасности ==&lt;br /&gt;
&lt;br /&gt;
В примерах выше служба запускается от пользователя:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=root&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для собственного сервера это работает, однако большинству Python-приложений права root не нужны.&lt;br /&gt;
&lt;br /&gt;
Более безопасный вариант — создать отдельного системного пользователя для приложения и запускать службу от его имени.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
useradd --system --home /opt/Python/Telegram/noProdaction --shell /usr/sbin/nologin noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого необходимо выдать пользователю права на необходимые файлы приложения и заменить в unit-файле:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=root&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
на:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;ini&amp;quot;&amp;gt;&lt;br /&gt;
User=noprodaction&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Warning|Не храните токены Telegram-бота, API-ключи, пароли баз данных и другие секреты непосредственно в публичном unit-файле или исходном коде проекта. Для секретов лучше использовать отдельный файл окружения с ограниченными правами доступа.}}&lt;br /&gt;
&lt;br /&gt;
== Итог ==&lt;br /&gt;
&lt;br /&gt;
Для простого Python-приложения рекомендуется использовать ‘’‘Способ №2’’’:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
             Загрузка Linux&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                 systemd&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
         noprodaction.service&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                Python&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
                main.py&lt;br /&gt;
                    │&lt;br /&gt;
                    ▼&lt;br /&gt;
             Telegram Bot&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После этого приложение автоматически запускается вместе с системой, работает в фоне и при аварийном завершении автоматически запускается снова.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=125</id>
		<title>Unit for tg bot</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=125"/>
		<updated>2026-08-31T18:34:47Z</updated>

		<summary type="html">&lt;p&gt;Artem: Содержимое страницы заменено на «== &amp;#039;&amp;#039;&amp;#039;Создаем Unit для tg bot&amp;#039;&amp;#039;&amp;#039; ==»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &#039;&#039;&#039;Создаем Unit для tg bot&#039;&#039;&#039; ==&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=124</id>
		<title>Unit for tg bot</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=124"/>
		<updated>2026-08-31T18:34:29Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== &#039;&#039;&#039;Создаем Unit для tg bot&#039;&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
=== &#039;&#039;&#039;Способ №1:&#039;&#039;&#039; ===&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
Создаем исполняемый фаил &#039;&#039;&#039;noProdaction.sh&#039;&#039;&#039; и в нем вписываем что то типо:&lt;br /&gt;
    &lt;br /&gt;
    #!/bin/bash&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
    /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&lt;br /&gt;
&lt;br /&gt;
Далее создаем  с помощью нашего любимого редактора &#039;&#039;&#039;nano&#039;&#039;&#039; по пути /&#039;&#039;&#039;etc/systemd/system/&#039;&#039;&#039; фаил &#039;&#039;&#039;noprodaction.service&#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
    nano /etc/systemd/system/noprodaction.service&lt;br /&gt;
&lt;br /&gt;
И вписываем что то типо такого:&lt;br /&gt;
&lt;br /&gt;
    [Unit]&lt;br /&gt;
    Description=telegam bot OmArtVal&lt;br /&gt;
    After=network.target&amp;lt;br&amp;gt;&lt;br /&gt;
    [Service]&lt;br /&gt;
    User=root&lt;br /&gt;
    Nice=1&lt;br /&gt;
    KillMode=process&lt;br /&gt;
    SuccessExitStatus=0 1&lt;br /&gt;
    ProtectHome=true&lt;br /&gt;
    ProtectSystem=full&lt;br /&gt;
    PrivateDevices=true&lt;br /&gt;
    NoNewPrivileges=true&lt;br /&gt;
    WorkingDirectory=/opt/Python/Telegram/noProdaction&lt;br /&gt;
    ExecStart=/opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
    Restart=always&amp;lt;br&amp;gt;&lt;br /&gt;
    [Install]&lt;br /&gt;
    WantedBy=multi-user.target&lt;br /&gt;
&lt;br /&gt;
Закрываем редактор с сохранением изменений &#039;&#039;&#039;CTRL+O&#039;&#039;&#039; и &#039;&#039;&#039;CTRL+X&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Перезагружаем демона:&lt;br /&gt;
&lt;br /&gt;
    systemctl daemon-reload&lt;br /&gt;
&lt;br /&gt;
И стартуем его:&lt;br /&gt;
&lt;br /&gt;
    systemctl start noprodaction.service&lt;br /&gt;
&lt;br /&gt;
И все! Наш сервис должен работать! Проверить это можно командой &lt;br /&gt;
&lt;br /&gt;
    systemctl status noprodaction.service&lt;br /&gt;
&lt;br /&gt;
Вывод должен быть таким:&lt;br /&gt;
&lt;br /&gt;
    root@python:~# systemctl status noprodaction.service &lt;br /&gt;
    * noprodaction.service - telegam bot noProdaction&lt;br /&gt;
         Loaded: loaded (/etc/systemd/system/noprodaction.service; enabled; vendor preset: enabled)&lt;br /&gt;
         Active: active (running) since Tue 2023-11-14 11:44:32 MSK; 3h 14min ago&lt;br /&gt;
       Main PID: 173 (python3.11)&lt;br /&gt;
          Tasks: 2 (limit: 96529)&lt;br /&gt;
         Memory: 34.1M&lt;br /&gt;
            CPU: 1.766s&lt;br /&gt;
         CGroup: /system.slice/noprodaction.service&lt;br /&gt;
                 `-173 /usr/bin/python3.11 /opt/Python/Telegram/noProdaction/noprodaction-1/main.py&amp;lt;br&amp;gt;&lt;br /&gt;
    Nov 14 11:44:32 python systemd[1]: Started telegam bot noProdaction.&lt;br /&gt;
&lt;br /&gt;
и у нас при старте сервера вудет работать скрипт.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=NGINXproxyManager&amp;diff=123</id>
		<title>NGINXproxyManager</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=NGINXproxyManager&amp;diff=123"/>
		<updated>2026-08-31T18:21:55Z</updated>

		<summary type="html">&lt;p&gt;Artem: Обновление статьи&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Установка Nginx Proxy Manager в Docker =&lt;br /&gt;
&lt;br /&gt;
‘’‘Nginx Proxy Manager (NPM)’’’ — удобная графическая оболочка для управления реверсивным прокси-сервером Nginx.&lt;br /&gt;
&lt;br /&gt;
С его помощью можно:&lt;br /&gt;
&lt;br /&gt;
* публиковать внутренние веб-сервисы в Интернет;&lt;br /&gt;
* направлять разные домены и поддомены на разные серверы;&lt;br /&gt;
* автоматически получать SSL-сертификаты Let’s Encrypt;&lt;br /&gt;
* управлять HTTPS через веб-интерфейс;&lt;br /&gt;
* создавать перенаправления;&lt;br /&gt;
* ограничивать доступ к отдельным сервисам.&lt;br /&gt;
&lt;br /&gt;
В результате схема работы выглядит примерно так:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                     INTERNET&lt;br /&gt;
                         │&lt;br /&gt;
                  HTTP / HTTPS&lt;br /&gt;
                    80 / 443&lt;br /&gt;
                         │&lt;br /&gt;
                         ▼&lt;br /&gt;
              ┌─────────────────────┐&lt;br /&gt;
              │ Nginx Proxy Manager │&lt;br /&gt;
              │                     │&lt;br /&gt;
              │      Docker         │&lt;br /&gt;
              └──────────┬──────────┘&lt;br /&gt;
                         │&lt;br /&gt;
             ┌───────────┼───────────┐&lt;br /&gt;
             │           │           │&lt;br /&gt;
             ▼           ▼           ▼&lt;br /&gt;
          Web #1      Web #2      Web #3&lt;br /&gt;
        192.168.1.x 192.168.1.x 192.168.1.x&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Требования ==&lt;br /&gt;
&lt;br /&gt;
Для установки потребуется сервер или виртуальная машина с Linux.&lt;br /&gt;
&lt;br /&gt;
В данной инструкции предполагается использование Debian/Ubuntu.&lt;br /&gt;
&lt;br /&gt;
Также необходимо убедиться, что порты:&lt;br /&gt;
&lt;br /&gt;
* ‘’‘80/TCP’’’ — HTTP;&lt;br /&gt;
* ‘’‘443/TCP’’’ — HTTPS;&lt;br /&gt;
* ‘’‘81/TCP’’’ — панель управления Nginx Proxy Manager&lt;br /&gt;
&lt;br /&gt;
не заняты другими сервисами.&lt;br /&gt;
&lt;br /&gt;
Проверить используемые порты можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
ss -tulpn&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Обновление системы ==&lt;br /&gt;
&lt;br /&gt;
Сначала обновляем список пакетов и установленные пакеты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update &amp;amp;&amp;amp; apt upgrade -y&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При необходимости устанавливаем дополнительные сетевые утилиты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt install net-tools curl ca-certificates -y&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Установка Docker ==&lt;br /&gt;
&lt;br /&gt;
Для актуальных установок рекомендуется использовать официальный репозиторий Docker.&lt;br /&gt;
&lt;br /&gt;
Добавляем ключ репозитория:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
install -m 0755 -d /etc/apt/keyrings&lt;br /&gt;
curl -fsSL https://download.docker.com/linux/debian/gpg \&lt;br /&gt;
  -o /etc/apt/keyrings/docker.asc&lt;br /&gt;
chmod a+r /etc/apt/keyrings/docker.asc&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем репозиторий Docker:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cat &amp;gt; /etc/apt/sources.list.d/docker.sources &amp;lt;&amp;lt;EOF&lt;br /&gt;
Types: deb&lt;br /&gt;
URIs: https://download.docker.com/linux/debian&lt;br /&gt;
Suites: $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;quot;$VERSION_CODENAME&amp;quot;)&lt;br /&gt;
Components: stable&lt;br /&gt;
Architectures: $(dpkg --print-architecture)&lt;br /&gt;
Signed-By: /etc/apt/keyrings/docker.asc&lt;br /&gt;
EOF&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обновляем список пакетов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt update&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Устанавливаем Docker Engine и Docker Compose:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем версию Docker:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker --version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
И Docker Compose:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose version&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Проверка Docker ==&lt;br /&gt;
&lt;br /&gt;
Проверяем состояние службы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl status docker&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если Docker не запущен:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl start docker&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем Docker в автозагрузку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
systemctl enable docker&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для дополнительной проверки можно запустить тестовый контейнер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --rm hello-world&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если установка выполнена правильно, Docker загрузит тестовый образ и выведет сообщение об успешном запуске.&lt;br /&gt;
&lt;br /&gt;
== Установка Nginx Proxy Manager ==&lt;br /&gt;
&lt;br /&gt;
Создадим отдельный каталог для Nginx Proxy Manager:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mkdir -p /opt/nginx-proxy-manager&lt;br /&gt;
cd /opt/nginx-proxy-manager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Создаём файл Docker Compose:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
nano docker-compose.yml&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавляем следующую конфигурацию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;yaml&amp;quot;&amp;gt;&lt;br /&gt;
services:&lt;br /&gt;
  app:&lt;br /&gt;
    image: &#039;jc21/nginx-proxy-manager:2.15.1&#039;&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
ports:&lt;br /&gt;
  - &#039;80:80&#039;&lt;br /&gt;
  - &#039;81:81&#039;&lt;br /&gt;
  - &#039;443:443&#039;&lt;br /&gt;
volumes:&lt;br /&gt;
  - ./data:/data&lt;br /&gt;
  - ./letsencrypt:/etc/letsencrypt&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Сохраняем файл:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + O&lt;br /&gt;
Enter&lt;br /&gt;
Ctrl + X&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В данной конфигурации используется встроенная база данных SQLite, поэтому отдельный контейнер MariaDB для обычной установки не требуется.&lt;br /&gt;
&lt;br /&gt;
== Запуск Nginx Proxy Manager ==&lt;br /&gt;
&lt;br /&gt;
Запускаем контейнеры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Проверяем их состояние:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose ps&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Также можно посмотреть непосредственно запущенные Docker-контейнеры:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker ps&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Nginx Proxy Manager должен отображаться со статусом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Up&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первый запуск может занять некоторое время.&lt;br /&gt;
&lt;br /&gt;
При необходимости посмотреть журнал запуска:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose logs -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выход из просмотра журнала:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Ctrl + C&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Вход в панель управления ==&lt;br /&gt;
&lt;br /&gt;
Открываем браузер и переходим по адресу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://IP_СЕРВЕРА:81&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://192.168.1.20:81&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После первого входа необходимо настроить учётную запись администратора согласно интерфейсу текущей версии Nginx Proxy Manager.&lt;br /&gt;
&lt;br /&gt;
‘’‘Обязательно используйте собственный надёжный пароль администратора.’’’&lt;br /&gt;
&lt;br /&gt;
== Назначение портов ==&lt;br /&gt;
&lt;br /&gt;
{| class=“wikitable”&lt;br /&gt;
! Порт&lt;br /&gt;
! Протокол&lt;br /&gt;
&lt;br /&gt;
! Назначение&lt;br /&gt;
&lt;br /&gt;
80&lt;br /&gt;
&lt;br /&gt;
TCP&lt;br /&gt;
&lt;br /&gt;
Входящие HTTP-запросы&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
443&lt;br /&gt;
&lt;br /&gt;
TCP&lt;br /&gt;
&lt;br /&gt;
Входящие HTTPS-запросы&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
81&lt;br /&gt;
&lt;br /&gt;
TCP&lt;br /&gt;
&lt;br /&gt;
Web-интерфейс администратора&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
{{Warning|Порт 81 предназначен для административной панели. Не рекомендуется без необходимости публиковать его напрямую в Интернет. Ограничьте доступ локальной сетью, VPN или правилами межсетевого экрана.}}&lt;br /&gt;
&lt;br /&gt;
== Создание первого Proxy Host ==&lt;br /&gt;
&lt;br /&gt;
После входа в Nginx Proxy Manager открываем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Hosts → Proxy Hosts → Add Proxy Host&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Указываем:&lt;br /&gt;
&lt;br /&gt;
{| class=“wikitable”&lt;br /&gt;
! Параметр&lt;br /&gt;
&lt;br /&gt;
! Пример&lt;br /&gt;
&lt;br /&gt;
Domain Names&lt;br /&gt;
&lt;br /&gt;
wiki.example.com&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Scheme&lt;br /&gt;
&lt;br /&gt;
http&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Forward Hostname / IP&lt;br /&gt;
&lt;br /&gt;
192.168.1.30&lt;br /&gt;
&lt;br /&gt;
-&lt;br /&gt;
&lt;br /&gt;
Forward Port&lt;br /&gt;
&lt;br /&gt;
80&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
После этого Nginx Proxy Manager будет принимать запрос:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
https://wiki.example.com&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и передавать его внутреннему серверу:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
http://192.168.1.30:80&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Схематично:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Пользователь&lt;br /&gt;
     │&lt;br /&gt;
     │ https://wiki.example.com&lt;br /&gt;
     ▼&lt;br /&gt;
┌─────────────────────┐&lt;br /&gt;
│ Nginx Proxy Manager │&lt;br /&gt;
│       :443          │&lt;br /&gt;
└──────────┬──────────┘&lt;br /&gt;
           │&lt;br /&gt;
           │ HTTP&lt;br /&gt;
           ▼&lt;br /&gt;
     192.168.1.30:80&lt;br /&gt;
           │&lt;br /&gt;
           ▼&lt;br /&gt;
       Web-сервис&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Получение SSL-сертификата ==&lt;br /&gt;
&lt;br /&gt;
При создании Proxy Host переходим во вкладку:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SSL&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выбираем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Request a new SSL Certificate&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При необходимости включаем:&lt;br /&gt;
&lt;br /&gt;
* ‘’‘Force SSL’’’ — принудительное перенаправление HTTP → HTTPS;&lt;br /&gt;
* ‘’‘HTTP/2 Support’’’ — поддержку HTTP/2;&lt;br /&gt;
* ‘’‘HSTS’’’ — только если понимаем последствия его использования.&lt;br /&gt;
&lt;br /&gt;
После сохранения Nginx Proxy Manager автоматически запросит сертификат Let’s Encrypt.&lt;br /&gt;
&lt;br /&gt;
Для стандартной HTTP-проверки Let’s Encrypt домен должен указывать на внешний IP сервера, а TCP-порт ‘’‘80’’’ должен быть доступен извне.&lt;br /&gt;
&lt;br /&gt;
== Управление контейнером ==&lt;br /&gt;
&lt;br /&gt;
=== Остановить Nginx Proxy Manager ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/nginx-proxy-manager&lt;br /&gt;
docker compose down&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Запустить ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Перезапустить ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose restart&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Посмотреть журнал ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose logs -f&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Проверить состояние ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose ps&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Обновление Nginx Proxy Manager ==&lt;br /&gt;
&lt;br /&gt;
Перед обновлением рекомендуется сделать резервную копию каталога:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/nginx-proxy-manager&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Затем переходим в каталог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
cd /opt/nginx-proxy-manager&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Загружаем актуальный Docker-образ:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose pull&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пересоздаём контейнер:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose up -d&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
После обновления проверяем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose ps&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и журнал:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker compose logs --tail=100&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Резервное копирование ==&lt;br /&gt;
&lt;br /&gt;
Основные данные установки находятся в каталогах:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/nginx-proxy-manager/data&lt;br /&gt;
/opt/nginx-proxy-manager/letsencrypt&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Для резервного копирования желательно сохранить весь каталог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/opt/nginx-proxy-manager/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В нём находятся конфигурация Nginx Proxy Manager, база данных, SSL-сертификаты и файл Docker Compose.&lt;br /&gt;
&lt;br /&gt;
== Итог ==&lt;br /&gt;
&lt;br /&gt;
После установки получаем централизованный reverse proxy:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    INTERNET&lt;br /&gt;
                        │&lt;br /&gt;
                 ┌──────┴──────┐&lt;br /&gt;
                 │             │&lt;br /&gt;
               :80           :443&lt;br /&gt;
                 │             │&lt;br /&gt;
                 └──────┬──────┘&lt;br /&gt;
                        ▼&lt;br /&gt;
             ┌─────────────────────┐&lt;br /&gt;
             │ Nginx Proxy Manager │&lt;br /&gt;
             │       Docker        │&lt;br /&gt;
             └──────────┬──────────┘&lt;br /&gt;
                        │ LAN&lt;br /&gt;
        ┌───────────────┼───────────────┐&lt;br /&gt;
        ▼               ▼               ▼&lt;br /&gt;
      Wiki            Cloud           Matrix&lt;br /&gt;
  192.168.1.x      192.168.1.x     192.168.1.x&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь новые внутренние веб-сервисы можно публиковать через HTTPS практически полностью из графического интерфейса Nginx Proxy Manager.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=122</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=122"/>
		<updated>2026-08-28T10:53:12Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;padding:20px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align:center; margin-bottom:30px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h1&amp;gt;📚 База знаний&amp;lt;/h1&amp;gt;&lt;br /&gt;
&amp;lt;p&amp;gt;Документация по инфраструктуре, Linux и игровым серверам.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| style=&amp;quot;width:100%; border-spacing:12px;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;width:33%; vertical-align:top; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
=== 🖥️ Инфраструктура ===&lt;br /&gt;
&#039;&#039;Серверы и виртуализация&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Proxmox]]&lt;br /&gt;
* [[PBS]]&lt;br /&gt;
* [[iLO]]&lt;br /&gt;
* [[BrainyCP]]&lt;br /&gt;
* [[Сетевое оборудование]]&lt;br /&gt;
* [[RAMBA Matrix]]&lt;br /&gt;
* [[RAMBA AI Router]]&lt;br /&gt;
* [[Happ-gateway|HAPP Gateway]]&lt;br /&gt;
* [[Kuzya2-0|Телеграм бот Кузя 2.0]]&lt;br /&gt;
&lt;br /&gt;
| style=&amp;quot;width:33%; vertical-align:top; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
=== 🐧 Linux ===&lt;br /&gt;
&#039;&#039;Системное администрирование&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Ubuntu]]&lt;br /&gt;
* [[Debian]]&lt;br /&gt;
* [[Nginx]]&lt;br /&gt;
* [[Docker]]&lt;br /&gt;
* [[Bash]]&lt;br /&gt;
&lt;br /&gt;
| style=&amp;quot;width:33%; vertical-align:top; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
=== 🎮 Игровые серверы ===&lt;br /&gt;
&#039;&#039;Игровая инфраструктура&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* [[Rust]]&lt;br /&gt;
* [[LGSM]]&lt;br /&gt;
* [[SteamCMD]]&lt;br /&gt;
* [[Резервное копирование]]&lt;br /&gt;
* [[Мониторинг]]&lt;br /&gt;
&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top:20px; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ⭐ Избранные статьи ==&lt;br /&gt;
&lt;br /&gt;
* [[Установка Proxmox VE]]&lt;br /&gt;
* [[Настройка Proxmox Backup Server]]&lt;br /&gt;
* [[Настройка BrainyCP]]&lt;br /&gt;
* [[Создание LXC-контейнеров]]&lt;br /&gt;
* [[Настройка Rust-сервера через LGSM]]&lt;br /&gt;
* [[Minecraft_в_2026_году]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top:20px; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🕒 Последние изменения ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:RecentChanges|Посмотреть все последние изменения]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-top:20px; background:#f8f9fa; border:1px solid #c8ccd1; border-radius:8px; padding:15px;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 🔗 Полезные ссылки ==&lt;br /&gt;
&lt;br /&gt;
* [[Special:AllPages|Все статьи]]&lt;br /&gt;
* [[Special:Categories|Все категории]]&lt;br /&gt;
* [[Special:WantedPages|Нужные страницы]]&lt;br /&gt;
* [[Special:Random|🎲 Случайная статья]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Kuzya2-0&amp;diff=121</id>
		<title>Kuzya2-0</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Kuzya2-0&amp;diff=121"/>
		<updated>2026-08-28T10:38:47Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «= Кузя — интеллектуальный администратор Telegram-сообщества =  &amp;#039;&amp;#039;&amp;#039;Кузя&amp;#039;&amp;#039;&amp;#039; — Telegram-бот для администрирования и сопровождения сообщества. Проект развивается от классического административного бота к интеллектуальному помощнику и AI-модератору, способному ана...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Кузя — интеллектуальный администратор Telegram-сообщества =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Кузя&#039;&#039;&#039; — Telegram-бот для администрирования и сопровождения сообщества. Проект развивается от классического административного бота к интеллектуальному помощнику и AI-модератору, способному анализировать происходящее в чате, помогать участникам и администраторам и самостоятельно выявлять нарушения.&lt;br /&gt;
&lt;br /&gt;
Основная задача проекта — не заменить живых администраторов, а снять с них значительную часть рутинной работы и предоставить дополнительные инструменты для управления сообществом.&lt;br /&gt;
&lt;br /&gt;
== Текущее состояние проекта ==&lt;br /&gt;
&lt;br /&gt;
Кузя уже является рабочим Telegram-ботом и используется для выполнения административных и информационных задач.&lt;br /&gt;
&lt;br /&gt;
На данный момент реализованы следующие возможности:&lt;br /&gt;
&lt;br /&gt;
* выдача мута;&lt;br /&gt;
* снятие мута;&lt;br /&gt;
* временный и постоянный бан;&lt;br /&gt;
* система предупреждений;&lt;br /&gt;
* указание причины нарушения;&lt;br /&gt;
* хранение истории предупреждений;&lt;br /&gt;
* отдельный список администраторов Кузи;&lt;br /&gt;
* приветствие новых участников;&lt;br /&gt;
* публикация информационных сообщений;&lt;br /&gt;
* вывод правил сообщества;&lt;br /&gt;
* публикация ссылок;&lt;br /&gt;
* приглашения;&lt;br /&gt;
* информация о поддержке проекта;&lt;br /&gt;
* взаимодействие с публикациями Telegram-канала;&lt;br /&gt;
* автоматическая публикация информационного сообщения под новым видео;&lt;br /&gt;
* хранение истории сообщений Telegram-чата;&lt;br /&gt;
* изменение ряда настроек и текстов через команды администратора;&lt;br /&gt;
* базовые функции AI-ассистента.&lt;br /&gt;
&lt;br /&gt;
== База данных сообщества ==&lt;br /&gt;
&lt;br /&gt;
Кузя работает с MySQL и ведёт собственную историю чата.&lt;br /&gt;
&lt;br /&gt;
На август 2026 года в базе сохранено около:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;497 000 сообщений.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для сообщений сохраняются, в частности:&lt;br /&gt;
&lt;br /&gt;
* дата и время;&lt;br /&gt;
* Telegram ID пользователя;&lt;br /&gt;
* username;&lt;br /&gt;
* отображаемое имя;&lt;br /&gt;
* текст сообщения;&lt;br /&gt;
* Telegram message ID.&lt;br /&gt;
&lt;br /&gt;
Отдельно существует база предупреждений.&lt;br /&gt;
&lt;br /&gt;
В ней сохраняются:&lt;br /&gt;
&lt;br /&gt;
* пользователь;&lt;br /&gt;
* сообщение, за которое выдано предупреждение;&lt;br /&gt;
* причина;&lt;br /&gt;
* номер предупреждения;&lt;br /&gt;
* администратор, принявший решение;&lt;br /&gt;
* дата и время.&lt;br /&gt;
&lt;br /&gt;
Большинство предупреждений связано с исходным сообщением через &#039;&#039;&#039;message_id&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Таким образом, за время существования Кузи администраторами фактически был создан первоначальный набор вручную размеченных примеров нарушений.&lt;br /&gt;
&lt;br /&gt;
Эти данные в дальнейшем могут использоваться для разработки интеллектуальной системы модерации.&lt;br /&gt;
&lt;br /&gt;
== Концепция дальнейшего развития ==&lt;br /&gt;
&lt;br /&gt;
В перспективе Кузя должен состоять из трёх основных подсистем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                    КУЗЯ&lt;br /&gt;
                      |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
        |             |             |&lt;br /&gt;
        v             v             v&lt;br /&gt;
 Telegram Admin   AI Assistant    Guardian&lt;br /&gt;
        |             |             |&lt;br /&gt;
   mute / ban       диалог       модерация&lt;br /&gt;
   warnings         память       антиспам&lt;br /&gt;
   rules            поиск       конфликты&lt;br /&gt;
   channel           RAG         репутация&lt;br /&gt;
        |             |             |&lt;br /&gt;
        +-------------+-------------+&lt;br /&gt;
                      |&lt;br /&gt;
                      v&lt;br /&gt;
                  RAMBA AI&lt;br /&gt;
              Local AI Router&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Локальный искусственный интеллект ==&lt;br /&gt;
&lt;br /&gt;
Основной AI Кузи планируется сделать &#039;&#039;&#039;локальным&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Для обработки запросов используется инфраструктура RAMBA AI с несколькими локальными нейронными моделями.&lt;br /&gt;
&lt;br /&gt;
Архитектура предусматривает три специализированные модели, работающие на локальном сервере с NVIDIA GeForce GTX 1080.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
  Кузя&lt;br /&gt;
    |&lt;br /&gt;
    v&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 1&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 2&lt;br /&gt;
    |&lt;br /&gt;
    +------ Model 3&lt;br /&gt;
    |&lt;br /&gt;
    +------ OpenAI API&lt;br /&gt;
            дополнительный уровень&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
AI Router определяет, какая модель лучше подходит для конкретной задачи.&lt;br /&gt;
&lt;br /&gt;
OpenAI API при этом не является основным интеллектом Кузи. Он рассматривается как дополнительный инструмент для отдельных сложных задач и сценариев, в которых возможностей локальных моделей недостаточно.&lt;br /&gt;
&lt;br /&gt;
Это также позволяет не передавать всю историю сообщества внешним AI-сервисам.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.0 — новая архитектура ==&lt;br /&gt;
&lt;br /&gt;
Первым этапом развития станет создание &#039;&#039;&#039;Kuzya 2.0&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Главный принцип:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Сначала переносим все существующие возможности без потери функциональности, затем добавляем AI.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Текущая рабочая версия сохраняется как:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kuzya Legacy Stable&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Новая версия разрабатывается отдельно.&lt;br /&gt;
&lt;br /&gt;
В Kuzya 2.0 существующий монолитный код планируется разделить на независимые компоненты:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
kuzya/&lt;br /&gt;
|&lt;br /&gt;
+-- bot/&lt;br /&gt;
|   +-- moderation/&lt;br /&gt;
|   +-- commands/&lt;br /&gt;
|   +-- channel/&lt;br /&gt;
|   +-- users/&lt;br /&gt;
|   +-- handlers/&lt;br /&gt;
|&lt;br /&gt;
+-- database/&lt;br /&gt;
|   +-- messages&lt;br /&gt;
|   +-- warnings&lt;br /&gt;
|   +-- admins&lt;br /&gt;
|   +-- settings&lt;br /&gt;
|&lt;br /&gt;
+-- ai/&lt;br /&gt;
|   +-- assistant&lt;br /&gt;
|   +-- moderation&lt;br /&gt;
|   +-- context&lt;br /&gt;
|   +-- memory&lt;br /&gt;
|&lt;br /&gt;
+-- services/&lt;br /&gt;
|&lt;br /&gt;
+-- config/&lt;br /&gt;
|&lt;br /&gt;
+-- main.py&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволит развивать отдельные возможности Кузи независимо друг от друга.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.1 — развитие базы данных ==&lt;br /&gt;
&lt;br /&gt;
Существующая MySQL-база сохраняется.&lt;br /&gt;
&lt;br /&gt;
История почти из полумиллиона сообщений является ценным архивом и не должна изменяться или удаляться в процессе модернизации.&lt;br /&gt;
&lt;br /&gt;
Для новой версии предполагается постепенно перейти к единой структуре данных:&lt;br /&gt;
&lt;br /&gt;
* chats;&lt;br /&gt;
* users;&lt;br /&gt;
* messages;&lt;br /&gt;
* warnings;&lt;br /&gt;
* moderation_actions;&lt;br /&gt;
* admins;&lt;br /&gt;
* chat_settings.&lt;br /&gt;
&lt;br /&gt;
Каждое административное действие сможет дополнительно содержать источник решения:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;human&#039;&#039;&#039; — решение администратора;&lt;br /&gt;
* &#039;&#039;&#039;ai&#039;&#039;&#039; — решение AI;&lt;br /&gt;
* &#039;&#039;&#039;rule&#039;&#039;&#039; — автоматическое правило.&lt;br /&gt;
&lt;br /&gt;
Это позволит впоследствии анализировать качество работы AI.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.2 — AI Router ==&lt;br /&gt;
&lt;br /&gt;
Кузя подключается к RAMBA AI Router.&lt;br /&gt;
&lt;br /&gt;
Telegram-бот при этом не запускает и не управляет моделями непосредственно.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя&lt;br /&gt;
 |&lt;br /&gt;
 | запрос&lt;br /&gt;
 v&lt;br /&gt;
RAMBA AI Router&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; разговорная модель&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; модель сложных задач&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; специализированная модель&lt;br /&gt;
 |&lt;br /&gt;
 +--&amp;gt; внешний AI (при необходимости)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это позволит менять модели независимо от Telegram-бота и использовать одну AI-инфраструктуру для нескольких проектов.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.3 — полноценный AI-ассистент ==&lt;br /&gt;
&lt;br /&gt;
Кузя сможет поддерживать обычный разговор.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, что сегодня обсуждали?&lt;br /&gt;
&lt;br /&gt;
Кузя, объясни подробнее.&lt;br /&gt;
&lt;br /&gt;
Кузя, какие правила относятся к публикации ссылок?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
При ответе AI сможет учитывать:&lt;br /&gt;
&lt;br /&gt;
* текущий вопрос;&lt;br /&gt;
* предыдущие сообщения разговора;&lt;br /&gt;
* контекст Telegram-чата;&lt;br /&gt;
* правила сообщества;&lt;br /&gt;
* настройки конкретного чата.&lt;br /&gt;
&lt;br /&gt;
Таким образом появляется краткосрочная память.&lt;br /&gt;
&lt;br /&gt;
== Kuzya 2.4 — долговременная память ==&lt;br /&gt;
&lt;br /&gt;
История сообщений не должна целиком передаваться нейронной модели.&lt;br /&gt;
&lt;br /&gt;
Для этого предполагается использовать технологию RAG.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
История MySQL&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
  индексация&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
 Vector DB&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
поиск нужной истории&lt;br /&gt;
      |&lt;br /&gt;
      v&lt;br /&gt;
     AI&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например, участник сможет спросить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, мы раньше обсуждали эту проблему?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кузя найдёт связанные старые обсуждения и использует их при формировании ответа.&lt;br /&gt;
&lt;br /&gt;
Таким образом накопленная история чата становится долговременной памятью сообщества.&lt;br /&gt;
&lt;br /&gt;
= Kuzya Guardian =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kuzya Guardian&#039;&#039;&#039; — ключевое направление дальнейшего развития проекта.&lt;br /&gt;
&lt;br /&gt;
Это интеллектуальная система модерации Telegram-чата.&lt;br /&gt;
&lt;br /&gt;
== Анализ сообщений ==&lt;br /&gt;
&lt;br /&gt;
Новые сообщения смогут проходить через несколько уровней проверки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Telegram message&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
простые правила&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
AI-анализ&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
оценка риска&lt;br /&gt;
       |&lt;br /&gt;
       v&lt;br /&gt;
решение&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
AI сможет определять, например:&lt;br /&gt;
&lt;br /&gt;
* спам;&lt;br /&gt;
* флуд;&lt;br /&gt;
* нежелательную рекламу;&lt;br /&gt;
* оскорбления;&lt;br /&gt;
* провокации;&lt;br /&gt;
* нарушения правил сообщества;&lt;br /&gt;
* эскалацию конфликтов;&lt;br /&gt;
* повторные нарушения.&lt;br /&gt;
&lt;br /&gt;
При этом анализироваться сможет не только одно сообщение, но и контекст разговора.&lt;br /&gt;
&lt;br /&gt;
== Shadow Mode ==&lt;br /&gt;
&lt;br /&gt;
На первом этапе AI &#039;&#039;&#039;не получает право самостоятельно наказывать пользователей&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Кузя работает в теневом режиме — Shadow Mode.&lt;br /&gt;
&lt;br /&gt;
При обнаружении возможного нарушения в административный чат поступает сообщение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя обнаружил возможное нарушение.&lt;br /&gt;
&lt;br /&gt;
Пользователь: @username&lt;br /&gt;
Тип: оскорбление&lt;br /&gt;
Уверенность: 87 %&lt;br /&gt;
&lt;br /&gt;
Предлагаемое действие:&lt;br /&gt;
Предупреждение&lt;br /&gt;
&lt;br /&gt;
[Нарушение]&lt;br /&gt;
[Не нарушение]&lt;br /&gt;
[Мут]&lt;br /&gt;
[Бан]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Окончательное решение принимает человек.&lt;br /&gt;
&lt;br /&gt;
Решение администратора сохраняется в базе.&lt;br /&gt;
&lt;br /&gt;
== Обучение на решениях администраторов ==&lt;br /&gt;
&lt;br /&gt;
Shadow Mode одновременно позволяет собирать новый качественный набор данных.&lt;br /&gt;
&lt;br /&gt;
Для каждого случая можно сохранять:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
сообщение&lt;br /&gt;
+&lt;br /&gt;
контекст&lt;br /&gt;
+&lt;br /&gt;
решение AI&lt;br /&gt;
+&lt;br /&gt;
решение администратора&lt;br /&gt;
+&lt;br /&gt;
причина&lt;br /&gt;
+&lt;br /&gt;
применённое действие&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом Кузя постепенно получает примеры того, &#039;&#039;&#039;как именно администрация данного сообщества трактует его правила&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Существующая база предупреждений также может использоваться как первоначальный набор размеченных примеров.&lt;br /&gt;
&lt;br /&gt;
== Полуавтоматическая модерация ==&lt;br /&gt;
&lt;br /&gt;
После накопления статистики отдельные очевидные нарушения можно будет обрабатывать автоматически.&lt;br /&gt;
&lt;br /&gt;
Примерная модель:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
низкая уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; никаких действий&lt;br /&gt;
&lt;br /&gt;
средняя уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; запись в журнал&lt;br /&gt;
&lt;br /&gt;
высокая уверенность&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; сообщение администраторам&lt;br /&gt;
&lt;br /&gt;
очень высокая уверенность&lt;br /&gt;
+ безопасная категория&lt;br /&gt;
        |&lt;br /&gt;
        +--&amp;gt; автоматическое действие&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Порог автоматизации будет зависеть от типа нарушения.&lt;br /&gt;
&lt;br /&gt;
Например, очевидный массовый спам можно обрабатывать автоматически, тогда как спорные конфликты между людьми должны передаваться администратору.&lt;br /&gt;
&lt;br /&gt;
== Репутация пользователей ==&lt;br /&gt;
&lt;br /&gt;
В перспективе Guardian сможет учитывать историю поведения пользователя.&lt;br /&gt;
&lt;br /&gt;
Учитываются:&lt;br /&gt;
&lt;br /&gt;
* предупреждения;&lt;br /&gt;
* муты;&lt;br /&gt;
* баны;&lt;br /&gt;
* повторные нарушения;&lt;br /&gt;
* частота конфликтов;&lt;br /&gt;
* длительные периоды без нарушений.&lt;br /&gt;
&lt;br /&gt;
Репутация является внутренним параметром системы и не обязательно должна отображаться участникам.&lt;br /&gt;
&lt;br /&gt;
Она используется только как дополнительный контекст для принятия решения.&lt;br /&gt;
&lt;br /&gt;
== Анализ конфликтов ==&lt;br /&gt;
&lt;br /&gt;
Одна из перспективных функций — обнаружение развивающегося конфликта.&lt;br /&gt;
&lt;br /&gt;
Кузя анализирует последовательность сообщений нескольких участников и может определить постепенную эскалацию.&lt;br /&gt;
&lt;br /&gt;
Вместо немедленного наказания бот сначала сможет предложить участникам прекратить спор.&lt;br /&gt;
&lt;br /&gt;
Если конфликт продолжается, информация передаётся администраторам.&lt;br /&gt;
&lt;br /&gt;
Таким образом система должна оценивать не только отдельные слова, но и развитие разговора.&lt;br /&gt;
&lt;br /&gt;
= Аналитика сообщества =&lt;br /&gt;
&lt;br /&gt;
Кузя сможет формировать статистику Telegram-чата.&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Статистика за сутки&lt;br /&gt;
&lt;br /&gt;
Сообщений: 2351&lt;br /&gt;
Активных участников: 187&lt;br /&gt;
Новых участников: 14&lt;br /&gt;
&lt;br /&gt;
Предупреждений: 3&lt;br /&gt;
Мутов: 1&lt;br /&gt;
Удалено спама: 9&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Дополнительно AI сможет определять основные темы обсуждения.&lt;br /&gt;
&lt;br /&gt;
== Ежедневный дайджест ==&lt;br /&gt;
&lt;br /&gt;
В перспективе возможно автоматическое формирование краткого отчёта:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Что произошло сегодня&lt;br /&gt;
&lt;br /&gt;
Обсудили:&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Важные ссылки:&lt;br /&gt;
* ...&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
Модерация:&lt;br /&gt;
* 2 предупреждения&lt;br /&gt;
* 1 мут&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это особенно полезно участникам и администраторам, которые не могли постоянно следить за чатом.&lt;br /&gt;
&lt;br /&gt;
= Знание правил сообщества =&lt;br /&gt;
&lt;br /&gt;
Правила конкретного сообщества становятся частью базы знаний Кузи.&lt;br /&gt;
&lt;br /&gt;
Участник сможет спросить:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Кузя, можно здесь публиковать ссылку на YouTube?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ответ будет основан именно на действующих правилах данного сообщества.&lt;br /&gt;
&lt;br /&gt;
Кузя также сможет объяснять административные решения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Почему сообщение удалено?&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Сообщение нарушает пункт 2 правил:&lt;br /&gt;
ссылка опубликована без необходимого описания.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Этапы разработки =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Версия&lt;br /&gt;
! Основная задача&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Legacy&#039;&#039;&#039;&lt;br /&gt;
| Текущий рабочий Кузя&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.0&#039;&#039;&#039;&lt;br /&gt;
| Новая архитектура и полный перенос существующих функций&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.1&#039;&#039;&#039;&lt;br /&gt;
| Новая структура MySQL и сохранение существующей истории&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.2&#039;&#039;&#039;&lt;br /&gt;
| Интеграция с RAMBA AI Router&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.3&#039;&#039;&#039;&lt;br /&gt;
| Полноценные AI-диалоги и краткосрочный контекст&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2.4&#039;&#039;&#039;&lt;br /&gt;
| RAG и долговременная память по истории Telegram-чата&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.0&#039;&#039;&#039;&lt;br /&gt;
| Kuzya Guardian&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.1&#039;&#039;&#039;&lt;br /&gt;
| Shadow Mode&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.2&#039;&#039;&#039;&lt;br /&gt;
| Полуавтоматическая модерация&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.3&#039;&#039;&#039;&lt;br /&gt;
| Репутационная система&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;3.4&#039;&#039;&#039;&lt;br /&gt;
| Анализ конфликтов&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.0&#039;&#039;&#039;&lt;br /&gt;
| Аналитика сообщества и дайджесты&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;4.1&#039;&#039;&#039;&lt;br /&gt;
| Глубокая интеграция AI с правилами сообщества&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;5.0&#039;&#039;&#039;&lt;br /&gt;
| Полноценный интеллектуальный Community Guardian&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Принципы проекта =&lt;br /&gt;
&lt;br /&gt;
При разработке Кузи предлагается придерживаться нескольких основных принципов.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Существующие функции не должны быть потеряны.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Новая версия сначала достигает функционального паритета с текущей и только затем заменяет её.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Решение человека важнее решения AI.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Администратор всегда должен иметь возможность отменить или изменить решение системы.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Автоматизация вводится постепенно.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Сначала наблюдение, затем рекомендации и только после проверки качества — автоматические действия.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. История сообщества является ценным активом.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Существующая MySQL-база сохраняется и используется для построения памяти и системы модерации.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Основной AI работает локально.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Локальные модели являются основой интеллектуальных функций Кузи. Внешние AI API используются только как дополнительный инструмент.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;6. Кузя остаётся специализированным ботом.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Его основная область ответственности — Telegram-сообщество.&lt;br /&gt;
&lt;br /&gt;
Управление серверами, Proxmox, GitLab, Matrix и другой инфраструктурой RAMBA выносится в отдельный RAMBA Bot.&lt;br /&gt;
&lt;br /&gt;
= Конечная цель =&lt;br /&gt;
&lt;br /&gt;
Конечная цель проекта — превратить Кузю из набора административных Telegram-команд в полноценного интеллектуального помощника сообщества:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                 КУЗЯ&lt;br /&gt;
                   |&lt;br /&gt;
     +-------------+-------------+&lt;br /&gt;
     |             |             |&lt;br /&gt;
     v             v             v&lt;br /&gt;
Администратор  AI-ассистент    Guardian&lt;br /&gt;
     |             |             |&lt;br /&gt;
 команды          диалог       модерация&lt;br /&gt;
 правила          память       антиспам&lt;br /&gt;
 warnings         RAG          конфликты&lt;br /&gt;
 канал            поиск       репутация&lt;br /&gt;
     |             |             |&lt;br /&gt;
     +-------------+-------------+&lt;br /&gt;
                   |&lt;br /&gt;
                   v&lt;br /&gt;
               RAMBA AI&lt;br /&gt;
            Local AI Router&lt;br /&gt;
               GTX 1080&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кузя должен не просто выполнять команды администратора, а понимать происходящее в сообществе, помогать его участникам, сохранять накопленные знания и поддерживать порядок, оставляя окончательный контроль за администрацией.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=60</id>
		<title>Gitignore</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=60"/>
		<updated>2023-04-15T18:32:07Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Python.gitignore ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ссылка на [https://github.com/github/gitignore/blob/main/Python.gitignore гитхаб]&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore .gitignore file тут]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=59</id>
		<title>Gitignore</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=59"/>
		<updated>2023-04-15T18:30:20Z</updated>

		<summary type="html">&lt;p&gt;Artem: Содержимое страницы заменено на «== Python.gitignore ==  &amp;#039;&amp;#039;&amp;#039;[https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore .gitignore file тут]&amp;#039;&amp;#039;&amp;#039;»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Python.gitignore ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore .gitignore file тут]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=58</id>
		<title>Gitignore</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Gitignore&amp;diff=58"/>
		<updated>2023-04-15T18:16:25Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class  # C extensions *.so  # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST  # PyInstaller #  Usually these files are written by a python script from a template #  before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *....»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Byte-compiled / optimized / DLL files&lt;br /&gt;
__pycache__/&lt;br /&gt;
*.py[cod]&lt;br /&gt;
*$py.class&lt;br /&gt;
&lt;br /&gt;
# C extensions&lt;br /&gt;
*.so&lt;br /&gt;
&lt;br /&gt;
# Distribution / packaging&lt;br /&gt;
.Python&lt;br /&gt;
build/&lt;br /&gt;
develop-eggs/&lt;br /&gt;
dist/&lt;br /&gt;
downloads/&lt;br /&gt;
eggs/&lt;br /&gt;
.eggs/&lt;br /&gt;
lib/&lt;br /&gt;
lib64/&lt;br /&gt;
parts/&lt;br /&gt;
sdist/&lt;br /&gt;
var/&lt;br /&gt;
wheels/&lt;br /&gt;
share/python-wheels/&lt;br /&gt;
*.egg-info/&lt;br /&gt;
.installed.cfg&lt;br /&gt;
*.egg&lt;br /&gt;
MANIFEST&lt;br /&gt;
&lt;br /&gt;
# PyInstaller&lt;br /&gt;
#  Usually these files are written by a python script from a template&lt;br /&gt;
#  before PyInstaller builds the exe, so as to inject date/other infos into it.&lt;br /&gt;
*.manifest&lt;br /&gt;
*.spec&lt;br /&gt;
&lt;br /&gt;
# Installer logs&lt;br /&gt;
pip-log.txt&lt;br /&gt;
pip-delete-this-directory.txt&lt;br /&gt;
&lt;br /&gt;
# Unit test / coverage reports&lt;br /&gt;
htmlcov/&lt;br /&gt;
.tox/&lt;br /&gt;
.nox/&lt;br /&gt;
.coverage&lt;br /&gt;
.coverage.*&lt;br /&gt;
.cache&lt;br /&gt;
nosetests.xml&lt;br /&gt;
coverage.xml&lt;br /&gt;
*.cover&lt;br /&gt;
*.py,cover&lt;br /&gt;
.hypothesis/&lt;br /&gt;
.pytest_cache/&lt;br /&gt;
cover/&lt;br /&gt;
&lt;br /&gt;
# Translations&lt;br /&gt;
*.mo&lt;br /&gt;
*.pot&lt;br /&gt;
&lt;br /&gt;
# Django stuff:&lt;br /&gt;
*.log&lt;br /&gt;
local_settings.py&lt;br /&gt;
db.sqlite3&lt;br /&gt;
db.sqlite3-journal&lt;br /&gt;
&lt;br /&gt;
# Flask stuff:&lt;br /&gt;
instance/&lt;br /&gt;
.webassets-cache&lt;br /&gt;
&lt;br /&gt;
# Scrapy stuff:&lt;br /&gt;
.scrapy&lt;br /&gt;
&lt;br /&gt;
# Sphinx documentation&lt;br /&gt;
docs/_build/&lt;br /&gt;
&lt;br /&gt;
# PyBuilder&lt;br /&gt;
.pybuilder/&lt;br /&gt;
target/&lt;br /&gt;
&lt;br /&gt;
# Jupyter Notebook&lt;br /&gt;
.ipynb_checkpoints&lt;br /&gt;
&lt;br /&gt;
# IPython&lt;br /&gt;
profile_default/&lt;br /&gt;
ipython_config.py&lt;br /&gt;
&lt;br /&gt;
# pyenv&lt;br /&gt;
#   For a library or package, you might want to ignore these files since the code is&lt;br /&gt;
#   intended to run in multiple environments; otherwise, check them in:&lt;br /&gt;
# .python-version&lt;br /&gt;
&lt;br /&gt;
# pipenv&lt;br /&gt;
#   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.&lt;br /&gt;
#   However, in case of collaboration, if having platform-specific dependencies or dependencies&lt;br /&gt;
#   having no cross-platform support, pipenv may install dependencies that don&#039;t work, or not&lt;br /&gt;
#   install all needed dependencies.&lt;br /&gt;
#Pipfile.lock&lt;br /&gt;
&lt;br /&gt;
# poetry&lt;br /&gt;
#   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.&lt;br /&gt;
#   This is especially recommended for binary packages to ensure reproducibility, and is more&lt;br /&gt;
#   commonly ignored for libraries.&lt;br /&gt;
#   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control&lt;br /&gt;
#poetry.lock&lt;br /&gt;
&lt;br /&gt;
# pdm&lt;br /&gt;
#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.&lt;br /&gt;
#pdm.lock&lt;br /&gt;
#   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it&lt;br /&gt;
#   in version control.&lt;br /&gt;
#   https://pdm.fming.dev/#use-with-ide&lt;br /&gt;
.pdm.toml&lt;br /&gt;
&lt;br /&gt;
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm&lt;br /&gt;
__pypackages__/&lt;br /&gt;
&lt;br /&gt;
# Celery stuff&lt;br /&gt;
celerybeat-schedule&lt;br /&gt;
celerybeat.pid&lt;br /&gt;
&lt;br /&gt;
# SageMath parsed files&lt;br /&gt;
*.sage.py&lt;br /&gt;
&lt;br /&gt;
# Environments&lt;br /&gt;
.env&lt;br /&gt;
.venv&lt;br /&gt;
env/&lt;br /&gt;
venv/&lt;br /&gt;
ENV/&lt;br /&gt;
env.bak/&lt;br /&gt;
venv.bak/&lt;br /&gt;
&lt;br /&gt;
# Spyder project settings&lt;br /&gt;
.spyderproject&lt;br /&gt;
.spyproject&lt;br /&gt;
&lt;br /&gt;
# Rope project settings&lt;br /&gt;
.ropeproject&lt;br /&gt;
&lt;br /&gt;
# mkdocs documentation&lt;br /&gt;
/site&lt;br /&gt;
&lt;br /&gt;
# mypy&lt;br /&gt;
.mypy_cache/&lt;br /&gt;
.dmypy.json&lt;br /&gt;
dmypy.json&lt;br /&gt;
&lt;br /&gt;
# Pyre type checker&lt;br /&gt;
.pyre/&lt;br /&gt;
&lt;br /&gt;
# pytype static type analyzer&lt;br /&gt;
.pytype/&lt;br /&gt;
&lt;br /&gt;
# Cython debug symbols&lt;br /&gt;
cython_debug/&lt;br /&gt;
&lt;br /&gt;
# PyCharm&lt;br /&gt;
#  JetBrains specific template is maintained in a separate JetBrains.gitignore that can&lt;br /&gt;
#  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore&lt;br /&gt;
#  and can be added to the global gitignore or merged into this file.  For a more nuclear&lt;br /&gt;
#  option (not recommended) you can uncomment the following to ignore the entire idea folder.&lt;br /&gt;
#.idea/&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=VENV&amp;diff=57</id>
		<title>VENV</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=VENV&amp;diff=57"/>
		<updated>2023-04-15T18:03:00Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Для создания нового виртуального окружения в проекте:&lt;br /&gt;
&lt;br /&gt;
python3 -m venv имя_вирт_окружения&lt;br /&gt;
&lt;br /&gt;
Запуск VENV&lt;br /&gt;
&lt;br /&gt;
Windows - .\env\Scripts\activate&lt;br /&gt;
&lt;br /&gt;
Linux/MacOS - source venv/bin/activate&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=56</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=56"/>
		<updated>2023-04-15T08:00:10Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://wiki.ramba-art.ru/NGINXproxyManager &#039;&#039;&#039;Поднимаем NGINXproxyManager&#039;&#039;&#039;] &lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/VENV &#039;&#039;&#039;Кратко о VENV&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_requirements_txt &#039;&#039;&#039;Как создать requirements txt&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_Ubuntu_%D0%B8%D0%BB%D0%B8_UBUNTU_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC &#039;&#039;&#039;UBUNTU на русский&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04 &#039;&#039;&#039;Как сделать сервер Minecraft на Ubuntu 20 04&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_root_%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%82%D1%8C%D1%81%D1%8F_%D0%BF%D0%BE_ssh &#039;&#039;&#039;Разрешить пользователю root подключаться по ssh&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9E%D1%82%D0%BA%D0%BB%D1%8E%D1%87%D0%B8%D1%82_%D0%BF%D0%B5%D1%80%D0%B5%D1%85%D0%BE%D0%B4_%D0%B2_%D1%81%D0%BE%D0%BD_%D0%B8%D0%BB%D0%B8_%D0%B3%D0%B8%D0%B1%D0%B5%D1%80%D0%BD%D0%B0%D1%86%D0%B8%D1%8E_%D0%BF%D1%80%D0%B8_%D0%B7%D0%B0%D0%BA%D1%80%D1%8B%D1%82%D0%B8%D0%B8_%D0%BA%D1%80%D1%8B%D1%88%D0%BA%D0%B8_%D0%BD%D0%BE%D1%83%D1%82%D0%B0_%D0%BF%D0%BE%D0%B4_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5%D0%BC_linux &#039;&#039;&#039;Отключить ждущий режим и гибернацию в Ubuntu&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%94%D0%BE%D0%B1%D0%B0%D0%B2%D0%B8%D1%82%D1%8C_proxy_%D0%B2_ubuntu&#039;&#039;&#039;Добавить proxy в ubuntu&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;[https://wiki.ramba-art.ru/Unit%20for%20tg%20bot Unit for tg bot]&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=55</id>
		<title>Unit for tg bot</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=Unit_for_tg_bot&amp;diff=55"/>
		<updated>2023-04-12T17:05:37Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «         [Unit]     Description=telegam bot OmArtVal     After=network.target      [Service]     User=root     Nice=1     KillMode=process     SuccessExitStatus=0 1     ProtectHome=true     ProtectSystem=full     PrivateDevices=true     NoNewPrivileges=true     WorkingDirectory=/opt/Python/Telegram/noProdaction     ExecStart=/opt/Python/Telegram/start/noProdaction.sh     Restart=always      [Install]     WantedBy=multi-user.target»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;    &lt;br /&gt;
    [Unit]&lt;br /&gt;
    Description=telegam bot OmArtVal&lt;br /&gt;
    After=network.target&lt;br /&gt;
&lt;br /&gt;
    [Service]&lt;br /&gt;
    User=root&lt;br /&gt;
    Nice=1&lt;br /&gt;
    KillMode=process&lt;br /&gt;
    SuccessExitStatus=0 1&lt;br /&gt;
    ProtectHome=true&lt;br /&gt;
    ProtectSystem=full&lt;br /&gt;
    PrivateDevices=true&lt;br /&gt;
    NoNewPrivileges=true&lt;br /&gt;
    WorkingDirectory=/opt/Python/Telegram/noProdaction&lt;br /&gt;
    ExecStart=/opt/Python/Telegram/start/noProdaction.sh&lt;br /&gt;
    Restart=always&lt;br /&gt;
&lt;br /&gt;
    [Install]&lt;br /&gt;
    WantedBy=multi-user.target&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=48</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=48"/>
		<updated>2023-03-27T16:35:19Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://wiki.ramba-art.ru/NGINXproxyManager &#039;&#039;&#039;Поднимаем NGINXproxyManager&#039;&#039;&#039;] &lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/VENV &#039;&#039;&#039;Кратко о VENV&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_requirements_txt &#039;&#039;&#039;Как создать requirements txt&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_Ubuntu_%D0%B8%D0%BB%D0%B8_UBUNTU_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC &#039;&#039;&#039;UBUNTU на русский&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04 &#039;&#039;&#039;Как сделать сервер Minecraft на Ubuntu 20 04&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_root_%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%82%D1%8C%D1%81%D1%8F_%D0%BF%D0%BE_ssh &#039;&#039;&#039;Разрешить пользователю root подключаться по ssh&#039;&#039;&#039;]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_root_%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%82%D1%8C%D1%81%D1%8F_%D0%BF%D0%BE_ssh&amp;diff=47</id>
		<title>Разрешить пользователю root подключаться по ssh</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%A0%D0%B0%D0%B7%D1%80%D0%B5%D1%88%D0%B8%D1%82%D1%8C_%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8E_root_%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B0%D1%82%D1%8C%D1%81%D1%8F_%D0%BF%D0%BE_ssh&amp;diff=47"/>
		<updated>2023-03-27T16:34:18Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «разрешить подключение по &amp;#039;&amp;#039;&amp;#039;рут &amp;#039;&amp;#039;&amp;#039; Используя команду:      &amp;#039;&amp;#039;&amp;#039;sudo sed -i &amp;#039;s/#PermitRootLogin prohibit-password/PermitRootLogin yes/&amp;#039; /etc/ssh/sshd_config&amp;#039;&amp;#039;&amp;#039;  Или лезем в фаил &amp;#039;&amp;#039;&amp;#039;sshd_config&amp;#039;&amp;#039;&amp;#039; находящийся в каталоге &amp;#039;&amp;#039;&amp;#039;etc&amp;#039;&amp;#039;&amp;#039; потом &amp;#039;&amp;#039;&amp;#039;ssh&amp;#039;&amp;#039;&amp;#039;     &amp;#039;&amp;#039;&amp;#039;nano /etc/ssh/sshd_config&amp;#039;&amp;#039;&amp;#039;  убираем комент (&amp;#039;&amp;#039;&amp;#039;#&amp;#039;&amp;#039;&amp;#039;) в строчке &amp;#039;&amp;#039;&amp;#039;PermitRootLogin&amp;#039;&amp;#039;&amp;#039; и ставим знач...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;разрешить подключение по &#039;&#039;&#039;рут&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
Используя команду:&lt;br /&gt;
&lt;br /&gt;
    &#039;&#039;&#039;sudo sed -i &#039;s/#PermitRootLogin prohibit-password/PermitRootLogin yes/&#039; /etc/ssh/sshd_config&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Или лезем в фаил &#039;&#039;&#039;sshd_config&#039;&#039;&#039; находящийся в каталоге &#039;&#039;&#039;etc&#039;&#039;&#039; потом &#039;&#039;&#039;ssh&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
   &#039;&#039;&#039;nano /etc/ssh/sshd_config&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
убираем комент (&#039;&#039;&#039;#&#039;&#039;&#039;) в строчке &#039;&#039;&#039;PermitRootLogin&#039;&#039;&#039; и ставим значение &#039;&#039;&#039;&#039;&#039;yes&#039;&#039;&#039;&#039;&#039;, а также ищем строчку &#039;&#039;&#039;PermitRootLogin&#039;&#039;&#039; и устанавливаем значение &#039;&#039;&#039;&#039;&#039;prohibit-password&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ВАЖНО!!!!! ЛОГИНИТСЯ ПОД РУТ - НЕБЕЗОПАСНО!!!!! ОПАСТНО!!!!!&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=46</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=46"/>
		<updated>2023-03-25T20:50:39Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://wiki.ramba-art.ru/NGINXproxyManager &#039;&#039;&#039;Поднимаем NGINXproxyManager&#039;&#039;&#039;] &lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/VENV &#039;&#039;&#039;Кратко о VENV&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_requirements_txt &#039;&#039;&#039;Как создать requirements txt&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_Ubuntu_%D0%B8%D0%BB%D0%B8_UBUNTU_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC &#039;&#039;&#039;UBUNTU на русский&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04 &#039;&#039;&#039;Как сделать сервер Minecraft на Ubuntu 20 04&#039;&#039;&#039;]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=45</id>
		<title>Заглавная страница</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%97%D0%B0%D0%B3%D0%BB%D0%B0%D0%B2%D0%BD%D0%B0%D1%8F_%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0&amp;diff=45"/>
		<updated>2023-03-25T20:50:23Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[https://wiki.ramba-art.ru/NGINXproxyManager &#039;&#039;&#039;Поднимаем NGINXproxyManager&#039;&#039;&#039;] &lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/VENV &#039;&#039;&#039;Кратко о VENV&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D1%82%D1%8C_requirements_txt &#039;&#039;&#039;Как создать requirements txt&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9D%D0%B0%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B0_%D0%BB%D0%BE%D0%BA%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8_Ubuntu_%D0%B8%D0%BB%D0%B8_UBUNTU_%D0%BD%D0%B0_%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%BC &#039;&#039;&#039;UBUNTU на русский&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.ramba-art.ru/%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04 Как сделать сервер Minecraft на Ubuntu 20 04]&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04&amp;diff=44</id>
		<title>Как сделать сервер Minecraft на Ubuntu 20 04</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%9A%D0%B0%D0%BA_%D1%81%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C_%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80_Minecraft_%D0%BD%D0%B0_Ubuntu_20_04&amp;diff=44"/>
		<updated>2023-03-25T20:49:34Z</updated>

		<summary type="html">&lt;p&gt;Artem: Новая страница: «&amp;#039;&amp;#039;&amp;#039;Подготовка&amp;#039;&amp;#039;&amp;#039; Согласно официальному сайту Minecraft, в качестве минимальной конфигурации для типичной установки рекомендуется 4 ГБ ОЗУ.  &amp;#039;&amp;#039;&amp;#039;Установите пакеты, необходимые для сборки инструмента mcrcon :&amp;#039;&amp;#039;&amp;#039;      apt update &amp;amp;&amp;amp; apt upgrate -y     apt install git build-essential  &amp;#039;&amp;#039;&amp;#039;Установка сред...»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Подготовка&#039;&#039;&#039;&lt;br /&gt;
Согласно официальному сайту Minecraft, в качестве минимальной конфигурации для типичной установки рекомендуется 4 ГБ ОЗУ.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Установите пакеты, необходимые для сборки инструмента mcrcon :&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    apt update &amp;amp;&amp;amp; apt upgrate -y&lt;br /&gt;
    apt install git build-essential&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Установка среды выполнения Java&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    apt install openjdk-17-jre-headless&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Проверяем версию&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
    java -version&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Ответ должны получить&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
    openjdk version &amp;quot;17.0.5&amp;quot; 2022-10-18&lt;br /&gt;
    OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04)&lt;br /&gt;
    OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Создание пользователя Minecraft&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
По соображениям безопасности Minecraft не следует запускать от имени пользователя root. Мы создадим нового системного пользователя и группу с домашним каталогом /opt/minecraft . У пользователя будут минимально необходимые разрешения для запуска сервера Minecraft:&lt;br /&gt;
&lt;br /&gt;
    useradd -r -m -U -d /opt/minecraft -s /bin/bash minecraft&lt;br /&gt;
&lt;br /&gt;
Мы не будем устанавливать пароль для этого пользователя. Таким образом, пользователь не сможет войти через SSH и его нельзя будет скомпрометировать. Чтобы перейти на пользователя minecraft , вам необходимо войти на сервер как пользователь root или пользователь с привилегиями sudo .&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Установка Minecraft на Ubuntu&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Переходим на вновь созданного пользователя&lt;br /&gt;
&lt;br /&gt;
    su - minecraft&lt;br /&gt;
&lt;br /&gt;
Выполните следующую команду, чтобы создать три новых каталога внутри домашнего каталога пользователя:&lt;br /&gt;
&lt;br /&gt;
    mkdir -p ~/{backups,tools,server}&lt;br /&gt;
&lt;br /&gt;
* В каталоге backups будут храниться резервные копии вашего сервера Minecraft. Вы можете синхронизировать этот каталог с вашим удаленным сервером резервного копирования.&lt;br /&gt;
* Каталог tools будет содержать клиент mcrcon и скрипт резервного копирования.&lt;br /&gt;
* Каталог server будет содержать фактический сервер Minecraft и его данные.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Скачивание и компиляция mcrcon&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
RCON — это протокол, который позволяет подключаться к серверам Minecraft и выполнять команды. mcron — это клиент RCON, написанный на C.&lt;br /&gt;
&lt;br /&gt;
Мы mcrcon исходный код с GitHub и mcrcon двоичный файл mcrcon .&lt;br /&gt;
&lt;br /&gt;
Tiiffi/mcrcon репозиторий Tiiffi/mcrcon с GitHub в каталог ~/tools/mcron :&lt;br /&gt;
&lt;br /&gt;
    git clone https://github.com/Tiiffi/mcrcon.git ~/tools/mcrcon&lt;br /&gt;
&lt;br /&gt;
По завершении mcron каталог mcron и mcron утилиту:&lt;br /&gt;
&lt;br /&gt;
    cd ~/tools/mcrcon&lt;br /&gt;
    gcc -std=gnu11 -pedantic -Wall -Wextra -O2 -s -o mcrcon mcrcon.c&lt;br /&gt;
&lt;br /&gt;
После завершения убедитесь, что mcrcon успешно скомпилирован, распечатав его версию:&lt;br /&gt;
&lt;br /&gt;
    ./mcrcon -v&lt;br /&gt;
&lt;br /&gt;
Результат будет выглядеть примерно так:&lt;br /&gt;
   &lt;br /&gt;
    mcrcon 0.7.2 (built: Oct  2 2022 16:10:42) - https://github.com/Tiiffi/mcrcon&lt;br /&gt;
    Bug reports:&lt;br /&gt;
        tiiffi+mcrcon at gmail&lt;br /&gt;
        https://github.com/Tiiffi/mcrcon/issues/&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Скачивание сервера Minecraft&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Существует несколько модов сервера Minecraft, таких как Craftbukkit или Spigot, которые позволяют добавлять функции (плагины) на ваш сервер и дополнительно настраивать и настраивать параметры сервера.&lt;br /&gt;
&lt;br /&gt;
В этом руководстве мы установим последний официальный ванильный сервер Minecraft от Mojang. Те же инструкции применимы и для установки других серверных модов.&lt;br /&gt;
&lt;br /&gt;
Перейдите на страницу [https://www.minecraft.net/en-us/download/server загрузки Minecraft], чтобы получить ссылку для загрузки последней версии файла архива Java (JAR) сервера Minecraft. На момент написания последняя версия — 1.19.4 .&lt;br /&gt;
&lt;br /&gt;
Загрузите файл jar в каталог ~/server с помощью wget :&lt;br /&gt;
&lt;br /&gt;
    wget https://piston-data.mojang.com/v1/objects/8f3112a1049751cc472ec13e397eade5336ca7ae/server.jar -P ~/server&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Настройка Сервера Майнкрафт&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
После завершения загрузки переключитесь в каталог ~/server и запустите сервер Minecraft:&lt;br /&gt;
&lt;br /&gt;
    cd ~/server&lt;br /&gt;
    java -Xmx1024M -Xms1024M -jar server.jar nogui&lt;br /&gt;
&lt;br /&gt;
При первом запуске сервер выполняет некоторые операции, создает файлы server.properties и eula.txt и останавливается.&lt;br /&gt;
&lt;br /&gt;
    [17:35:14] [main/ERROR]: Failed to load properties from file: server.properties&lt;br /&gt;
    [17:35:15] [main/WARN]: Failed to load eula.txt&lt;br /&gt;
    [17:35:15] [main/INFO]: You need to agree to the EULA in order to run the server. Go to eula.txt for more info.&lt;br /&gt;
&lt;br /&gt;
Чтобы запустить сервер, вам необходимо согласиться с лицензионным соглашением Minecraft EULA, как указано в выходных данных выше. Откройте файл eula.txt и замените eula=false на eula=true :&lt;br /&gt;
&lt;br /&gt;
    nano ~/server/eula.txt&lt;br /&gt;
&lt;br /&gt;
                       &#039;&#039;&#039;&#039;&#039;~/server/eula.txt&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
    eula=true&lt;br /&gt;
&lt;br /&gt;
акройте и сохраните файл. Напомню ctrl + O =&amp;gt; save &amp;amp; ctrl + X =&amp;gt; exit.&lt;br /&gt;
&lt;br /&gt;
Затем откройте файл server.properties включите протокол rcon и установите пароль rcon:&lt;br /&gt;
&lt;br /&gt;
    nano ~/server/server.properties&lt;br /&gt;
&lt;br /&gt;
Найдите следующие строки и обновите их значения, как показано ниже:&lt;br /&gt;
&lt;br /&gt;
                      &#039;&#039;&#039;&#039;&#039;~/server/server.properties&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
    rcon.port=25575&lt;br /&gt;
    rcon.password=strong-password&lt;br /&gt;
    enable-rcon=true&lt;br /&gt;
&lt;br /&gt;
Не забудьте сменить надежный strong-password на более безопасный. Если вы не хотите подключаться к серверу Minecraft из удаленных мест, убедитесь, что порт rcon заблокирован вашим брандмауэром.&lt;br /&gt;
Здесь вы также можете настроить свойства сервера по умолчанию. Для получения дополнительной информации о настройках сервера посетите страницу [https://minecraft.fandom.com/wiki/Server.properties server.properties] .&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Создание файла модуля Systemd&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Вместо того, чтобы вручную запускать сервер Minecraft, мы создадим файл модуля Systemd и запустим Minecraft как службу.&lt;br /&gt;
&lt;br /&gt;
Вернитесь к своему пользователю sudo, набрав exit .&lt;br /&gt;
&lt;br /&gt;
Откройте текстовый редактор и создайте файл с именем minecraft.service в каталоге /etc/systemd/system/ :&lt;br /&gt;
&lt;br /&gt;
    sudo nano /etc/systemd/system/minecraft.service&lt;br /&gt;
&lt;br /&gt;
Вставьте следующую конфигурацию:&lt;br /&gt;
&lt;br /&gt;
                      &#039;&#039;&#039;&#039;&#039;/etc/systemd/system/minecraft.service&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
    [Unit]&lt;br /&gt;
    Description=Minecraft Server&lt;br /&gt;
    After=network.target&lt;br /&gt;
&lt;br /&gt;
    [Service]&lt;br /&gt;
    User=minecraft&lt;br /&gt;
    Nice=1&lt;br /&gt;
    KillMode=none&lt;br /&gt;
    SuccessExitStatus=0 1&lt;br /&gt;
    ProtectHome=true&lt;br /&gt;
    ProtectSystem=full&lt;br /&gt;
    PrivateDevices=true&lt;br /&gt;
    NoNewPrivileges=true&lt;br /&gt;
    WorkingDirectory=/opt/minecraft/server&lt;br /&gt;
    ExecStart=/usr/bin/java -Xmx1024M -Xms1024M -jar server.jar nogui&lt;br /&gt;
    ExecStop=/opt/minecraft/tools/mcrcon/mcrcon -H 127.0.0.1 -P 25575 -p strong-password stop&lt;br /&gt;
&lt;br /&gt;
    [Install]&lt;br /&gt;
    WantedBy=multi-user.target&lt;br /&gt;
&lt;br /&gt;
Измените флаги Xmx и Xms соответствии с ресурсами вашего сервера. Флаг Xmx определяет максимальный пул распределения памяти для виртуальной машины Java (JVM), а Xms определяет начальный пул распределения памяти. Также убедитесь, что вы используете правильный порт rcon и пароль.&lt;br /&gt;
&lt;br /&gt;
Сохраните файл и перезагрузите конфигурацию systemd manager:&lt;br /&gt;
&lt;br /&gt;
    sudo systemctl daemon-reload&lt;br /&gt;
&lt;br /&gt;
Теперь вы можете запустить сервер Minecraft, набрав:&lt;br /&gt;
&lt;br /&gt;
    sudo systemctl start minecraft&lt;br /&gt;
&lt;br /&gt;
При первом запуске службы она сгенерирует несколько файлов конфигурации и каталогов, включая мир Minecraft.&lt;br /&gt;
&lt;br /&gt;
Проверьте статус службы с помощью следующей команды:&lt;br /&gt;
&lt;br /&gt;
    sudo systemctl status minecraft&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
   * minecraft.service - Minecraft Server&lt;br /&gt;
     Loaded: loaded (/etc/systemd/system/minecraft.service; disabled; vendor preset: enabled)&lt;br /&gt;
     Active: active (running) since Tue 2020-06-23 17:48:44 UTC; 8s ago&lt;br /&gt;
   Main PID: 1338035 (java)&lt;br /&gt;
      Tasks: 15 (limit: 1074)&lt;br /&gt;
     Memory: 465.3M&lt;br /&gt;
     CGroup: /system.slice/minecraft.service&lt;br /&gt;
             └─1338035 /usr/bin/java -Xmx1024M -Xms1024M -jar server.jar nogui&lt;br /&gt;
&lt;br /&gt;
Наконец, включите автоматический запуск службы Minecraft во время загрузки:&lt;br /&gt;
&lt;br /&gt;
    sudo systemctl enable minecraft&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Настройка брандмауэра&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ubuntu поставляется с инструментом настройки брандмауэра под названием UFW. Если в вашей системе включен брандмауэр , и вы хотите получить доступ к серверу Minecraft извне вашей локальной сети, вам необходимо открыть порт 25565 :&lt;br /&gt;
&lt;br /&gt;
    sudo ufw allow 25565/tcp&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Настройка резервного копирования&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
В этом разделе мы создадим сценарий оболочки резервного копирования и задание cron для автоматического резервного копирования сервера Minecraft.&lt;br /&gt;
&lt;br /&gt;
Переключитесь на minecraft :&lt;br /&gt;
&lt;br /&gt;
    sudo su - minecraft&lt;br /&gt;
&lt;br /&gt;
Откройте текстовый редактор и создайте следующий файл:&lt;br /&gt;
&lt;br /&gt;
    nano /opt/minecraft/tools/backup.sh&lt;br /&gt;
&lt;br /&gt;
Вставьте следующую конфигурацию:&lt;br /&gt;
&lt;br /&gt;
                      &#039;&#039;&#039;&#039;&#039;/opt/minecraft/tools/backup.sh&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
&lt;br /&gt;
    function rcon {&lt;br /&gt;
      /opt/minecraft/tools/mcrcon/mcrcon -H 127.0.0.1 -P 25575 -p strong-password &amp;quot;$1&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rcon &amp;quot;save-off&amp;quot;&lt;br /&gt;
    rcon &amp;quot;save-all&amp;quot;&lt;br /&gt;
    tar -cvpzf /opt/minecraft/backups/server-$(date +%F-%H-%M).tar.gz /opt/minecraft/server&lt;br /&gt;
    rcon &amp;quot;save-on&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    ## Delete older backups&lt;br /&gt;
    find /opt/minecraft/backups/ -type f -mtime +7 -name &#039;*.gz&#039; -delete&lt;br /&gt;
&lt;br /&gt;
Сохраните файл и сделайте скрипт исполняемым :&lt;br /&gt;
&lt;br /&gt;
    chmod +x /opt/minecraft/tools/backup.sh&lt;br /&gt;
&lt;br /&gt;
Затем создайте задание cron, которое будет запускаться автоматически один раз в день в определенное время.&lt;br /&gt;
&lt;br /&gt;
Откройте файл crontab, набрав:&lt;br /&gt;
&lt;br /&gt;
    crontab -e&lt;br /&gt;
&lt;br /&gt;
Чтобы запускать сценарий резервного копирования каждый день в 23:00, вставьте следующую строку:&lt;br /&gt;
&lt;br /&gt;
    0 23 * * * /opt/minecraft/tools/backup.sh&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Доступ к консоли Minecraft&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Для доступа к консоли Minecraft используйте утилиту mcrcon . Вам необходимо указать хост, порт rcon, пароль rcon и использовать переключатель -t который включает mcrcon терминала mcrcon :&lt;br /&gt;
&lt;br /&gt;
    /opt/minecraft/tools/mcrcon/mcrcon -H 127.0.0.1 -P 25575 -p strong-password -t&lt;br /&gt;
&lt;br /&gt;
    Logged in. Type &amp;quot;Q&amp;quot; to quit!&lt;br /&gt;
    &amp;gt;&lt;br /&gt;
 &lt;br /&gt;
При доступе к консоли Minecraft из удаленного места убедитесь, что порт rcon не заблокирован.&lt;br /&gt;
&lt;br /&gt;
Если вы регулярно подключаетесь к консоли Minecraft, вместо того, чтобы вводить эту длинную команду, вы создаете псевдоним bash .&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Выводы&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Мы показали вам, как создать сервер Minecraft на Ubuntu 20.04 и настроить ежедневное резервное копирование.&lt;br /&gt;
&lt;br /&gt;
Теперь вы можете запустить свой клиент Minecraft , подключиться к серверу и начать свое приключение в Minecraft.&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
	<entry>
		<id>https://wiki.ramba-art.ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8Bc%D0%B9.png&amp;diff=43</id>
		<title>Файл:Безымянныcй.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.ramba-art.ru/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8Bc%D0%B9.png&amp;diff=43"/>
		<updated>2023-03-25T20:10:35Z</updated>

		<summary type="html">&lt;p&gt;Artem: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;скрин терминала&lt;/div&gt;</summary>
		<author><name>Artem</name></author>
	</entry>
</feed>