Compare commits
4 Commits
main
...
8ce4b5f47a
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ce4b5f47a | |||
| bccbdb9bf3 | |||
| 64e90bb8e2 | |||
| a9d73b7368 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,6 +8,7 @@ backup/*
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
package-lock.json
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
|
||||
3974
package-lock.json
generated
3974
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
316
src/content/blog/09-graylog.md
Normal file
316
src/content/blog/09-graylog.md
Normal file
@@ -0,0 +1,316 @@
|
||||
---
|
||||
title: 'Graylog'
|
||||
summary: 'Краткое руководство по установки Graylog'
|
||||
date: '11 07 2024'
|
||||
draft: false
|
||||
tags:
|
||||
- Graylog
|
||||
- log
|
||||
---
|
||||
|
||||
# Введение
|
||||
Graylog — это платформа с открытым исходным кодом, предназначенная для управления логами. Она собирает и извлекает важные данные из логов сервера, которые обычно отправляются с помощью протокола Syslog.
|
||||
|
||||
## Возможности Graylog:
|
||||
|
||||
- Поиск и визуализация логов в веб-интерфейсе.
|
||||
- Настройка фильтрации и поиска логов.
|
||||
- Мониторинг и отправка оповещений.
|
||||
- Graylog позволяет отправлять логи и журналы событий с сотен сетевых устройств, включая серверы на Linux, Windows, сетевые устройства и другое оборудование.
|
||||
|
||||
## Архитектура Graylog
|
||||
Стек Graylog включает следующие компоненты:
|
||||
|
||||
- Сервер Graylog — веб-интерфейс для визуализации и настройки.
|
||||
- MongoDB — используется для хранения метаданных.
|
||||
- ElasticSearch или его форк OpenSearch — для хранения и полнотекстового поиска в структурированных и неструктурированных логах.
|
||||
- Java (OpenJDK) — среда выполнения для OpenSearch (Elasticsearch).
|
||||
Мы будем использовать стек OpenSearch для хранения журналов, который является бесплатным аналогом стека ELK (Elasticsearch + Logstash + Kibana).
|
||||
|
||||
## Причины выбора Graylog
|
||||
- Распространенность и проверенность временем.
|
||||
- Открытый исходный код.
|
||||
- Бесплатная версия включает все необходимое.
|
||||
- Минимальный функционал, оптимальный для наших задач.
|
||||
- "Из коробки" решение требует минимальных настроек.
|
||||
- Низкая ресурсоемкость по сравнению с ELK.
|
||||
|
||||
# Подготовка сервера
|
||||
|
||||
| Параметры | Значения |
|
||||
|------------------------|-----------------|
|
||||
| Кол-во ядер процессора | 4 CPU |
|
||||
| Размер ОЗУ | 8 GB |
|
||||
| Размер DISK | 90 GB |
|
||||
| Сетевой интерфейс |2 eth / 2 подсети|
|
||||
|
||||
Для стабильной работы используйте следующие версии
|
||||
| Дистрибутив| Версия |
|
||||
|------------|--------|
|
||||
| Debian | 12 |
|
||||
| MongoDB | 6.0 |
|
||||
| Graylog | 5.2 |
|
||||
| OpenSearch | 2.17 |
|
||||
|
||||
Проверьте архитектуру системы, поскольку MongoDB 6.0 поддерживает только x64 Debian:
|
||||
```sh
|
||||
uname -m
|
||||
# Нужно получить
|
||||
# x86_64
|
||||
```
|
||||
Авторизуемся под рутом
|
||||
```sh
|
||||
su -
|
||||
Password:
|
||||
```
|
||||
Устанавливаем sudo
|
||||
```sh
|
||||
apt install sudo
|
||||
# Сразу добавим пользователю права на будущее
|
||||
nano /etc/sudoers
|
||||
```
|
||||
Ниже этой строки пользователя root добавляем своего `<username> ALL=(ALL:ALL) ALL`
|
||||
```sh
|
||||
# User privilege specification
|
||||
root ALL=(ALL:ALL) ALL
|
||||
<username> ALL=(ALL:ALL) ALL
|
||||
```
|
||||
### Настройка часового пояса (если не указано при установке ОС)
|
||||
```sh
|
||||
timedatectl set-timezone Asia/Yakutsk
|
||||
```
|
||||
## Установка необходимых пакетов
|
||||
```sh
|
||||
# Обновляем пакеты
|
||||
apt update -y && apt upgrade -y && apt dist-upgrade -y
|
||||
# Устанавливаем целевые пакеты
|
||||
apt install -y net-tools mc htop git wget curl make gcc neofetch lsb-release ca-certificates gnupg gnupg2 tar lbzip2 zip unzip screen pwgen
|
||||
```
|
||||
Так же рекомендуется воспользоваться настройками для начальной защиты сервера на Linux
|
||||
|
||||
Если вы настроили firewalld то дополните настройки:
|
||||
```sh
|
||||
# Если не используем ipv6 - лучше отключить:
|
||||
firewall-cmd --remove-service=dhcpv6-client
|
||||
# Добавляем порты в файрвол
|
||||
firewall-cmd --permanent --add-port=9000/tcp
|
||||
firewall-cmd --permanent --add-port=514/tcp
|
||||
firewall-cmd --permanent --add-port=514/udp
|
||||
firewall-cmd --permanent --zone=itsoft --add-service=https
|
||||
firewall-cmd --permanent --zone=itsoft --add-service=http
|
||||
# После добавления/удаления перезагрузим сервис:
|
||||
firewall-cmd --reload
|
||||
```
|
||||
Настойка neofetch
|
||||
```sh
|
||||
# Первый запуск для создания ~/.config/neofetch/config.conf
|
||||
neofetch
|
||||
# Далее добавляем в .bashrc в самый конец файла
|
||||
echo "neofetch" >> ~/.bashrc
|
||||
# Далее идем редактировать конфиг
|
||||
nano ~/.config/neofetch/config.conf
|
||||
```
|
||||
Я использую вот такие параметры для вывода минимально необходимого при подключении к серверу.
|
||||
```sh
|
||||
print_info() {
|
||||
info title
|
||||
info underline
|
||||
|
||||
info "OS" distro
|
||||
info "Host" model
|
||||
info "Kernel" kernel
|
||||
info "Uptime" uptime
|
||||
#info "Packages" packages
|
||||
info "Shell" shell
|
||||
#info "Resolution" resolution
|
||||
#info "DE" de
|
||||
#info "WM" wm
|
||||
#info "WM Theme" wm_theme
|
||||
#info "Theme" theme
|
||||
#info "Icons" icons
|
||||
info "Terminal" term
|
||||
info "Terminal Font" term_font
|
||||
info "CPU" cpu
|
||||
#info "GPU" gpu
|
||||
info "Memory" memory
|
||||
|
||||
# info "GPU Driver" gpu_driver # Linux/macOS only
|
||||
# info "CPU Usage" cpu_usage
|
||||
info "Disk" disk
|
||||
# info "Battery" battery
|
||||
# info "Font" font
|
||||
# info "Song" song
|
||||
# [[ "$player" ]] && prin "Music Player" "$player"
|
||||
info "Local IP" local_ip
|
||||
# info "Public IP" public_ip
|
||||
# info "Users" users
|
||||
# info "Locale" locale # This only works on glibc systems.
|
||||
|
||||
#info cols
|
||||
}
|
||||
```
|
||||
### Установка MongoDB 6
|
||||
```sh
|
||||
# Добавление публичного ключа:
|
||||
curl -fsSL https://www.mongodb.org/static/pgp/server-6.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-6.0.gpg --dearmor
|
||||
# Добавление репозитория:
|
||||
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-6.0.gpg] http://repo.mongodb.org/apt/debian bullseye/mongodb-org/6.0 main" | sudo tee /etc/apt/sources.list.d/mongodb-org-6.0.list
|
||||
# Обновление локальной базы пакетов:
|
||||
sudo apt-get update
|
||||
# Установка MongoDB:
|
||||
sudo apt-get install -y mongodb-org
|
||||
```
|
||||
Если при установке вы получили сообщение об unmet dependencies
|
||||
```sh
|
||||
The following packages have unmet dependencies:
|
||||
mongodb-org-mongos : Depends: libssl1.1 (>= 1.1.1) but it is not installable
|
||||
mongodb-org-server : Depends: libssl1.1 (>= 1.1.1) but it is not installable
|
||||
```
|
||||
выполните следующие команды:
|
||||
```sh
|
||||
sudo wget http://archive.ubuntu.com/ubuntu/pool/main/o/openssl/libssl1.1_1.1.1f-1ubuntu2_amd64.deb
|
||||
sudo dpkg -i libssl1.1_1.1.1f-1ubuntu2_amd64.deb
|
||||
```
|
||||
И повторяем установку `mongodb-org`
|
||||
```sh
|
||||
sudo apt-get install -y mongodb-org
|
||||
```
|
||||
Запуск сервиса MongoDB:
|
||||
```sh
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable mongod.service
|
||||
sudo systemctl restart mongod.service
|
||||
# Посмотреть статус сервиса
|
||||
sudo systemctl --type=service --state=active | grep mongod
|
||||
```
|
||||
### Переходим к развёртыванию OpenSearch
|
||||
```sh
|
||||
# Добавление публичного ключа для OpenSearch:
|
||||
curl -o- https://artifacts.opensearch.org/publickeys/opensearch.pgp | sudo gpg --dearmor --batch --yes -o /usr/share/keyrings/opensearch-keyring
|
||||
# Добавление репозитория OpenSearch:
|
||||
echo "deb [signed-by=/usr/share/keyrings/opensearch-keyring] https://artifacts.opensearch.org/releases/bundle/opensearch/2.x/apt stable main" | sudo tee /etc/apt/sources.list.d/opensearch-2.x.list
|
||||
# Обновление локальной базы пакетов:
|
||||
sudo apt-get update
|
||||
```
|
||||
Установка OpenSearch с генерацией пароля администратора:
|
||||
```sh
|
||||
sudo OPENSEARCH_INITIAL_ADMIN_PASSWORD=$(tr -dc A-Z-a-z-0-9_@#%^-_=+ < /dev/urandom | head -c${1:-32}) apt-get install opensearch
|
||||
```
|
||||
### Настройка OpenSearch
|
||||
```sh
|
||||
# Редактирование конфигурации OpenSearch:
|
||||
sudo nano /etc/opensearch/opensearch.yml
|
||||
```
|
||||
|
||||
```sh
|
||||
cluster.name: graylog
|
||||
node.name: ${HOSTNAME}
|
||||
path.data: /var/lib/opensearch
|
||||
path.logs: /var/log/opensearch
|
||||
network.host: 0.0.0.0
|
||||
# Добавляем в параметров перед plugins
|
||||
discovery.type: single-node
|
||||
action.auto_create_index: false
|
||||
plugins.security.disabled: true
|
||||
indices.query.bool.max_clause_count: 32768
|
||||
```
|
||||
Настройка параметров Java:
|
||||
```sh
|
||||
sudo nano /etc/opensearch/jvm.options
|
||||
```
|
||||
В параметрах `Xms` и `Xmx` установите половину объема ОЗУ сервера. Например, для сервера с 8 ГБ укажите:
|
||||
```sh
|
||||
-Xms4g
|
||||
-Xmx4g
|
||||
```
|
||||
Изменение параметров виртуальной памяти:
|
||||
```sh
|
||||
sudo sysctl -w vm.max_map_count=262144
|
||||
sudo echo 'vm.max_map_count=262144' >> /etc/sysctl.conf
|
||||
```
|
||||
Запуск OpenSearch:
|
||||
```sh
|
||||
sudo systemctl enable --now opensearch
|
||||
```
|
||||
### Установка Graylog
|
||||
Есть две версии Graylog: бесплатная Graylog Open и enterprise версия Graylog Operations, доступная по подписке.
|
||||
```sh
|
||||
wget https://packages.graylog2.org/repo/packages/graylog-5.2-repository_latest.deb
|
||||
sudo dpkg -i graylog-5.2-repository_latest.deb
|
||||
sudo apt-get update && sudo apt-get install graylog-server
|
||||
```
|
||||
Сгенерируйте пароли для двух переменных password_secret и root_password_sha2, без которых Graylog не запустится.
|
||||
|
||||
Пароль password_secret должен содержать минимум 64 символа:
|
||||
```sh
|
||||
pwgen -N 1 -s 96
|
||||
# Получаем сгенерированный пароль
|
||||
XzN25fRfHv7NGbVODAGDcRWhzd6QAQQa11RXLIVgSXCgaDZexaxE4VlLA1abmEQjN25BlRVyEp3LNhN6HcJL8GYjV3RQgwkA
|
||||
# Отправляем пароль для получения HEX ключа
|
||||
echo -n "Enter Password: " && head -1 </dev/stdin | tr -d '\n' | sha256sum | cut -d" " -f1
|
||||
```
|
||||
Скопируйте полученные значения password_secret и root_password_sha2 в файл `/etc/graylog/server/server.conf`.
|
||||
```sh
|
||||
password_secret = <сгенерированный_пароль>
|
||||
root_password_sha2 = <HEX_ключа>
|
||||
http_bind_address = <IP_адрес_сервера>:9000
|
||||
```
|
||||
Запустите сервер graylog:
|
||||
```sh
|
||||
sudo systemctl enable --now graylog-server
|
||||
sudo systemctl status graylog-server
|
||||
```
|
||||
### настройка Graylog
|
||||
Теперь нужно посмотреть логи сервера GrayLog, там вы обнаружите интересное сообщение:
|
||||
```sh
|
||||
cat /var/log/graylog-server/server.log
|
||||
# Получаем лог
|
||||
It seems you are starting Graylog for the first time. To set up a fresh install, a setup interface has been started. You must log in to it to perform the initial configuration and continue.
|
||||
Initial configuration is accessible at 0.0.0.0:9000, with username 'admin' and password 'eDluAYfeaX'.
|
||||
Try clicking on http://admin:eDluAYfeaX@0.0.0.0:9000
|
||||
```
|
||||
Видна ссылка для первого входа по временному паролю `http://admin:eDluAYfeaX@0.0.0.0:9000`
|
||||
В первый раз нужно зайти под временным паролем, который указан в лог файле. Воспользуйтесь простым мастером начальной конфигурации. Режим Graylog data node используется для настройки OpenSearch кластера из нескольких нод. Для простой конфигурации из одного сервера логов, этот этап можно пропустить.
|
||||
После первой настройки рекомендуется создать отдельного пользователя в `System -> Users and Teams`, назначив ему роль admin. Некоторые настройки встроенного администратора нельзя кастомизировать, поэтому лучше работать под отдельным пользователя. Назначьте пользователю роль `admin` и задайте email адрес.
|
||||
|
||||
Создайте сборщики данных в виде Input для разных устройств, например, `Syslog UDP` для Linux. Для каждого класса устройств лучше делать отдельный `input` (Linux сервера, сетевое оборудование, Windows хосты и т.д.).
|
||||
|
||||
Нужно указать его название, и порт, на котором сервер будет принимать данные. Остальные настройки оставить по-умолчанию.
|
||||
|
||||
|
||||
|
||||
Создайте индекс для класса Linux в `System -> Indices`, указав имя и настройки хранения логов.
|
||||
|
||||
Нужно указать имя, описание и префикс (например `linux_indx` ). Здесь можно также настроить сколько дней нужно хранить старые логи, и когда можно удалять старые индекс, а также максимальный размер индекса.
|
||||
|
||||
|
||||
|
||||
Для каждого `input` лучше создать отдельный `Stream`. Так разные сообщений от разных классов устройства будут находится в разных индексах. Перейдите в `Stream -> Create Stream ->` укажите название потока и выберите индекс, который нужно использовать.
|
||||
|
||||
В настройках `Stream` добавьте новое правило. Правило определят какие логи нужно отнести к этому потоку. В нашем случае выбираем `match input ->` выберите ваш `Linux Input`.
|
||||
|
||||
|
||||
После этого запустите `stream`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
230
src/content/blog/10-debian-start-conf.md
Normal file
230
src/content/blog/10-debian-start-conf.md
Normal file
@@ -0,0 +1,230 @@
|
||||
---
|
||||
title: 'Начальная настройка Debian'
|
||||
summary: 'Настройка debian server после установки'
|
||||
date: '10 06 2024'
|
||||
draft: false
|
||||
tags:
|
||||
- Debian
|
||||
- Fail2ban
|
||||
- firewalld
|
||||
---
|
||||
# Введение
|
||||
|
||||
## Настройка языка
|
||||
Параметры локали (locale) в Linux определяют текущие региональные настройки операционной системы, используемые в терминале и в графическом интерфейсе (формат даты и времени, поддерживаемые наборы символов/кодировки). Рассмотрим, как получить или изменить текущие настройки локали в Linux на примере Ubuntu и Debian.
|
||||
|
||||
Вывести текущие настройки локали в Ubuntu и Debian можно с помощью команды:
|
||||
|
||||
```sh
|
||||
locale
|
||||
# ИЛИ
|
||||
localectl status
|
||||
```
|
||||
|
||||
```sh
|
||||
LANG=en_US.UTF-8
|
||||
LANGUAGE=
|
||||
LC_CTYPE="en_US.UTF-8"
|
||||
LC_NUMERIC=en_US.UTF-8
|
||||
LC_TIME=en_US.UTF-8
|
||||
LC_COLLATE="en_US.UTF-8"
|
||||
LC_MONETARY=en_US.UTF-8
|
||||
LC_MESSAGES="en_US.UTF-8"
|
||||
LC_PAPER=en_US.UTF-8
|
||||
LC_NAME=en_US.UTF-8
|
||||
LC_ADDRESS=en_US.UTF-8
|
||||
LC_TELEPHONE=en_US.UTF-8
|
||||
LC_MEASUREMENT=en_US.UTF-8
|
||||
LC_IDENTIFICATION=en_US.UTF-8
|
||||
LC_ALL=
|
||||
```
|
||||
|
||||
|
||||
- **LANG** — текущая системная локаль (`en_US.UTF-8`)
|
||||
- **LC_NUMERIC** — формат чисел
|
||||
- **LC_MONETARY** — валюта и формат денежных величин
|
||||
- **LC_TIME** — формат даты и времени
|
||||
|
||||
Чтобы вывести список доступных локалей на хосте:
|
||||
|
||||
```sh
|
||||
locale -a
|
||||
# ИЛИ
|
||||
localectl list-locales
|
||||
```
|
||||
|
||||
Для детальной информации об установленных локалях:
|
||||
```sh
|
||||
locale -a -v
|
||||
```
|
||||
|
||||
Системная локаль `C.UTF-8` всегда присутствует в списке (локаль по умолчанию).
|
||||
|
||||
Чтобы вывести информацию о переменной окружения для формата времени и даты:
|
||||
```sh
|
||||
locale -k LC_TIME
|
||||
```
|
||||
|
||||
### Установить русскую local в Ubuntu и Debian
|
||||
|
||||
Добавим русскую локаль `ru_RU.UTF-8`.
|
||||
|
||||
Список локалей, доступных для установки, можно найти в файле `/etc/locale.gen`. Для генерации русской локали выполните:
|
||||
|
||||
```sh
|
||||
sudo locale-gen ru_RU.UTF-8
|
||||
```
|
||||
|
||||
Назначение русской локали по умолчанию:
|
||||
```sh
|
||||
sudo update-locale LANG=ru_RU.UTF-8
|
||||
```
|
||||
Или:
|
||||
```sh
|
||||
sudo localectl set-locale LANG=ru_RU.UTF-8
|
||||
```
|
||||
|
||||
Эта команда запишет следующую строку в файл `/etc/default/locale`:
|
||||
```sh
|
||||
LANG=ru_RU.UTF-8
|
||||
```
|
||||
Перезагрузите хост Linux, чтобы применить изменения.
|
||||
|
||||
Если вы зададите локаль, которая не была сгенерирована, команда `locale` выведет ошибки:
|
||||
|
||||
```sh
|
||||
locale: Cannot set LC_CTYPE to default locale: No such file or directory
|
||||
locale: Cannot set LC_MESSAGES to default locale: No such file or directory
|
||||
locale: Cannot set LC_ALL to default locale: No such file or directory
|
||||
LANG=fr_FR.utf8
|
||||
```
|
||||
|
||||
Можно задать разные локали для различных региональных настроек:
|
||||
|
||||
```sh
|
||||
sudo update-locale LC_NUMERIC=en_US.UTF-8 LC_TIME=en_US.UTF-8 LC_MONETARY=en_US.UTF-8
|
||||
```
|
||||
|
||||
В некоторых случаях необходимо сначала установить нужную локаль:
|
||||
|
||||
```sh
|
||||
sudo apt-get install language-pack-fr
|
||||
```
|
||||
|
||||
Если локаль не задана, и команда `locale -a` возвращает только три записи:
|
||||
|
||||
```sh
|
||||
C
|
||||
C.UTF-8
|
||||
POSIX
|
||||
```
|
||||
Сгенерируйте новую локаль и примените изменения:
|
||||
```sh
|
||||
sudo locale-gen ru_RU.UTF-8
|
||||
sudo update-locale LANG=ru_RU.UTF-8
|
||||
```
|
||||
Перезагрузите систему или откройте новое окно терминала. Новые пользователи будут использовать локаль, указанную в файле `/etc/default/locale`.
|
||||
|
||||
Для изменения локали конкретного пользователя, отредактируйте файл `.bashrc` в его домашнем каталоге:
|
||||
```sh
|
||||
nano .bashrc
|
||||
```
|
||||
### Создание нерутового пользователя
|
||||
|
||||
Создание нерутового пользователя — важная мера безопасности. Для этого используйте команды:
|
||||
```sh
|
||||
useradd [options] <username>
|
||||
```
|
||||
Затем для него добавляется пароль командой `passwd`:
|
||||
```sh
|
||||
passwd <username>
|
||||
```
|
||||
Наконец, этого пользователя нужно добавить в группу, которая имеет право выполнять команды с повышением привилегий `sudo`.
|
||||
```sh
|
||||
usermod -aG sudo <username>
|
||||
```
|
||||
### Ключи вместо паролей SSH
|
||||
Рекомендуется отключить аутентификацию по паролям в SSH и использовать ключи. Сначала установите OpenSSH:
|
||||
```sh
|
||||
sudo apt install openssh-client openssh-server
|
||||
```
|
||||
|
||||
Запуск демона SSH (sshd) на сервере под Ubuntu:
|
||||
```sh
|
||||
sudo systemctl start sshd
|
||||
# Автоматический запуск демона при каждой загрузке:
|
||||
sudo systemctl enable sshd
|
||||
```
|
||||
Итак, нужно сгенерировать ключи SSH на компьютере, с которого вы будете заходить на сервер:
|
||||
```sh
|
||||
ssh-keygen -t rsa -b 4096
|
||||
```
|
||||
Публичный ключ хранится в файле `.pub` и выглядит как строка случайных символов, которые начинаются с `ssh-rsa`.
|
||||
```sh
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ3GIJzTX7J6zsCrywcjAM/7Kq3O9ZIvDw2OFOSXAFVqilSFNkHlefm1iMtPeqsIBp2t9cbGUf55xNDULz/bD/4BCV43yZ5lh0cUYuXALg9NI29ui7PEGReXjSpNwUD6ceN/78YOK41KAcecq+SS0bJ4b4amKZIJG3JWm49NWvoo0hdM71sblF956IXY3cRLcTjPlQ84mChKL1X7+D645c7O4Z1N3KtL7l5nVKSG81ejkeZsGFzJFNqvr5DuHdDL5FAudW23me3BDmrM9ifUmt1a00mWci/1qUlaVFft085yvVq7KZbF2OP2NQACUkwfwh+iSTP username@hostname
|
||||
```
|
||||
Публичный ключ добавляется на сервер:
|
||||
```sh
|
||||
mkdir -p /home/<username>/.ssh && touch /home/<username>/.ssh/authorized_keys
|
||||
vim /home/<username>/.ssh/authorized_keys
|
||||
chmod 700 /home/<username>/.ssh && chmod 600 /home/<username>/.ssh/authorized_keys
|
||||
chown -R <username>:<username> /home/<username>/.ssh
|
||||
```
|
||||
Затем настройте файл конфигурации SSH **/etc/ssh/sshd_config** :
|
||||
```sh
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication no
|
||||
```
|
||||
### SSH на клиенте Windows
|
||||
SSH Agent может хранить закрытые ключи и предоставлять их в контексте безопасности текущего пользователя. Запустите службу ssh-agent и настройте автоматический запуск с помощью PowerShell команд управления службами:
|
||||
```powershell
|
||||
Set-service ssh-agent StartupType ‘Automatic’
|
||||
Start-Service ssh-agent
|
||||
```
|
||||
Добавьте ваш закрытый ключ в базу ssh-agent:
|
||||
```powershell
|
||||
ssh-add "C:\Users\user\.ssh\id_key_ssh"
|
||||
# или так
|
||||
ssh-add.exe $ENV:UserProfile\.ssh\id_key_ssh
|
||||
```
|
||||
### Настройки Firewall
|
||||
#### Установка и настройка Firewalld
|
||||
Чтобы ограничить доступ на сервер, можно использовать Firewalld. Установка:
|
||||
```sh
|
||||
sudo apt install firewalld
|
||||
```
|
||||
Добавляем SSH в исключения:
|
||||
```sh
|
||||
sudo firewall-cmd --zone=public --add-service=ssh --permanent
|
||||
```
|
||||
Запускаем сервис systemd для firewalld:
|
||||
```sh
|
||||
sudo systemctl start firewalld
|
||||
sudo systemctl enable firewalld
|
||||
```
|
||||
### Настройки Fail2Ban
|
||||
Fail2Ban помогает предотвратить атаки перебором, блокируя IP-адреса после нескольких неудачных попыток авторизации.
|
||||
#### Установка Fail2Ban
|
||||
|
||||
Для установки на Ubuntu и Debian выполните:
|
||||
```sh
|
||||
sudo apt install fail2ban
|
||||
```
|
||||
Запуск сервиса:
|
||||
```sh
|
||||
systemctl start fail2ban
|
||||
systemctl enable fail2ban
|
||||
```
|
||||
Настройки находятся в файлах `/etc/fail2ban/fail2ban.conf` и `/etc/fail2ban/jail.conf`.
|
||||
### Автоматические обновления безопасности
|
||||
В Ubuntu автоматические обновления включены по умолчанию.
|
||||
### Смена порта SSH
|
||||
Изменение порта SSH — мера обфускации:
|
||||
```sh
|
||||
Port <custom_port>
|
||||
```
|
||||
|
||||
Указывайте порт с параметром `-p` для SSH и `-P` для SFTP и SCP.
|
||||
### Заключение
|
||||
|
||||
Все эти шаги позволяют значительно повысить безопасность Linux-сервера.
|
||||
147
src/content/blog/11-python-script-OCR.md
Normal file
147
src/content/blog/11-python-script-OCR.md
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
title: 'Graylog'
|
||||
summary: 'Краткое руководство по установки Graylog'
|
||||
date: '10 05 2024'
|
||||
draft: false
|
||||
tags:
|
||||
- Python
|
||||
- OCR
|
||||
- tensorflow
|
||||
- pytesseract
|
||||
- opencv-python
|
||||
---
|
||||
# Скрипт для перевода изображения в текст
|
||||
|
||||
# Устанавливаем библиотеки
|
||||
|
||||
```python
|
||||
pip install opencv-python pytesseract tensorflow
|
||||
```
|
||||
|
||||
Не забудьте дополнительно установить Tesseract OCR на ваш компьютер, так как pytesseract является только оболочкой для него. Инструкции по установке можно найти [здесь](https://github.com/tesseract-ocr/tesseract).
|
||||
|
||||
|
||||
# Сам скрипт
|
||||
|
||||
```python
|
||||
import cv2
|
||||
import pytesseract
|
||||
import os
|
||||
|
||||
class TextRecognizer:
|
||||
def __init__(self, tesseract_cmd: str, languages: str = 'rus+eng'):
|
||||
# Указываем путь к Tesseract и языки для распознавания
|
||||
pytesseract.pytesseract.tesseract_cmd = tesseract_cmd
|
||||
self.languages = languages
|
||||
|
||||
def recognize_text(self, image):
|
||||
"""Распознавание текста на нескольких языках."""
|
||||
text = pytesseract.image_to_string(image, config='--oem 3 --psm 6', lang=self.languages)
|
||||
return text.strip()
|
||||
|
||||
class TextSaver:
|
||||
def __init__(self, directory: str = '.'):
|
||||
self.directory = directory
|
||||
|
||||
def save_text_to_file(self, text, filename='result.txt'):
|
||||
"""Сохранение распознанного текста в файл."""
|
||||
path = os.path.join(self.directory, filename)
|
||||
with open(path, 'w', encoding='utf-8') as file:
|
||||
file.write(text)
|
||||
print(f"Распознанный текст сохранен в файл '{path}'.")
|
||||
|
||||
class ImageProcessor:
|
||||
def __init__(self, recognizer: TextRecognizer, saver: TextSaver):
|
||||
self.recognizer = recognizer
|
||||
self.saver = saver
|
||||
|
||||
def ask_yes_no(self, question):
|
||||
"""Запрос подтверждения (да/нет)."""
|
||||
while True:
|
||||
answer = input(f"{question} (да/д/y/yes, нет/н/n/no): ").strip().lower()
|
||||
if answer in ('да', 'д', 'y', 'yes'):
|
||||
return True
|
||||
elif answer in ('нет', 'н', 'n', 'no'):
|
||||
return False
|
||||
else:
|
||||
print("Пожалуйста, введите 'да', 'д', 'y', 'yes', 'нет', 'н', 'n' или 'no'.")
|
||||
|
||||
def save_image(self, image, filename):
|
||||
"""Сохранение изображения."""
|
||||
cv2.imwrite(filename, image)
|
||||
print(f"Изображение сохранено как {filename}")
|
||||
|
||||
def preprocess_image(self, image):
|
||||
"""Создание нескольких вариантов улучшенных изображений."""
|
||||
# Преобразование в серый
|
||||
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||
|
||||
# Вариант 1: Бинаризация
|
||||
binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)[1]
|
||||
self.save_image(binary, 'binary.png')
|
||||
|
||||
# Вариант 2: Гауссово размытие
|
||||
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
|
||||
self.save_image(blurred, 'blurred.png')
|
||||
|
||||
# Вариант 3: Адаптивное пороговое преобразование
|
||||
adaptive_thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
|
||||
cv2.THRESH_BINARY, 11, 2)
|
||||
self.save_image(adaptive_thresh, 'adaptive_thresh.png')
|
||||
|
||||
return {
|
||||
'1': ('binary.png', binary),
|
||||
'2': ('blurred.png', blurred),
|
||||
'3': ('adaptive_thresh.png', adaptive_thresh)
|
||||
}
|
||||
|
||||
def process_image(self, image_path: str):
|
||||
"""Основной процесс обработки изображения."""
|
||||
if not os.path.isfile(image_path):
|
||||
print("Указанный файл не найден. Пожалуйста, проверьте путь.")
|
||||
return
|
||||
|
||||
image = cv2.imread(image_path)
|
||||
if image is None:
|
||||
print("Не удалось загрузить изображение. Убедитесь, что файл является изображением.")
|
||||
return
|
||||
|
||||
# Предварительное улучшение изображения
|
||||
if self.ask_yes_no("Хотите улучшить качество изображения перед распознаванием?"):
|
||||
options = self.preprocess_image(image)
|
||||
print("Варианты улучшения:")
|
||||
print("1 - Бинаризация")
|
||||
print("2 - Гауссово размытие")
|
||||
print("3 - Адаптивное пороговое преобразование")
|
||||
|
||||
choice = input("Выберите вариант улучшения (1/2/3): ").strip()
|
||||
if choice in options:
|
||||
selected_image = options[choice][1]
|
||||
print(f"Использование варианта {choice} для распознавания.")
|
||||
else:
|
||||
print("Некорректный выбор. Используется исходное изображение.")
|
||||
selected_image = image
|
||||
else:
|
||||
selected_image = image
|
||||
|
||||
if self.ask_yes_no("Хотите распознать текст на изображении?"):
|
||||
text = self.recognizer.recognize_text(selected_image)
|
||||
print(f"Распознанный текст:\n{text}")
|
||||
|
||||
if self.ask_yes_no("Хотите сохранить текст?"):
|
||||
self.saver.save_text_to_file(text)
|
||||
|
||||
# Убедитесь, что вы используете правильное условие для запуска основной функции
|
||||
if __name__ == "__main__":
|
||||
tesseract_cmd_path = r'C:\Users\<user>\AppData\Local\Programs\Tesseract-OCR\tesseract.exe'
|
||||
|
||||
# Инициализация классов
|
||||
recognizer = TextRecognizer(tesseract_cmd=tesseract_cmd_path)
|
||||
saver = TextSaver(directory='.')
|
||||
processor = ImageProcessor(recognizer=recognizer, saver=saver)
|
||||
|
||||
# Запуск обработки изображения
|
||||
image_path = input("Укажите путь до изображения (можно без кавычек): ").strip().strip('"')
|
||||
processor.process_image(image_path)
|
||||
|
||||
```
|
||||
323
src/content/blog/12-backend-frondend-project.md
Normal file
323
src/content/blog/12-backend-frondend-project.md
Normal file
@@ -0,0 +1,323 @@
|
||||
---
|
||||
title: 'Django сервер и JS приложения'
|
||||
summary: 'В этой статье описан полный цыкл стать от настройки ВМ устновки серверных приложений и их настроек'
|
||||
date: '18 11 2024'
|
||||
draft: false
|
||||
tags:
|
||||
- Python
|
||||
- venv
|
||||
- Django
|
||||
- TS
|
||||
---
|
||||
# Backend-Fronend старт проекта
|
||||
|
||||
## Стартовый установщик
|
||||
|
||||
### Установка необходимых пакетов
|
||||
|
||||
```sh
|
||||
sudo apt-get install -y zsh wget build-essential tree redis-server nginx \
|
||||
zlib1g-dev libbz2-dev libreadline-dev llvm libncurses5-dev libncursesw5-dev \
|
||||
xz-utils tk-dev liblzma-dev python3-dev python3-pip python3-venv python3-pil \
|
||||
python3-lxml libxslt-dev python3-libxml2 libffi-dev libssl-dev python3-dev \
|
||||
gnumeric libsqlite3-dev libpq-dev libxml2-dev libxslt1-dev libjpeg-dev \
|
||||
libfreetype6-dev libcurl4-openssl-dev libgdbm-dev libc6-dev supervisor
|
||||
```
|
||||
### Установка и настройка `Oh-my-zsh`
|
||||
```sh
|
||||
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
|
||||
zsh
|
||||
chsh -s $(which zsh)
|
||||
# или для root пользователя
|
||||
sudo chsh -s $(which zsh)
|
||||
```
|
||||
### Установка и настройка `neofetch`
|
||||
```sh
|
||||
# Первый запуск для создания конфигурационного файла ~/.config/neofetch/config.conf
|
||||
neofetch
|
||||
# Добавляем вызов neofetch в файл конфигурации zsh
|
||||
echo "neofetch" >> ~/.zshrc
|
||||
# Редактируем конфигурацию
|
||||
nano ~/.config/neofetch/config.conf
|
||||
```
|
||||
[Настройка описана вот в этой статье](https://xn----7sbabksvrfvnenyr4r.xn--p1ai/blog/09-graylog/#:~:text=cmd%20%2D%2Dreload-,%D0%9D%D0%B0%D1%81%D1%82%D0%BE%D0%B9%D0%BA%D0%B0%20neofetch,-%23%20%D0%9F%D0%B5%D1%80%D0%B2%D1%8B%D0%B9%20%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D0%BA%20%D0%B4%D0%BB%D1%8F)
|
||||
### Редактируем сообщение приветствия
|
||||
```sh
|
||||
sudo nano /etc/motd
|
||||
```
|
||||
## Настройка backend часть проект
|
||||
|
||||
При копировании обращайте внимание на `<username>` `project`
|
||||
### 1. Скачиваем и устанавливаем Python:
|
||||
```sh
|
||||
wget https://www.python.org/ftp/python/3.11.10/Python-3.11.10.tgz ; \
|
||||
tar xvf Python-3.11.* ; \
|
||||
cd Python-3.11.10 ; \
|
||||
mkdir ~/.python ; \
|
||||
./configure --enable-optimizations --prefix=/home/<username>/.python ; \
|
||||
make -j8 ; \
|
||||
sudo make altinstall
|
||||
###
|
||||
sudo /home/<username>/.python/bin/python3.11 -m pip install -U pip
|
||||
```
|
||||
### 2. Создаем рабочий каталог:
|
||||
```sh
|
||||
mkdir /var/www/project
|
||||
# даем права на группу root:users прописываем свои
|
||||
sudo chown -R root:users /var/www/project1
|
||||
sudo chmod 775 /var/www/project1
|
||||
cd /var/www/project1
|
||||
```
|
||||
### 3. Настраиваем виртуальное окружение:
|
||||
```sh
|
||||
/home/<username>/.python/bin/python3 -m venv env
|
||||
source env/bin/activate
|
||||
pip install -U pip
|
||||
git clone https://github.com/Project1.git
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
### Настройка базы данных и запуск проекта
|
||||
```shell
|
||||
python.exe manage.py makemigrations accounts media main
|
||||
python manage.py migrate
|
||||
python manage.py createsuperuser
|
||||
### Уже можем проверить старт приложения
|
||||
python manage.py runserver 0.0.0.0:8000
|
||||
```
|
||||
### Добавляем доступ к порт если есть `firewall`
|
||||
```sh
|
||||
sudo firewall-cmd --permanent --add-port=8000/tcp
|
||||
sudo firewall-cmd --permanent --add-port=8001/tcp
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
### Устанавливаем и настраиваем `gunicorn`
|
||||
Нужно создать 2 файла один в директории проекта, второй на уровне env, так же нужно установить сам gunicorn если его нет в списках `requirements.txt`
|
||||
```sh
|
||||
pip install gunicorn
|
||||
```
|
||||
#### Создаем конфигурационные файлы:
|
||||
1. `/var/www/project1/gunicorn_config.py`
|
||||
```python
|
||||
command = '/var/www/env/bin/gunicorn'
|
||||
pythonpath = '/var/www/project1'
|
||||
bind = '127.0.0.1:8001'
|
||||
workers = 5
|
||||
user = '<username>'
|
||||
limit_request_fields = 32000
|
||||
limit_request_field_size = 0
|
||||
raw_env = 'DJANGO_SETTINGS_MODULE=project1.settings'
|
||||
```
|
||||
2. Скрипт запуска `gunicorn_start.sh`:
|
||||
```sh
|
||||
#!/bin/bash
|
||||
source /var/www/env/bin/activate
|
||||
source /var/www/env/bin/postactivate
|
||||
exec gunicorn -c "/var/www/project1/gunicorn_config.py" project1.wsgi
|
||||
```
|
||||
3. Настройка прав:
|
||||
```sh
|
||||
chmod +x gunicorn_start.sh
|
||||
```
|
||||
### Настраиваем `supervisior`
|
||||
Создаем файл конфигурации `/etc/supervisior/conf.d/project1.conf`
|
||||
```sh
|
||||
[program:project1_gunicorn]
|
||||
command=/var/www/gunicorn_start.sh
|
||||
user=<username>
|
||||
process_name=%(program_name)s
|
||||
numprocs=1
|
||||
autostart=true
|
||||
autorestart=true
|
||||
redirect_stderr=true
|
||||
```
|
||||
### Настройка nginx
|
||||
Пример конфигурации `/etc/nginx/sites-available/project1`
|
||||
```sh
|
||||
server {
|
||||
server_name example.com;
|
||||
# Оптимизация SSL
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
|
||||
# HTTP заголовки для безопасности
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
# Основной корневой каталог
|
||||
root /var/www/html;
|
||||
index index.html index.htm index.nginx-debian.html;
|
||||
# Прокси для backend
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8001;
|
||||
proxy_set_header X-Forwarded-Host $server_name;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
|
||||
# Убедитесь, что вам действительно нужно разрешить доступ с любого домена
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
}
|
||||
# Обработка медиа файлов
|
||||
location /media/ {
|
||||
alias /var/www/project1/media/;
|
||||
expires max;
|
||||
access_log on;
|
||||
}
|
||||
# Логи
|
||||
error_log /var/log/nginx/backend-error.log;
|
||||
access_log /var/log/nginx/backend-access.log;
|
||||
# Максимальный размер загружаемого файла
|
||||
client_max_body_size 100M;
|
||||
# Защита от медленных атак (slowloris)
|
||||
client_body_timeout 10s;
|
||||
client_header_timeout 10s;
|
||||
#send_timeout 10s;
|
||||
keepalive_timeout 65;
|
||||
}
|
||||
# Редирект с HTTP на HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name example.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
```
|
||||
Активируем конфигурацию:
|
||||
```sh
|
||||
sudo ln -s /etc/nginx/sites-available/project1 /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo service nginx restart
|
||||
```
|
||||
### Установка SSL с `certbot`
|
||||
Для корректной работы нужно установить сертификат LetsEncrypt ssl, установка будет с помощью `certbot`
|
||||
[Инструкция с официального сайта]([Инструкции Certbot | Certbot](https://certbot.eff.org/instructions?ws=nginx&os=pip))
|
||||
```sh
|
||||
sudo apt update
|
||||
sudo apt install python3 python3-venv libaugeas0
|
||||
sudo /home/<username>/.python/bin/python3 -m venv /opt/certbot/
|
||||
sudo /opt/certbot/bin/pip install --upgrade pip
|
||||
sudo /opt/certbot/bin/pip install certbot certbot-nginx
|
||||
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
|
||||
sudo certbot --nginx
|
||||
```
|
||||
#### Добавляем авто перевыпуск сертификата
|
||||
```
|
||||
echo "0 0,12 * * * root /opt/certbot/bin/python -c 'import random; import time; time.sleep(random.random() * 3600)' && sudo certbot renew -q" | sudo tee -a /etc/crontab > /dev/null
|
||||
```
|
||||
## Настройка frontend часть проект
|
||||
1. Скачиваем проект:
|
||||
```sh
|
||||
git clone https://github.com/Project2.git
|
||||
cd project2
|
||||
```
|
||||
2. Устанавливаем `npm`
|
||||
```sh
|
||||
sudo apt install -y npm
|
||||
```
|
||||
3. Устанавливаем библиотеки из проекта
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
4. Стартуем проект в режиме разработчика
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
### Возвращаемся к добавления порта в `firewall`
|
||||
```sh
|
||||
sudo firewall-cmd --permanent --add-port=8002/tcp
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
### Создаем новый файл конфигурации для nginx
|
||||
`/etc/nginx/sites-available/project2`
|
||||
```sh
|
||||
server {
|
||||
listen 443;
|
||||
server_name example2.com;
|
||||
charset utf-8;
|
||||
|
||||
# Оптимизация SSL
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384";
|
||||
|
||||
# HTTP headers для безопасности
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
}
|
||||
# Обработка запросов
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8002;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
|
||||
# Защита от медленных атак (slowloris)
|
||||
client_body_timeout 10s;
|
||||
#client_header_timeout 10s;
|
||||
send_timeout 10s;
|
||||
}
|
||||
|
||||
# Логи
|
||||
error_log /var/log/nginx/frontend-error.log;
|
||||
access_log /var/log/nginx/frontend-access.log;
|
||||
|
||||
# Максимальный размер загружаемого файла (например, 100MB)
|
||||
client_max_body_size 100M;
|
||||
|
||||
# Защита от слишком долгих соединений
|
||||
keepalive_timeout 65;
|
||||
}
|
||||
|
||||
# Редирект с HTTP на HTTPS
|
||||
server {
|
||||
listen 80;
|
||||
server_name example2.com;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
```
|
||||
### Активируем конфигурацию:
|
||||
```sh
|
||||
sudo ln -s /etc/nginx/sites-available/project /etc/nginx/sites-enabled/
|
||||
sudo nginx -t && sudo service nginx restart
|
||||
# или используем nginx -s reload
|
||||
sudo nginx -t && sudo nginx -s reload
|
||||
# Добавляем сертификат на новый домен
|
||||
sudo certbot --nginx
|
||||
```
|
||||
### Устанавливаем приложения для управления проектом pm2
|
||||
```sh
|
||||
sudo npm i pm2 -g
|
||||
```
|
||||
Создаем файл конфигурации вместе с проектом
|
||||
```js
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'project2',
|
||||
port: '8002',
|
||||
exec_mode: 'cluster',
|
||||
instances: 'max',
|
||||
script: './project2/.output/server/index.mjs'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
### Включаем автозагрузку проекта
|
||||
```sh
|
||||
pm2 startup
|
||||
```
|
||||
Reference in New Issue
Block a user