#+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 @ exit ssh-copy-id @ #+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://:5000. Если все работает - начинаем тестировать gunicorn: #+begin_src shell gunicorn --bind 0.0.0.0:8000 wsgi:app #+end_src С локального компьютера открываем браузер на странице http://: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 Начальная установка: #+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 = MOJMpDrnsE5upIw9iqFQgkQnbsCAdQI17tL5mGuGRW8= 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 = 6I+0r4jXDsPQJqHEsrNHNu44ZMS/tDivDFL7/rVRxV8= 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 = l3tzC968A9at/1AvLaxRX9BmUj9kfGFql3Y0HEk35So= # 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= # Address = 10.8.0.2/32 DNS = 8.8.8.8 [Peer] PublicKey = cW4mpBGG3CBcW01I2HTSXpyxzId72Lh/EAF5Q7iS3RQ= # 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 -----BEGIN OpenVPN Static key V1----- feb1af5407baa247d4e772c76aed6c75 ... -----END OpenVPN Static key V1----- -----BEGIN CERTIFICATE----- MIIDTjCCAjagAwIBAgIUX0VQrHTgLDabUUIOAf7tD9cGp4YwDQYJKoZIhvcNAQEL ... WA9BBk2shVWfR849Lmkep+GPyqHpU47dZAz37ARB2Gfu3w== -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: ... /7FvJaeLqmUHnvSs5eBlRZSgtOL19SCFkG0HXdnw3LtBaoHQXxgzOkDPW1+5 -----END CERTIFICATE----- -----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+DI7kg6MsRoCs ... 6WdLcNtWKAcU294xJEZoOA8/ -----END PRIVATE KEY----- #+end_src Если работаем с OpenWRT - добавляем опцию (перед ) route-noexec. После этого добавляем файл в OVPNClient и радуемся)