Виртуальный сервер: настройка всякого

В этой теме мы научимся заказывать и настраивать виртуальный сервер. Выкатим на него телеграм-бота, небольшую веб-страницу и настроим свой собственный vpn.

Программы для винды для работы с этим всем

Для работы под Windows установите следующие программы:

Выбор VPS, оплата

Искать дешёвый VPS удобно на сайте https://poiskvps.ru/. Для наших целей достаточно 1ГБ оперативки и 1 ядра процессора. Вы можете выбрать что-то своё, я буду показывать на примере skyhost и тарифа VDS-1: 149 рублей в месяц за 1ГБ оперативки и 1 ядро.

Итак, регаемся на skyhost (или где-то ещё) и заказываем новый VPS. При регистрации укажите не свои, но с виду валидные адрес и номер паспорта. Скажем, «ул. Трофимова, 15-24» и «4508956118». Имя сервера укажите какое вам нравится. Но лучше разумное, оно будет отображаться в консоли. В качестве операционной системы выбирайте Ubuntu 20.04 (amd64). Панель управления вам не нужна. Через некоторое время на почту придёт письмо вида

VDS-1

SSH-доступ:
IP: 193.187.123.123
Login: root
Password: somePassword

Этого достаточно, чтобы подключиться! Открываете Windows Terminal или PowerShell (или иной терминал) и вводите команду:

ssh root@193.187.123.123 -p 22

В этой команде root — это имя пользователя, дальше после @ идёт ip-адрес вашего сервера, а -p 22 — это указание порта для подключения. По умолчанию порт и так 22, поэтому его можно и не указывать. После подключения спросят пароль, введите его. Если вы используете Windows Terminal, то для копипаста можно использовать Ctrl+C и Ctrl+V. Иначе Ctrl+Insert для копирования и Shift+Insert для вставки.
Если всё получилось правильно, то вы получите ответ вида:

Welcome to Ubuntu 20.04.1 LTS (GNU/Linux 5.4.0-58-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
root@test179:~#

Если всё так, то поздравляю! Вы успешно подключились к своему новому виртуальному серверу!

A: Поднять VPS

В этой задаче нужно сдать в тестирующую систему две строчки: ip-адрес VPS'а и порт для подключения по SSH (стандартно 22). (Это после того, как вы получили доступ к своему VPS).

193.187.175.97 22

Основные команды в терминале

Взаимодействие с виртуальным сервером будут происходить через команды в терминале. Прочитать можно них можно вот здесь:

B: Стандартные команды

Полезно уметь делать стандартные штуки в терминале: скачивать файлы, перемещаться между папками, копировать, перемещать и удалять файлы и папки. А также искать файлы по имени и по содержимому.

Итак в этой задаче нужно сделать последовательность команд, после чего сохранить историю в файл output.txt и сдать его на проверку. Лучше сначала убедиться, что вы всё понимаете, а потом провести чистовой проход. В выдаче разрешаются лишние команды, но лучше оставить их поменьше.
Чтобы начать всё с начала:

# Удаляем архив и папку с файлами
rm -f ~/bash.7z
rm -rf ~/bash
# Чистим историю
history -c

Задания:

  1. Перейдите в свою домашнюю папку ~.
  2. Выведите текущий полный путь.
  3. Скачайте wget'ом файл https://server.179.ru/tasks/python/2022b/attachments/bash.7z.
  4. Установите пакет p7zip, в котором архиватор 7-zip.
  5. Разархивируйте bash.7z в текущую папку (p7zip --help в помощь).
  6. Создайте в домашнем каталоге подкаталог cntrl (гуглить mkdir).
  7. Перейдите в подкаталог bash, который был в архиве (гуглить cd).
  8. Выведите список файлов и папок в этом каталоге на экран (гуглить ls).
  9. Перейдите в папку, в имени которой есть ee.
  10. Выведите список файлов и папок в этом каталоге на экран.
  11. Скопируйте подкаталог one из этого каталога в каталог cntrl, созданный выше, вместе со всеми файлами и вложенными подкаталогами (гуглить cp и использование ..).
  12. Перейдите в подкаталог one каталога cntrl, созданного выше (одной командой).
  13. Выведите на экран список файлов в этом каталоге.
  14. Переместите подкаталог two из текущего каталога в родительский каталог вместе со всеми файлами и вложенными подкаталогами (гуглить mv).
  15. Перейдите в подкаталог two родительского каталога (он должен быть создан в результате выполнения предыдущего пункта) (одной командой).
  16. Выведите на экран список всех файлов в текущем каталоге.
  17. Скопируйте все файлы (не каталоги!) из текущего каталога в каталог cntrl/one, который был создан выше (п.11). Используйте относительный путь для задания адреса.
  18. Перейдите в каталог cntrl/one, который был создан выше (п.11). Используйте относительный путь для задания адреса.
  19. Переместите в родительский каталог все файлы, третий символ в имени которых является нечётной цифрой (гуглить wildcards: *?[]{}).
  20. Выведите список файлов в текущем каталоге на экран.
  21. Перейдите в родительский каталог.
  22. Выведите список файлов в этом каталоге на экран.
  23. Сотрите в текущем каталоге все файлы, не стирая подкаталоги one и two (гуглить rm).
  24. Выведите на экран список всех файлов в текущем каталоге.
  25. Выведите список файлов в подкаталоге one (не переходя в него!).
  26. Удалите из каталога one все вложенные файлы и подкаталоги, не удаляя сам каталог one и не переходя в него.
  27. Удалите пустой каталог one (гуглить rmdir).
  28. Удалите каталог two вместе со всеми содержащимися в нем файлами и подкаталогами.
  29. Выведите список файлов на экран.
  30. Перейдите в родительский каталог.
  31. Сотрите подкаталог cntrl вместе со всеми файлами и подкаталогами.
  32. Выведите содержимое файла bash/files/nose (гуглить cat).
  33. Выведите имена всех файлы из папки bash/files, которые начинаются на fo (гуглить find).
  34. Выведите первые 10 строчек файла bash/rows/rows.txt (гуглить head).
  35. Выведите последние 20 строчек файла bash/rows/rows.txt (гуглить tail).
  36. Выведите все строчки файла bash/rows/rows.txt, содержащие слово Artur (гуглить grep).
  37. Выведите все файлы из папки bash/files, содержащие слово fools в любом регистре (выводить файл и пример строки) (снова гуглить grep).
  38. Выполните команду history > output.txt, отправьте его в тестирующую систему.

Начинаться всё должно примерно так:

1 cd ~ 2 pwd 3 wget https://server.179.ru/tasks/python/2022b/attachments/bash.7z 4 sudo apt install p7zip ...

C: Создать пользователя

В этой задаче нужно создать нового пользователя при помощи команды adduser. Дайте ему какое угодно имя и какой угодно пароль (чур без пробелов внутри!). Сдайте их в тестирующую систему в таком формате:

193.187.175.97 22 newuser password
Для параноиков
Если вы не хотите, чтобы под этим пользователем нельзя было на вашем виртуальном сервере ничего испортить, то можно поставить ему restricted bash и запретить примерно всё.
# Создаём restricted bash
sudo ln -s /bin/bash /bin/rbash
# Создаём папку для разрешённых бинарников (yourestricteduser — имя вашего пользователя)
sudo mkdir /home/yourestricteduser/bin
# Создаём ссылку на команду ls, чтобы её разрешить
sudo ln -s /bin/ls /home/yourestricteduser/bin/ls
# Ставим restricted bash при запуске
sudo chsh -s /bin/rbash yourestricteduser
# Настройка при логине
echo 'export PATH=$HOME/bin' | sudo tee /home/yourestricteduser/.bash_profile

Как пользоваться этим листком

В идеале нужно научиться находить решения в интернете. Поэтому все решения будут спрятаны за спойлерами. Почти все запросы для поиска должны на старте выглядеть так: «ubuntu установить mc».
Если вам неохота искать и разбираться, то... открывайте спойлеры и вводите команды. Даже это не всегда на 100% просто! Если что-то не работает — спрашивайте/пишите.

Установка midnight commander'а

Установка mc, если решение не ищется

После подключения по ssh под root'ом выполните команду:

apt install mc

Должно получиться в конце что-то такое:

root@test179:~# apt install mc
Reading package lists... Done
...
...
Setting up mc (3:4.8.24-2ubuntu1) ...
update-alternatives: using /usr/bin/mcview to provide /usr/bin/view (view) in auto mode
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for mime-support (3.64ubuntu1) ...
Processing triggers for libc-bin (2.31-0ubuntu9.1) ...
root@test179:~#

После установки выполните команду mc. И хотя «суровые админы» практически никогда не пользуются этой штукой, она может очень скрасить вам знакомство с администрированием linux.

Смотрите: там прямо сразу есть подсказка: переключение между Midnight commander'ом и консолью по клавишам Ctrl+O. Запомните его, пригодится.

Для работы в консольном текстовом редакторе вам потребуются горячие клавиши Ctrl+S, чтобы сохранить изменения, и Ctrl+Q для выхода.

Настройка локали

Чтобы система понимала, что вы «любите» русский язык в utf-8, нужно настроить локаль. Для этого нужно выполнить команды:

# Ставим пакет с русской локалью
sudo apt-get install language-pack-ru
# Ставим локалью по умолчанию utf-8
sudo update-locale LANG=ru_RU.UTF-8

Чтобы начало работать, нужно перезайти в терминал.

Настройка доступа по ssh и смена стандартного порта

SSH (англ. Secure Shell — «безопасная оболочка») — сетевой протокол прикладного уровня, позволяющий производить удалённое управление операционной системой. Всё управление виртуальным сервером будет производиться как раз через SSH. Так как 99.9% серверов управляются через SSH, то много «желающих» ваш виртуальный сервер сломать и использовать его для каких-нибудь своих целей: рассылать спам, устраивать DDOS-адаки, майнить крипту и т.п. Поэтому для стандартного начала работы с новым сервером нужно сделать следующие шаги:

Ещё одна причина, почему с этого нужно начинать такая: в результате неаккуратной настройки можно потерять доступ к серверу. Потребуется переустановка операционной системы. Очень обидно, если это происходит, когда в системе уже сделано что-то полезное.

Итак, ключевые слова, чтобы искать: «ubuntu сменить порт для ssh», «ubuntu новый пользователь с правами root», «ubuntu windows ssh ключ». Ну, вы уже поняли, да?

Смена стандартного порта ssh с 22 на 22179.

Открываем конфиг демона, который рулит SSH'ем на сервере. Он называется /etc/ssh/sshd_config.

sudo nano /etc/ssh/sshd_config

Находите там строчку вида #Port 22. Удаляете решётку — это комментарий — и ставите порт 22179. Сохраняете изменения.
Далее следует перезапустить демон SSH. Выполните команду:

sudo systemctl restart sshd

Проверяем порты SSH-сервера:

sudo ss -tupln | grep ssh

# Должно получиться
# serge@test179:~$ sudo ss -tupln | grep sshd
# tcp    LISTEN  0       128                  0.0.0.0:22179         0.0.0.0:*      users:(("sshd",pid=71737,fd=3))
# tcp    LISTEN  0       128                     [::]:22179            [::]:*      users:(("sshd",pid=71737,fd=4))

Теперь не закрывая старый терминал (на случай, если что-то сделали не так), открываем новый и вводим в нём:

ssh root@193.187.123.123 -p 22179

Если всё пошло по плану, то вы должны успешно подключиться.

Создание себе своего личного супер-пользователя

По идее вы уже должны были создать нового пользователя. Но если ещё нет, то

adduser serge

вводите пароль и соглашаетесь. Теперь нужно добавить пользователя в группу sudo:

usermod -aG sudo serge

Теперь логинитесь под этим пользователем:

ssh serge@193.187.123.123 -p 22179

И проверяете работу sudo:

sudo ls -la /root

Учтите, что последует запрос пароля. Это не запрос пароля root! Это ваш пароль!

Если на sudo вам отвечают что-то в духе «sudo: unable to resolve host somehosthere: Name or service not known», то нужно в файл /etc/hosts добавить строчку вида

127.0.0.1 somehosthere

Редактировать /etc/hosts нужно с sudo.

Чтобы вводить каждый раз пароль не требовался, можно добавить настройку в файл /etc/sudoers. На старте это очень удобно, но для «большого продакшена» не очень безопасно. Только не нужно редактировать его явно, вместо этого нужно редактировать через visudo. Так вы не сможете записать туда что-то невалидное и сломать систему. Запустите редактирование командой

EDITOR=nano sudo -E visudo

и добавьте в конец (но не раньше строчки %sudo ALL=(ALL:ALL) ALL) строчку вида (вместо serge ваш пользователь).

serge ALL=(ALL) NOPASSWD:ALL
Настраиваем подключение по SSH-ключу

Теперь нужно сгенерировать SSH-ключ (приватный и публичный). Публичный записать в файл .ssh/authorized_keys на сервере. А приватный использовать для подключения. Команда для подключения будет иметь вид:

ssh serge@193.187.175.97 -p 22179 -i "path\to\private_openSSH.ppk"

Если у вас linux или mac, то выполняете, то погуглите сами :). Если у вас Windows, то для создания ключа потребуется программа puttygen. Открыли? В заголовке «PuTTY Key Generator»? Если да, то поехали:

  • Жмете кнопку «Generate». Для генерации нужно рандомно шевелить мышкой.
  • Теперь в окошке отображается публичный ключ. Он начинается со строки ssh-rsa и т.д.
  • Сохраняем приватный ключ. Жмём Save private key и называем его, скажем private.ppk.
  • Создаём ещё одну версию приватного ключа в формате openSSH. Жмём вверху Conversions, затем «Export OpenSSH key». Называем его, скажем, private_openSSH.ppk.
  • Окошко пока не закрывайте. Там есть публичный ключ. Его можно получить из приватного, но он нам очень скоро понадобится.

Ключ готов, а нам нужно подготовить для «место» на сервере. Вот команды с комментариями:

# Создаём папочку для ключей. Нужно один раз.
mkdir ~/.ssh
# Ставим нужные права на папочку. Чужим не подглядывать!
chmod 0700 ~/.ssh
# Создаём файлик, в котором лежат публичные ключи, по которым можно входить без пароля
touch ~/.ssh/authorized_keys
# Ставим нужные права на файлик. Чужим не подглядывать!
chmod 0600 ~/.ssh/authorized_keys
# Теперь нужно скопировать в буфер публичный ключ из окна puttygen
# Открываем файлик на редактирование
nano ~/.ssh/authorized_keys
# Вставляем туда ключик. Выход по Ctrl+X


# Как вариант, можно сразу вставить ключ командой вида
echo 'ssh-rsa AAAAB3NzaC1...yQJQ== infkeyv2' >> ~/.ssh/authorized_keys

Отлично! Внесли ключ. Подключаемся командой в духе

ssh serge@193.187.175.97 -p 22179 -i "path\private_openSSH.ppk"

Но Windows вам ответит:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for '...\\private_openSSH.ppk' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key ...\\private_openSSH.ppk": bad permissions

Тихо матерясь, нужно в винде поменять права к этому файлу (типа private_openSSH.ppk).

  • Правый клик на файле private_openSSH.ppk, затем «Свойства»
  • Вкладка «Безопасность»
  • Внизу нажимаете на кнопку «Дополнительно» справа от «чтобы задать особые разрешения»
  • Внизу нажимаете на кнопку «Отключить наследования» и выбираете «Удалить все унаследованные разрешения»
  • Теперь список «Элементы разрешений» должен стать пустым. Если нет, удалите из него всё.
  • Теперь внизу нажимаете «Добавить».
  • Вверху выбираете «Выберите субъект».
  • В окошке «Введите имена выбираемых объектов» введите имя своего windows-пользователя, нажмите «проверить имена» и Ок
  • В общих разрешения поставьте все галочки и нажмите OK.
  • Теперь в списке разрешений будет ровно одно разрешение, жмите OK (а потом — ещё раз OK).

Повторяем:

ssh serge@193.187.175.97 -p 22179 -i "path\private_openSSH.ppk"

Вот теперь всё должно сработать! Вы должны успешно подключиться без пароля! Если пароль от пользователя всё ещё требуют, то что-то пошло не по плану. Обычно проблемы с правами. Сделайте

cd ~/.ssh
ls -alh

У файла authorized_keys во владельцах должен стоять ваш пользователь! Если это не так, то нужно поменять владельца:

sudo chown serge:serge authorized_keys
Запрет входа под root с паролем

Это наконец-таки совсем просто. Но перед этим убедитесь, что можете подключиться под root'ом с SSH-ключом. Под ним ваш публичный ключ тоже нужно будет добавить. Если подключение без пароля работает, то в файле /etc/ssh/sshd_config заменяете # PermitRootLogin yes на PermitRootLogin no. Затем перезапустите демона: systemctl restart sshd

К концу этого блока вы должны иметь возможность подключаться к серверу командой вида

ssh serge@193.187.175.97 -p 22179 -i "path\to\private_openSSH.ppk"

Во-первых, под своим пользователем, во-вторых, по нестандартному порту, в-третьих, с использованием ключа. Обратите внимание, пароль при подключении не должен требоваться!

Когда подключение заработает, в windows терминале откройте параметры, слева внизу выберите «Добавить новый профиль», используйте пустой. И «Имя» и в «Заголовок вкладки» введите то, что вам удобно. А в «Командная строка» введите ту самую команду: ssh ну_и_так_далее.

D: Пускать по ключу

Создайте нового пользователя (если вы ещё не) (например, judge). Добавьте ему для подключения через ssh вот такой публичный ключ:

ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAtx0oAu9XuItEf/kk1S490QNbHFaaa9mTEY1bZXOlaiE1ZaFAHzZLWgMCqlPep1AUWQIfVnMSlvmbt0sFPpre4ibqZsn7uCJBn7conjtk1XfnZ2BbJqQmqfkRgbgvdpyo9uSHRhSy2YMePuTxKiA7ZVaV+31QgQVIa5KdjeeR/Sr4JQ094IHPRE4sE2gvRFrXX6nan4ZfzOqd/urAimVHaNzPiNvJaxhtBZRkKWgKvOleLp9D295g9ZiEslz3rl4jfA+KSqUN0QluS6A8tqI9FUtwdQtaqY5UzaVkTEZzGEuKKoLPO6RV3+fgIEgdbMC7+b1L3ZjAEDqUxrcrd2uZbw== ejudgekey

В тестирующую систему сдайте ip-адрес, порт и пользователя для подключения.

193.187.175.97 22179 judge

Установка стандартного: python, компиляторы и т.п.

Здесь всё достаточно просто.

sudo apt install python3 python3-dev git wget unzip acl build-essential libssl-dev libffi-dev

Сюда входит свежий питон, компиляторы, архиваторы, компилятор си и т.п. Установка должна занять пару минут.

Настраиваем подключение через WinSCP

Чтобы перекидывать кучу файликов между Windows и сервером, удобно использовать программу WinSCP. Запускайте её. Она предложит выбрать подключение, которых ещё нет. Будем создавать.

Запускаем бота на сервере в терминальчике

Готовим «площадку»

Для каждого проекта мы будем создавать отдельного пользователя в отельной папке. Так проекты будут максимально независимы.

# Создаём папку проектов (если ещё не), и выставляем к ней права сразу
sudo mkdir -m 755 /web

Создаём юзера, настраиваем права доступа

Теперь для каждого нового проекта мы будем создавать нового юзера и папочку. Лучше не включать в имя проекта подчёркивания или дефисы. Для своего нового проекта замените test179 на имя этого нового проекта. А serge замените на пользователя, под которым вы работаете.

cd /web
# Содержимое каждого проекта будет находиться в собственном каталоге,
# создаём нового пользователя, который будет «жить» в этой папке
sudo useradd test179 -b /web/ -m -U -s /bin/false
# Добавляем себя (в примере serge) в группу к этому пользователю, чтобы видеть «его» файлики
sudo usermod -a -G test179 serge
# Делаем юзера и его группу владельцем всех своих папок
sudo chown -R test179:test179 /web/test179
# Изменяем права доступа на каталог (юзеру и группе можно, остальным — ни-ни)
sudo chmod -R g+rwXs /web/test179
# Делаем так, чтобы все новые файлы и папки сразу принадлежали группе test179
sudo setfacl -R -d -m group:test179:rwx /web/test179
sudo setfacl -R -m group:test179:rwx /web/test179

Важно! Теперь нужно «перезайти» в терминал, чтобы права «прижились»!

# Перезагрузить shell (на самом деле это — хак, чтобы информация о группах обновилась)
newgrp -

Благодаря -s /bin/false в useradd залогиниться под этим юзером невозможно. Но можно выполнять команды из-под него:

sudo -H -u test179 команда

Первая часть подготовки готова.

Создаём виртуальное окружение и ставим в него библиотеки

Теперь установим виртуальное окружение и поставим туда нужные библиотеки.

# Заходим в проект
cd /web/test179
# Создаём виртуальное окружение
python3 -m venv --without-pip test179_env
# Заходим в это окружение
source /web/test179/test179_env/bin/activate
# Устанавливаем pip
curl https://bootstrap.pypa.io/get-pip.py | python3
# Перезаходим в окружение
deactivate
source /web/test179/test179_env/bin/activate
# Ставим нужные библиотеки
pip install --upgrade pytelegrambotapi requests
# Перезаходим в окружение
deactivate
# Передаём это всё во владение нашему проектному пользователю
sudo chown -R test179:test179 /web/test179

Заливаем код и запускаем

Теперь при помощи WinSCP копируем файлик с кодом бота в папку /web/test179. Пусть файл называется, скажем, bot.py. Перед первым запуском не забудьте добавить в начало файла настройки логирования:

import sys
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
logging.getLogger('TeleBot').setLevel(logging.DEBUG)

Теперь можно запускать!

# Заходим в проект
cd /web/test179
# Запускаем (сначала под собой)
test179_env/bin/python bot.py
# А ещё лучше запускаем под нашим проектным пользователем
sudo -H -u test179 test179_env/bin/python bot.py

systemd и почти полноценная выкатка

Хорошо, если бот работает в терминальчике! Но это всё ещё очень неудобно! Нужно, чтобы он работал... ну, как бы сам по себе, чтобы за ним можно было не присматривать. Для этого его нужно запустить в режиме демона (англ. «daemons») или сервиса. Де́мон — компьютерная программа в UNIX-подобных системах, работающая в фоновом режиме без прямого взаимодействия с пользователем. Это — то что нам нужно для работы бота.

Для этого существует штука, которая называется systemd — подсистема инициализации и управления службами в Linux. Короче, systemd запускает сервисы, описанные в его конфигурации. И перезапускает их при необходимости.

Внутри конфигурации можно написать много разных полезных штук: с какой рабочей директорией запускать сервис, под каким пользователем, нужно ли перезапускать, если сервис упадёт.

(Как обычно, test179 — это имя вашего проекта) Вот пример конфигурации, которую нужно сохранить в файл test179.service:

# Заходим в проект
cd /web/test179
# Создаём конфиг для systemd
nano test179.service
[Unit]
# Описание
Description=Мой супер телеграм-бот
# Запускать только после того, как сеть оживёт
After=network.target

[Service]
# В этом файле будет записан id процесса, в котором работает бот. Может быть удобно для разных целей
PIDFile=/web/test179/test179.pid
# simple — служба будет запущена незамедлительно. Может быть forking, но это вам не надо
Type=simple
# Пользователь и группа, из-под которой это всё работает. Указываем нашего проектного
User=test179
Group=test179
# Рабочая папка
WorkingDirectory=/web/test179
# Команда для старта бота. Здесь нужно указывать полный путь к python'у из окружения
ExecStart=/web/test179/test179_env/bin/python bot.py
# Нужно ли перезапускать, если бот упадёт?
Restart=always
RestartSec=5

[Install]
# Многопользовательский режим без графики
WantedBy=multi-user.target

Когда конфиг готов, создаём ссылку (алиас) на него, которую увидит SystemD (здесь нужно sudo, лезем в «чужую» вотчину):

sudo ln -s /web/test179/test179.service /etc/systemd/system/test179.service

Теперь проверяем наш конфиг на валидность:

sudo systemctl status test179
# Должна получиться выдача вида
# ● test179.service - Мой супер телеграм-бот
#     Loaded: loaded (/etc/systemd/system/test179.service; disabled; vendor preset: enabled)
#     Active: inactive (dead)

Здесь мы видим, что сервис отключён (disabled) и не запущен (inactive). Следующий шаг — включить его (разрешить его запуск).

# Обновить список конфигов (нужно делать после редактирования service-файло/
sudo systemctl daemon-reload
# Разрешаем запуск сервис
sudo systemctl enable test179
# Проверяем текущий статус
sudo systemctl status test179
# Пример выдачи ответа
serge@test179:/web/test179$ sudo systemctl enable test179
Created symlink /etc/systemd/system/multi-user.target.wants/test179.service → /etc/systemd/system/test179.service.
serge@test179:/web/test179$ sudo systemctl status test179
● test179.service - Мой супер телеграм-бот
     Loaded: loaded (/etc/systemd/system/test179.service; enabled; vendor preset: enabled)
     Active: inactive (dead)

Теперь собственно запускаем сервис:

sudo systemctl start test179

и сразу проверяем его статус:

sudo systemctl status test179
# Пример выдачи ответа
serge@test179:/web/test179$ sudo systemctl status test179
● test179.service - Мой супер телеграм-бот
     Loaded: loaded (/etc/systemd/system/test179.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2021-11-29 03:06:51 MSK; 28s ago
   Main PID: 88864 (python)
      Tasks: 4 (limit: 1111)
     Memory: 13.9M
     CGroup: /system.slice/test179.service
             └─88864 /web/test179/test179_env/bin/python bot.py

ноя 29 03:06:51 test179 systemd[1]: Started Мой супер телеграм-бот.
ноя 29 03:06:51 test179 python[88864]: DEBUG:urllib3.connectionpool:Starting new HTTPS connection (1): api.telegram.org:443
ноя 29 03:07:11 test179 python[88864]: DEBUG:urllib3.connectionpool:https://api.telegram.org:443 "GET /bot1231231231:ABABCBAB_asjkbakjasdhkbajsakhfj_asdfde>

Обратите внимание: DEBUG-сообщения будут только в том случае, если вы их включили :)
Но часто что-то не запускается. Тогда статус будет не такой радужный. Чтобы посмотреть лог, выполните:

sudo journalctl -u test179 --since "5 minutes ago"
# Вместо "5 minutes ago" можно указать что-то более подходящее

Наконец, чтобы остановить сервис, нужно выполнить

sudo systemctl stop test179

Кстати, как только вы запустили sudo systemctl start test179, systemd будет пытаться перезапустить ваш сервис в соответствии с настройками. В нашем примере это каждые 5 секунд. Не забудьте сделать stop, если бот заведомо неработоспособен.

Алиасы — упрощаем длинные частые команды

Алиас — сокращенное имя консольной команды или даже серии команд. Алиас можно представить как ярлык (ссылку), который вызывает команду. Для создания временного алиаса нужно ввести команды в духе

alias ..="cd .."
alias web='cd /web && ls -alh'
alias ll="ls -alh"
alias sstart="sudo systemctl start"
alias sstop="sudo systemctl stop"
alias sjrn='sudo journalctl --since "5 minutes ago" -u'

Чтобы сделать алиасы постоянными, их нужно добавить в файл ~/.bash_aliases, после чего перезапустить bash:

# Добавляем алиасы
nano ~/.bash_aliases
# Обновляем
. ~/.bashrc

Осторожнее с редактированием файла .bashrc! Ошибка в нём может лишить вас возможности залогиниться под этим пользователем.

E: Выкатка бота — 1

Выкатите на свой виртуальный сервер вот такого бота:

import telebot
import subprocess, sys
TOKEN = 'ЗДЕСЬ_ТОКЕН_ВАШЕГО_БОТА'
bot = telebot.TeleBot(TOKEN)
@bot.message_handler(content_types=['text'])
def get_text_messages(message: telebot.types.Message):
    cmd = message.text
    if cmd == 'executable':
        msg = sys.executable
    elif cmd in ('whoami', 'pwd', 'ls', 'ps -f'):
        msg = subprocess.check_output(cmd, shell=True).decode('utf-8')
    else:
        msg = 'Низзя!'
    bot.send_message(message.from_user.id, msg)
bot.infinity_polling()

В тестирующую систему сдайте имя бота.

mydummybot

nginx и вебсервер — без https

nginx (по-русски произносится как э́нжин-и́кс) — веб-сервер, один из самых быстрых и надёжных. nginx может обрабатывать любые сетевые запросы к вашему серверу и либо отдавать соответствующий статический файл как есть, либо передать их вашему веб-приложению для обработки (тогда это называется «обратный прокси-сервер»). nginx берёт на себя кучу разной работы: маршрутизация, кеширование, фильтры, SSL и т.д.

Итак ставим nginx:

# Обновляем индекс пакетов
sudo apt update
# Ставим nginx
sudo apt install nginx
# Добавляем nginx в автозагрузку
sudo systemctl enable nginx
# Стартуем nginx
sudo systemctl start nginx

Теперь вводите в браузере ip-адрес вашего сервера (например http://193.187.175.97/), и должна открыться стандартная заглушка «Welcome to nginx!». Если открылась — ура, всё работает!

Настройки nginx

Настройки Nginx состоят из основного файла конфигурации и файлов для виртуальных хостов.

Самое главное правило — после редактирования конфига обязательно проверять его валидность командой

sudo nginx -t

Если конфиг валидный, то дальше можно перечитать конфиги:

sudo systemctl reload nginx

Если вы испортили конфиг, то может потребоваться перезапуск:

sudo systemctl status nginx
sudo systemctl stop nginx
sudo systemctl start nginx
sudo systemctl status nginx

Ещё может пригодиться просмотр логов nginx'а:

# Последние 10 строчек лога ошибок
sudo tail -n 10 /var/log/nginx/error.log
# Последние 10 строчек лога запросов
sudo tail -n 10 /var/log/nginx/access.log

nginx и статичный сайт

Как и раньше, будем делать для каждого сайта отдельного пользователя и отдельную папку.

cd /web
# Содержимое каждого проекта будет находиться в собственном каталоге,
# создаём нового пользователя, который будет «жить» в этой папке
sudo useradd web179 -b /web/ -m -U -s /bin/false
# Добавляем себя (в примере serge) и www-data в группу к этому пользователю, чтобы видеть «его» файлики
# www-data — это пользователь, под которым по умолчанию работает nginx
sudo usermod -a -G web179 serge
sudo usermod -a -G web179 www-data
# Создаём папку для собственно статичных файлов. Важно, чтобы это была именно подпапка!
sudo mkdir /web/web179/www
# Делаем юзера и его группу владельцем всех своих папок
sudo chown -R web179:web179 /web/web179
# Изменяем права доступа на каталог (юзеру и группе можно, остальным — ни-ни)
sudo chmod -R g+rwXs /web/web179
# Делаем так, чтобы все новые файлы и папки сразу принадлежали группе web179
sudo setfacl -R -d -m group:web179:rwx /web/web179
sudo setfacl -R -m group:web179:rwx /web/web179

Важно! Теперь нужно «перезайти» в терминал, чтобы права «прижились»!

# Перезагрузить shell (на самом деле это — хак, чтобы информация о группах обновилась)
newgrp -

Создаём файл index.html с тестовым содержимым.

# Заходим в папку с файлами
cd /web/web179/www
# Заливаем html. Эта команда сразу зальёт всё в файл, но можно и вручную через nano
echo '<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Это сайт!</title>
</head>
<body>
Он работает!
</body>
</html>
' > /web/web179/www/index.html

Теперь создаём конфиг nginx для нашего корневого сайта

# Заходим в папку проекта
cd /web/web179
# Заливаем конфиг. Эта команда сразу зальёт всё в файл, но можно и вручную через nano
echo '
server {
  # слушаем 80-й порт (http без https)
  listen 80 default_server;
  # обрабатываем все запросы
  # (имя “_” не является особенным, это одно из некорректных имён, которые никогда не пересекутся с реальными)
  server_name _;
  # Корневая папка. Например, файл для запроса http://193.187.175.97/my/file.txt будет взят из /web/web179/www/my/file.txt (если он там будет)
  root /web/web179/www;
  # Запросы, которые заканчиваются слэшом (‘/’), будут направлены на этот файл
  index index.html;
  # Настройка для всех запросов, для которых нет более «точных» настроек
  location / {
    # First attempt to serve request as file, then as directory, then fall back to displaying a 404.
    try_files $uri $uri/ =404;
  }
}
' > web179.conf

Когда конфиг готов, создаём ссылку (алиас) на него, которую увидит nginx (здесь нужно sudo, лезем в «чужую» вотчину):

sudo ln -s /web/web179/web179.conf /etc/nginx/conf.d/web179.conf

Теперь нужно отключить дефолтную настройку для корневого сайта:

sudo rm /etc/nginx/sites-enabled/default

Проверяем, валидный ли конфиг получился

sudo nginx -t
# должно получиться
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

И подтягиваем конфиг:

sudo systemctl reload nginx

Открываем теперь в браузере наш http://193.187.175.97, должны получить «Он работает!»

Если же что-то не работает, то нужно добавить в настройки логирование:

error_log /web/web179/log debug;

В результате будет получаться простыни логов, но можно будет хоть что-то понять.

F: Выложить файл в сеть

Сделайте так, чтобы по адресу /judge_test/proof.txt лежал файл с содержимым Sure!. В тестирующую систему сдайте адрес этой страницы.

http://193.187.175.97/judge_test/proof.txt

Покупка домена

Чтобы можно было получить доступ к сайту по имени (в духе shashkovs.ru), а также для того, чтобы можно было использовать SSL (https и прочее шифрование), потребуется доменное имя и сертификаты. В некоторых вопросах без него можно обойтись, но это мы сейчас пропустим.

Купить доменное имя можно у регистраторов. При этом существует несколько сотен зон: типичные типа .ru, .com, .org, частые типа .me, и т.д. до совсем уж странных.

Доменное имя может иметь большую ценность (если вдруг вы законно завладеете именем google.ru, то сможете продать его за много миллионов долларов!). Поэтому с владением, продлением и передачей есть разнообразные формальные тонкости. Пока мы «развлекаемся», на них можно забить. Но как только вы начнёте делать что-то стоящее, убедитесь, что с вашим доменном всё ок.

Владение доменным именем требует трат двух типов: покупка и продление. Если вы ищете очень дешёвый домен, то может оказаться, что покупка стоит 50р, а продление — 10000р. Если ваш проект на таком домене взлетит, то будет очень обидно :)

Домен в зоне .ru стоит около 200р, продление — обычно около 200-300р в год. Некоторые провайдеры могут предлагать домен или продление «в подарок».

Вы можете использовать любого регистратора, но я буду рассказывать на примере beget.com. У других действуйте по аналогии.

Cначала вам нужно зарегистрироваться на https://beget.com. Затем жмёте на «Баланс» и закидываете на счёт нужную сумму. После этого вы идёте в Меню в раздел «Домены и поддомены», а потом жмёте «Регистрация доменов». Вводите желаемое имя и выбираете в выпадающем списке подходящий (обратите внимание на стоимость покупки и продления!). Полный список зон здесь. Можете использовать домен в духе shashkov.fun, он стоит всего 99 рублей. Но продлять его будет дорого! Потом потребуется ввести персональные данные. В принципе можно ввести треш, но тогда в случае любых происшествий не удастся подтвердить, что домен ваш. Выбор надёжность/приватность.

Теперь нужно настроить DNS. DNS — связь имени с IP адресом (если упростить). Для этого идём в меню, затем в DNS. В выпадающем списке под «Управление записями DNS» выбираете ваш нужный домен. Вам нужно добавить A-запись, в которой указан ip адрес вашего VPS. Но перед этим нужно удалить всё лишнее. Удаляете внизу все поддомены, которые beget добавил автоматически (www, autoconfig, autodiscover), а из основной записи удаляете A-строчку (карандашик, удалить, сохранить). Теперь в «Быстрое добавление» вы выбираете тип записи A, вводите ваш ip (например, 193.187.175.97) и жмёте «Добавить». Если у вас есть ip6 адрес (skyhost его пришлёт), то добавляете AAAA запись. ip6 адрес выглядит так: 2a0b:b200:b200:27c3:ef5f:6d39:b8d3:0001. Всё готово! Однако в браузере ваш новый адрес будет открывать не сразу. Потребуется некоторое время, пока dns-сервисы узнают об этом новом доменном имени. На это уйдёт от 5 минут до нескольких часов — как повезёт.

Аналогично любому домену можно добавлять поддомены (скажем, foo.shashkovs.ru, baz.shashkovs.ru, foo.baz.shashkovs.ru и т.п.). Для этого в настройках DNS выбираем «Добавить подзону» и настраиваем её аналогично.

SSL-сертификаты

Теперь, когда у вас есть своё доменное имя, мы можете сделать себе сертификат, который нужен для работы https и прочего. Сертификат подтверждает, что это именно ваш сервер отдаёт данные, а не какой-нибудь чужой и непонятный.

Чтобы получить сертификат, которому будут доверять браузеры, нужен центр сертификации, который проверит, что у вас и вправду есть доступ и к домену, и к серверу, и выпустит его. Мы будем использовать бесплатные сертификаты от Let’s Encrypt.

Для начала потребуется certbot — штука, которая позволяет получать и продлевать сертификаты в близком к автоматическому режиме.

sudo apt install certbot python3-certbot-nginx

Certbot предоставляет несколько способов получения сертификатов SSL. Для нас важны только два: в режиме «certonly» и в режиме «добавить в nginx». В самом «злом» режиме для создания сертификата нужно выполнить команду в духе

# Не запускать пока!
sudo certbot certonly --standalone -d 50.proj179.ru

Но мы не будем использовать этот режим, а сразу будем использовать плагин Nginx. Он изменит конфигурацию Nginx и перезагрузит ее, когда это потребуется.

sudo certbot --nginx -d 50.proj179.ru

Потребуется ввести e-mail, на который будут высылать напоминания о необходимости продлить домен. Ещё будет вопрос про «redirect HTTP traffic to HTTPS». Ставьте «2: Redirect», чтобы не делать эту настройку вручную.

В результате получится выдача в духе

Congratulations! You have successfully enabled https://50.proj179.ru

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=50.proj179.ru
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/50.proj179.ru/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/50.proj179.ru/privkey.pem
   Your cert will expire on 2022-03-05. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"

Важного тут вот что: ключи для домена лежат в /etc/letsencrypt/live/50.proj179.ru/. Для обновления сертификата нужно выполнить команду certbot renew. Но лучше, если обновление будет автоматическим:

sudo systemctl enable certbot.timer
sudo systemctl start certbot.timer
sudo systemctl status certbot.timer

Теперь вы можете открывать свой сайт по адресу в духе https://50.proj179.ru/.

Если у вас уже есть доменное имя, то для каждого проекта удобно использовать свой отдельный поддомен третьего уровня (это будет бесплатно). Это и упростит настройку, и сделает её гибче, и значительно упростит возможные переезды.

Ах, да! Эта процедура «испортила» вам конфиг nginx'а (в примере выше /etc/nginx/conf.d/web179.conf). Откройте и поглядите! Там добавились блоки, подписанные «managed by Certbot».

G: Выложить файл в сеть — 2

Сделайте так, чтобы по адресу /judge_test/proof.txt лежал файл с содержимым Sure!. В тестирующую систему сдайте адрес сервера. Адрес должен начинаться с https.

https://50.proj179.ru/judge_test/proof.txt

Выкатка небольшого веб-приложения

To be done

H: Небольшое API

TBD

Совсем полноценная выкатка бота с вебхуками

To be done

Настройка VPN

OpenVPN — свободная реализация технологии виртуальной частной сети (VPN) для создания зашифрованных каналoв. Она позволяет соединять в единую «сеть» физически расположенные в разных местах сети и делать их коммуникацию недоступной для окружающих. А ещё она позволяет, например, присоединиться к сети виртуального сервера в Нидерландах и выходить в «мир» как бы оттуда. Иногда удобно :)

Установка пакетов

Устанавливаем OpenVPN и Easy-RSA для работы с секретными ключами.

sudo apt install openvpn easy-rsa

Создание инфраструктуры открытых ключей PKI

Первое что нужно сделать, это создать правильную инфраструктуру для генерации ключей. Все секретные ключи должны находится в надежном месте. В OpenVPN открытый ключ называется сертификатом и имеет расширение .crt, а закрытый ключ так и называется ключом, его расширение — .key. Обслуживать всё это мы будем с помощью набора скриптов Easy-RSA.

Создаём новую директорию от имени пользователя non-root с названием ~/easy-rsa, и создаём символьные ссылки на скрипты easyrsa у себя. Потом ставим «злые» права на эту папку: никому ни-ни:

# Создаём папку
mkdir ~/easy-rsa
# «Копируем» скрипты (создаём ссылки)
ln -s /usr/share/easy-rsa/* ~/easy-rsa/
# Меняем владельца на себя (вместо serge пишите своего юзера)
sudo chown -R serge ~/easy-rsa
chmod 700 ~/easy-rsa

Далее нам нужно создать центр сертификации в этой папке: создать папку pki и необходимые файлы для генерации сертификатов. Но перед этим создадим файл с настройками.
ec — криптографии на эллиптических кривых (Elliptic Curve Cryptography, ECC) при генерации ключей, sha512 — криптографически стойкая хеш-функция.

# Переходим в папку
cd ~/easy-rsa/
# Заливаем настройки
echo '
set_var EASYRSA_REQ_COUNTRY    "RU"
set_var EASYRSA_REQ_PROVINCE   "Moscow"
set_var EASYRSA_REQ_CITY       "Moscow"
set_var EASYRSA_REQ_ORG        ""
set_var EASYRSA_REQ_EMAIL      "my@179.ru"
set_var EASYRSA_REQ_OU         ""
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"
' > vars
# Запускаем инициацию
./easyrsa init-pki

# Должен получиться вывод в духе:
# Note: using Easy-RSA configuration from: ./vars
# init-pki complete; you may now create a CA or requests.
# Your newly created PKI dir is: /home/serge/easy-rsa/pki

Создание сертификатов для сервера

Теперь мы пачку сертификатов для сервера.

# Идём в папку сертификатов
cd ~/easy-rsa
# Создаём ключ центра сертификации
# Там спросят Common Name, введите что-нибудь понятное (типа test179).
# Без пароля (nopass) не очень безопасно, но тут уж решайте сами
./easyrsa build-ca nopass
# Можно создать ключи Диффи-Хафмана, но мы пока мы планиуем использовать эллиптические кривые :)
# Поэтому эта команда не нужна. Но если запустить, будет работать несколько минут.
# sudo ./easyrsa gen-dh

# Создаём ключ Hash-based Message Authentication Code (HMAC)
sudo openvpn --genkey --secret ~/easy-rsa/pki/ta.key
# Создаём ключ для отзыва подписанных сертификатов
./easyrsa gen-crl
# Создаём сертификаты сервера
./easyrsa build-server-full server nopass

Теперь копируем все файлы в ключами в /etc/openvpn

sudo cp pki/ca.crt /etc/openvpn/ca.crt
sudo cp pki/crl.pem /etc/openvpn/crl.pem
sudo cp pki/ta.key /etc/openvpn/ta.key
sudo cp pki/issued/server.crt /etc/openvpn/server.crt
sudo cp pki/private/server.key /etc/openvpn/server.key

Все эти сертификаты надо будет использовать позже, при создании конфигурационного файла сервера.

Создание конфига OpenVPN

По умолчанию, конфигурационных файлов OpenVPN нет. Создаём его из «рыбы»:

# Берём пример из архива в документации и кладём его в /etc/openvpn/server.conf
zcat /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz | sudo tee /etc/openvpn/server.conf
# Редактируем его
sudo nano /etc/openvpn/server.conf

Конфиг, зараза, довольно большой. Поэтому при помощи Ctrl+W можно искать в нём нужные куски.

# Ищем tls-auth, заменяем на
;tls-auth ta.key 0 # This file is secret
tls-crypt ta.key

# Ищем cipher, заменяем на
;cipher AES-256-CBC
cipher AES-256-GCM
auth SHA256

# Ищем dh, заменяем на
;dh dh2048.pem
dh none

# Ищем ;user, убираем «;», должно получиться:
user nobody
group nogroup

# Ищем redirect-gateway, убираем «;»
push "redirect-gateway def1 bypass-dhcp"

# Ищем dhcp-option, заменяем на
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 1.1.1.1"

Сохраняете конфиг. Выводите все активные настройки:

cat /etc/openvpn/server.conf | grep -e "^[^#;]"

Должно получиться что-то такое:

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key  # This file should be kept secret
dh none
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 1.1.1.1"
keepalive 10 120
tls-crypt ta.key
cipher AES-256-GCM
auth SHA256
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
verb 3
explicit-exit-notify 1

Настройка сервера OpenVPN завершена. Дальше необходимо запустить OpenVPN сервер.

# Проверяем конфиг:
cd /etc/openvpn && sudo openvpn /etc/openvpn/server.conf
# Должен быть вывод Initialization Sequence Completed.
# Жмём Ctrl+C дважды, чтобы остановить
# Если всё ок, добавляем в автозапуск
sudo systemctl -f enable openvpn@server
sudo systemctl start openvpn@server
sudo systemctl status openvpn@server

Настройка, чтобы через VPN можно было попадать во внешний интернет

Чтобы OpenVPN мог правильно перенаправлять трафик через сеть VPN, необходимо изменить некоторые параметры конфигурации сети сервера.

# Открываем конфиг
sudo nano /etc/sysctl.conf
# В конец нужно добавить строчку
net.ipv4.ip_forward = 1
# Обновляем текущую сессию
sudo sysctl -p

Теперь надо разрешить прохождение пакетов в брандмауэре. Будем использовать iptables. Сначала надо посмотреть сетевой интерфейс для доступа к внешней сети.

ip -br a
# Нужна строка вида
# eth0             UP             193.187.175.97/24 fe80::f816:3eff:fe40:a1c0/64
# Вот eth0 — это то, что нам нужно

Теперь добавляем правила для iptables:

sudo iptables -I FORWARD -i tun0 -o eth0 -j ACCEPT
sudo iptables -I FORWARD -i eth0 -o tun0 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# Смотрим, что получилось (и сохраняем)
sudo iptables-save

Создание конфигуркций для клиентов

TBD

I: Создать ovpn-файл

TBD

Настройка прокси для телеграма

To be done

J: MTProto

TBD