#+TITLE:     Install server from scratch (Rocky Linux)
#+SUBTITLE:  Quick reference card
#+AUTHOR:    Norets Alexey
#+EMAIL:     (concat "asnorets" at-sign "gmail.com")
#+DESCRIPTION: Rocky Linux from scratch
#+KEYWORDS:  Rocky linux, gunicorn + nginx + flask 
#+LANGUAGE:  ru
#+OPTIONS:   H:4 num:nil toc:2 p:t

* Установка сервера с нуля (gunicorn + nginx + flask) и настройка WireGuard

Данная инструкция предназначена для перенастройки сервера с сайтом и VPN.

** Создание и первоначальная настройка сервера

Создаем сервер. Заходим через SSH -> выходим -> копируем ключи на сервер:
#+begin_src shell
ssh <login>@<ip-address server>
exit
ssh-copy-id <login>@<ip-address server>
#+end_src

Теперь можем заходить по ключу (~/.ssh).

На сервере настраиваем SSH (запрет авторизации по паролю, запрет root по ssh):
#+begin_src shell
sudo vi /etc/ssh/sshd_config
#+end_src

Добавляем или изменяем строки:
#+begin_src conf
PermitRootLogin no
PasswordAuthentication no
#+end_src

Перезапускаем ssh:
#+begin_src shell
sudo systemctl restart sshd
#+end_src

** Установка необходимых пакетов

Обновляем систему:
#+begin_src shell
sudo dnf update
sudo dnf upgrade --refresh
#+end_src

Включаем CRB репозиторий:
#+begin_src shell
sudo dnf config-manager --set-enabled crb
sudo dnf install epel-release
#+end_src

Ставим необходимые пакеты:
#+begin_src shell
sudo dnf install zsh vim htop nginx git wget vim python3-pip python3-devel gcc emacs-nox -y
sudo pip3 install virtualenv
#+end_src

Устанавливаем [[https://github.com/robbyrussell/oh-my-zsh][oh-my-zsh]]:
#+begin_src shell
sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
#+end_src

Добавляем в ~~/.zshrc~:
#+begin_src conf
#  History
# хранить историю в указанном файле
export HISTFILE=~/.zsh_history
# максимальное число команд, хранимых в сеансе
export HISTSIZE=1000
export SAVEHIST=$HISTSIZE
# включить историю команд
setopt APPEND_HISTORY
# убрать повторяющиеся команды, пустые строки и пр.
setopt HIST_IGNORE_ALL_DUPS
setopt HIST_IGNORE_SPACE
setopt HIST_REDUCE_BLANKS

# alias ls='exa'
#+end_src

** Начинаем работу с проектом.

Создаем пользователя ~klintorg-www~:
#+begin_src shell
sudo mkdir /home/klintorg-www
sudo groupadd klintorg-www
sudo adduser -G nginx -g klintorg-www -d /home/klintorg-www klintorg-www --system --shell=/bin/false
#+end_src

~Временно~ выдаем права на папку ~klintorg-www~ и переходим в нее:
#+begin_src shell
sudo chmod -R 777 /home/klintorg-www
cd /home/klintorg-www
#+end_src

Клонируем проект:
#+begin_src shell
git clone https://github.com/Noretsa/klintorg.git
#+end_src

git запросит логин и пароль. Пароль необходимо создать, github -> settings -> Developer settings -> Personal access token -> Fine grained tokens. Дальше надо дать права токену, ну разберешься...

Переходим в папку проекта:
#+begin_src shell
cd klintorg
#+end_src

Создаем файл ~wsgi.py~:
#+begin_src shell
vim wsgi.py
#+end_src

В нем делаем так:
#+begin_src python
from __init__ import app

if __name__ == "__main__":
    app.run()
#+end_src

Создаем папку окружения и ставим зависимости проекта:
#+begin_src shell
virtualenv .klintorg
source .klintorg/bin/activate
pip install -r requirements.txt
pip install gunicorn
deactivate
#+end_src

Разрешаем в firewall порт 5000 и 8000 для тестов:
#+begin_src shell
sudo firewall-cmd --add-port=5000/tcp
sudo firewall-cmd --add-port=8000/tcp
#+end_src

Чтобы посмотреть лист открытых портов:
#+begin_src shell
sudo firewall-cmd --list-all
#+end_src



** Тестим проект

Можем протестировать проект:
#+begin_src shell
python __init__.py
#+end_src

С локального компьютера открываем браузер на странице http://<ip-address server>:5000.

Если все работает - начинаем тестировать gunicorn:
#+begin_src shell
gunicorn --bind 0.0.0.0:8000 wsgi:app
#+end_src

С локального компьютера открываем браузер на странице http://<ip-address server>:8000.

Если все работет гасим gunicorn (ctrl+c) и деактивируем окружение python:
#+begin_src shell
deactivate
#+end_src

Теперь для ~klintorg-www~ назначаем права:
#+begin_src shell
sudo chown -R klintorg-www:nginx /home/klintorg-www
sudo chmod -R 755 /home/klintorg-www
#+end_src

Отключаем ~SELinux~:
#+begin_src shell
sudo vim /etc/selinux/config
#+end_src

#+begin_src conf
SELINUX=disabled #enforcing
#+end_src

Перезагружаемся:
#+begin_src shell
sudo reboot now
#+end_src


** Настраиваем Flask Application

Мы протестировали что наш ~gunicorn~ работает с нашим приложением Flask. Теперь необходимо сделать так, чтобы он загружался при старте системы. Чтобы этого добиться, мы создадим ~systemd service~ и ~socket file~.

~Gunicorn socket~ будет создаваться при загрузке системы и прослушивать соединения. Когда придет коннект, ~systemd~ автоматически запустит ~Gunicorn~ процесс для поддержания соединения.

Начнем с создания ~systemd socket~ файла:
#+begin_src shell
sudo vim /etc/systemd/system/klintorg.socket
#+end_src

Внутри создаем следующие секции:
#+begin_src conf
[Unit]
Description=klintorg socket

[Socket]
ListenStream=/run/klintorg.sock

[Install]
WantedBy=sockets.target
#+end_src

Далее создаем ~systemd service~ файл. Имя этого файла должно совпадать с именем ~socket~ файла:
#+begin_src shell
sudo vim /etc/systemd/system/klintorg.service
#+end_src

В этом файле будет так:
#+begin_src conf
[Unit]
Description=klintorg daemon
Requires=klintorg.socket
After=network.target

[Service]
User=nginx
Group=nginx
WorkingDirectory=/home/klintorg-www/klintorg
ExecStart=/home/klintorg-www/klintorg/.klintorg/bin/gunicorn \
          --access-logfile - \
          --workers 3 \
          --bind unix:/run/klintorg.sock -m 007\
          wsgi:app

[Install]
WantedBy=multi-user.target
#+end_src

Перезапускаем демоны:
#+begin_src shell
sudo systemctl daemon-reload
#+end_src

Теперь запускаем ~Gunicorn socket~, когда он запустится, он стартанет наш ~gunicorn service~:
#+begin_src shell
sudo systemctl start klintorg.socket
sudo systemctl enable klintorg.socket
#+end_src

** Настраиваем NGINX

Создаем файл конфигурации:
#+begin_src shell
sudo vim /etc/nginx/conf.d/klintorg.conf
#+end_src

В файл добавляем следующие строки:
#+begin_src conf
server {
    listen 80;
    server_name server_domain_or_IP;

    location / {
        proxy_set_header Host $http_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_pass http://unix:/run/klintorg.sock;
    }
}
#+end_src

Теперь разрешаем Nginx доступ к соккету gunicorn:
#+begin_src shell
sudo semanage permissive -a httpd_t
#+end_src

Так же разрешаем Nginx доступ к папке проекта (???????):
#+begin_src shell
sudo chgrp -R nginx /usr/share/nginx/html/klintorg-www/klintorg/
#+end_src

Проверяем синтаксис:
#+begin_src shell
sudo nginx -t
#+end_src

Запускаем и добавляем в автостарт nginx:
#+begin_src shell
sudo systemctl start nginx
sudo systemctl enable nginx
#+end_src

Открываем 80 и 443 порты на firewall:
#+begin_src shell
sudo firewall-cmd --add-port=80/tcp --permanent
sudo firewall-cmd --add-port=443/tcp --permanent
sudo firewall-cmd --reload
#+end_src

** Настраиваем сертификат Let's Encrypt

Ставим ~certbot~:
#+begin_src shell
sudo dnf install certbot python3-certbot-nginx
#+end_src

Ставим ~snapd~ для автопродления сертификата:
#+begin_src shell
sudo dnf install snapd
sudo systemctl enable --now snapd.socket
sudo ln -s /var/lib/snapd/snap /snap
exit
#+end_src
Необходимо перезайти в систему!


Запускаем:
#+begin_src shell
sudo certbot --nginx
#+end_src

Проверяем обновляется ли:
#+begin_src shell
sudo certbot renew --dry-run
#+end_src

Проверяем что встало автообновление:
#+begin_src shell
sudo systemctl list-timers -all
#+end_src

** Wireguard
# https://www.digitalocean.com/community/tutorials/how-to-set-up-wireguard-on-rocky-linux-8

# Это более полезна оказалась: https://unix.stackexchange.com/questions/713798/rocky-linux-9-wireguard-masquerade-traffic-to-internet-not-working

# curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh
# sudo chmod +x wireguard-install.sh

Начальная установка:
#+begin_src shell
sudo dnf install elrepo-release epel-release
sudo dnf install wireguard-tools
#+end_src

Генерируем ключи:
#+begin_src shell
wg genkey | sudo tee /etc/wireguard/private.key
sudo chmod go= /etc/wireguard/private.key
sudo cat /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
#+end_src

Создаем файл конфигурации:
#+begin_src shell
sudo vim /etc/wireguard/wg0.conf
#+end_src

#+begin_src conf
[Interface]
Address = 10.8.0.1/24
# SaveConfig = true                                                                                              
ListenPort = 51820
PrivateKey = KM12oqlqAxKPyHXuOhL1XXcCeaGzYwAZ2pyYmHM8u2s=

PostUp = firewall-cmd --zone=public --add-masquerade; firewall-cmd --direct --add-rule ipv4 filter FORWARD 0 -i wg0 -o ens3 -j ACCEPT; firewall-cmd --direct --add-rule ipv4 nat POSTROUTING 0 -o ens3 -j MASQUERADE; firewall-cmd --add-port=51820/udp

PostDown = firewall-cmd --zone=public --remove-masquerade; firewall-cmd --direct --remove-rule ipv4 filter FORWARD 0 -i wg0 -o ens3 -j ACCEPT; firewall-cmd --direct --remove-rule ipv4 nat POSTROUTING 0 -o ens3 -j MASQUERADE; firewall-cmd --remove-port=51820/udp

[Peer]
PublicKey = ffLtSBKib0Wi7KnaEZXp7ZSWV+dswaPjPQHDYO1iiSQ=
AllowedIPs = 10.8.0.2/32
#+end_src

#+begin_src shell
sudo vim /etc/sysctl.conf
#+end_src
#+begin_src conf
net.ipv4.ip_forward=1
#+end_src
#+begin_src shell
sudo sysctl -p
#+end_src


# https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-firewalld-on-rocky-linux-9
Настраиваем Firewall (сначала делаем без этого, выше ссылка на инструкцию):
#+begin_src shell
firewall-cmd --permanent --direct --passthrough ipv4 -t nat -A POSTROUTING -s 10.8.0.0/24 -o enp0s3 -j MASQUERADE # это в первую очередь и проверяем, потом уже остальные
sudo firewall-cmd --zone=public --add-port=51830/udp --permanent
sudo firewall-cmd --zone=internal --add-interface=wg0 --permanent
sudo firewall-cmd --zone=public --add-rich-rule='rule family=ipv4 source address=10.8.0.0/24 masquerade' --permanent
# sudo firewall-cmd --zone=public --add-rich-rule='rule family=ipv6 source address=fd0d:86fa:c3bc::/64 masquerade' --permanent
sudo firewall-cmd --reload
#+end_src

Включаем ~Wireguard~:
#+begin_src shell
sudo systemctl enable wg-quick@wg0.service
sudo systemctl start wg-quick@wg0.service
#+end_src

*** Настройка клиента

Создаем папку в домашней директории:
#+begin_src shell
mkdir wg_norets
#+end_src

Создаем клиентскую пару ключей:
#+begin_src shell
wg genkey | tee /home/norets/wg_norets/norets_privatekey | wg pubkey | tee /home/norets/wg_norets/norets_publickey
#+end_src

Добавляем в конфиг WG:
#+begin_src shell
sudo vim /etc/wireguard/wg0.conf
#+end_src
#+begin_src conf
[Peer]
PublicKey = ll3VDt3gl81S54Lg9fX4wo2TylqfQLYZEB/63dxPgRg= # <norets_publickey>
AllowedIPs = 10.8.0.2/32
#+end_src

Перезапускаем сервис wireguard:
#+begin_src shell
sudo systemctl restart wg-quick@wg0
sudo systemctl status wg-quick@wg0
#+end_src

На клиенте создаем файл:
#+begin_src conf
[Interface]
PrivateKey = 2JgSg050VqNNgd+9rEt/NkhmuGTdzJNnzhNsDvIvSH8=  # <CLIENT-PRIVATE-KEY>
Address = 10.8.0.2/32
DNS = 8.8.8.8

[Peer]
PublicKey = cW4mpBGG3CBcW01I2HTSXpyxzId72Lh/EAF5Q7iS3RQ= # <SERVER-PUBKEY>
Endpoint = 88.210.3.57:51830
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 20
#+end_src


** OpenVPN
*** Server

Просто приложу команды:
#+begin_src shell
sudo -i
dnf install openvpn
dnf install easy-rsa
mkdir /etc/easy-rsa
cp -air /usr/share/easy-rsa/3.0.8/* /etc/easy-rsa/ # last ver. 3.0.8
cd /etc/easy-rsa/
./easyrsa init-pki
./easyrsa build-ca
./easyrsa gen-dh
./easyrsa build-server-full server nopass
openvpn --genkey secret /etc/easy-rsa/pki/ta.key
./easyrsa gen-crl
cp -rp /etc/easy-rsa/pki/{ca.crt,dh.pem,ta.key,crl.pem,issued,private} /etc/openvpn/server/
#+end_src

*** Clients
#+begin_src shell
./easyrsa build-client-full gentoo nopass # 1 client
./easyrsa build-client-full johndoe nopass # 2 client
mkdir /etc/openvpn/client/{gentoo,johndoe}
cp -rp /etc/easy-rsa/pki/{ca.crt,issued/gentoo.crt,private/gentoo.key} /etc/openvpn/client/gentoo
cp -rp /etc/easy-rsa/pki/{ca.crt,issued/johndoe.crt,private/johndoe.key} /etc/openvpn/client/johndoe/
cp /usr/share/doc/openvpn/sample/sample-config-files/server.conf /etc/openvpn/server/
emacs /etc/openvpn/server/server.conf
#+end_src

Конфиг сервера:
#+begin_src conf
port 1194
proto udp4
dev tun
ca ca.crt
cert issued/server.crt
key private/server.key  # This file should be kept secret
dh dh.pem
topology subnet
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 192.168.10.3"
client-to-client
keepalive 10 120
tls-auth ta.key 0 # This file is secret
cipher AES-256-CBC
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status /var/log/openvpn/openvpn-status.log
log-append  /var/log/openvpn/openvpn.log
verb 3
explicit-exit-notify 1
auth SHA512
#+end_src

#+begin_src shell
mkdir /var/log/openvpn/
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl --system
firewall-cmd --add-port=1194/udp --permanent
firewall-cmd --add-masquerade --permanent
ip route get 8.8.8.8 # Чтобы посмотреть имя сетевого интерфейса ~ens3~
firewall-cmd --permanent --direct --passthrough ipv4 -t nat -A POSTROUTING -s 10.8.0.0/24 -o ens3 -j MASQUERADE
firewall-cmd --reload
systemctl enable --now openvpn-server@server
tail /var/log/openvpn/openvpn.log
#+end_src

Конфиг клиентов ~(client_file.ovpn)~:
#+begin_src conf
client
tls-client
pull
dev tun
proto udp4
remote 192.168.60.19 1194
resolv-retry infinite
nobind
#user nobody
#group nogroup
persist-key
persist-tun
key-direction 1
remote-cert-tls server
auth-nocache
comp-lzo
verb 3
auth SHA512
tls-auth ta.key 1
ca ca.crt
cert gentoo.crt
key gentoo.key
#+end_src

Работать будет только в том случае, если все сертификаты лежат рядом с файлом .ovpn. Иначе надо сертификаты писать в файл, вот так:
#+begin_src conf
client
tls-client
pull
dev tun
proto udp4
remote 192.168.60.19 1194
resolv-retry infinite
nobind
#user nobody
#group nogroup
persist-key
persist-tun
key-direction 1
remote-cert-tls server
auth-nocache
comp-lzo
verb 3
auth SHA512
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
feb1af5407baa247d4e772c76aed6c75
...
-----END OpenVPN Static key V1-----
</tls-auth>
<ca>
-----BEGIN CERTIFICATE-----
MIIDTjCCAjagAwIBAgIUX0VQrHTgLDabUUIOAf7tD9cGp4YwDQYJKoZIhvcNAQEL
...
WA9BBk2shVWfR849Lmkep+GPyqHpU47dZAz37ARB2Gfu3w==
-----END CERTIFICATE-----
</ca>
<cert>
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
...
/7FvJaeLqmUHnvSs5eBlRZSgtOL19SCFkG0HXdnw3LtBaoHQXxgzOkDPW1+5
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+DI7kg6MsRoCs
...
6WdLcNtWKAcU294xJEZoOA8/
-----END PRIVATE KEY-----
</key>
#+end_src

Если работаем с OpenWRT - добавляем опцию (перед <tls-auth>) route-noexec.
После этого добавляем файл в OVPNClient и радуемся)
