Compare commits
10 Commits
0b3e3b291d
...
966df8cc40
| Author | SHA1 | Date | |
|---|---|---|---|
| 966df8cc40 | |||
| d7b82854d4 | |||
| 5479fceff1 | |||
| c59c2fa34d | |||
| 70940720ad | |||
| 3a0138704a | |||
| 44958d77dc | |||
| 64fba789d0 | |||
| 6d4f77a92a | |||
| 99681d0103 |
594
#README.org#
Normal file
594
#README.org#
Normal file
@ -0,0 +1,594 @@
|
|||||||
|
#+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
|
||||||
|
|
||||||
|
Начальная установка:
|
||||||
|
#+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= # <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 и радуемся)
|
||||||
@ -333,6 +333,9 @@ sudo systemctl list-timers -all
|
|||||||
|
|
||||||
# Это более полезна оказалась: https://unix.stackexchange.com/questions/713798/rocky-linux-9-wireguard-masquerade-traffic-to-internet-not-working
|
# Это более полезна оказалась: 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
|
#+begin_src shell
|
||||||
sudo dnf install elrepo-release epel-release
|
sudo dnf install elrepo-release epel-release
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
from flask import Flask, render_template
|
from flask import Flask, render_template
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
app = Flask(__name__, static_folder='static', static_url_path='')
|
app = Flask(__name__, static_folder='static', static_url_path='')
|
||||||
@ -10,6 +11,7 @@ db = SQLAlchemy(app)
|
|||||||
|
|
||||||
class Product(db.Model):
|
class Product(db.Model):
|
||||||
"""Class for products."""
|
"""Class for products."""
|
||||||
|
"""another string"""
|
||||||
|
|
||||||
id = db.Column(db.Integer(), primary_key=True)
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
name = db.Column(db.String(length=50), nullable=False, unique=True)
|
name = db.Column(db.String(length=50), nullable=False, unique=True)
|
||||||
@ -29,6 +31,11 @@ menu = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_now():
|
||||||
|
return {'now': datetime.utcnow()}
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route("/")
|
||||||
@app.route("/home")
|
@app.route("/home")
|
||||||
def home():
|
def home():
|
||||||
|
|||||||
BIN
product.db
BIN
product.db
Binary file not shown.
@ -1,7 +1,7 @@
|
|||||||
click==7.1.2
|
click==7.1.2
|
||||||
Flask==1.1.2
|
Flask==1.1.2
|
||||||
Flask-SQLAlchemy==2.5.1
|
Flask-SQLAlchemy==2.5.1
|
||||||
greenlet==1.1.2
|
greenlet>=1.1.2
|
||||||
itsdangerous==1.1.0
|
itsdangerous==1.1.0
|
||||||
Jinja2==2.11.3
|
Jinja2==2.11.3
|
||||||
MarkupSafe==1.1.1
|
MarkupSafe==1.1.1
|
||||||
|
|||||||
@ -107,12 +107,12 @@
|
|||||||
<div itemscope itemtype="http://schema.org/Product">
|
<div itemscope itemtype="http://schema.org/Product">
|
||||||
<div itemprop="name"><h5 class="card-title text-warning">1С: Бухгалтерия. Базовая версия электронная поставка</h5></div><br/>
|
<div itemprop="name"><h5 class="card-title text-warning">1С: Бухгалтерия. Базовая версия электронная поставка</h5></div><br/>
|
||||||
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
|
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
|
||||||
<meta itemprop="price" content="3300.00">
|
<meta itemprop="price" content="4000.00">
|
||||||
<meta itemprop="priceCurrency" content="RUB">
|
<meta itemprop="priceCurrency" content="RUB">
|
||||||
<link itemprop="availability" href="http://schema.org/InStock">
|
<link itemprop="availability" href="http://schema.org/InStock">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">3 300 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">4 000 ₽</h4><br/>
|
||||||
<div itemprop="description"><p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p></div>
|
<div itemprop="description"><p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p></div>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/buhv8/vyberite-svoyu-1s-bukhgalteriyu-8/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/buhv8/vyberite-svoyu-1s-bukhgalteriyu-8/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
@ -127,12 +127,12 @@
|
|||||||
<div itemscope itemtype="http://schema.org/Product">
|
<div itemscope itemtype="http://schema.org/Product">
|
||||||
<div itemprop="name"><h5 class="card-title text-warning">1С: Бухгалтерия ПРОФ. Электронная поставка</h5></div><br/>
|
<div itemprop="name"><h5 class="card-title text-warning">1С: Бухгалтерия ПРОФ. Электронная поставка</h5></div><br/>
|
||||||
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
|
<div itemprop="offers" itemscope itemtype="http://schema.org/Offer">
|
||||||
<meta itemprop="price" content="13000.00">
|
<meta itemprop="price" content="17600.00">
|
||||||
<meta itemprop="priceCurrency" content="RUB">
|
<meta itemprop="priceCurrency" content="RUB">
|
||||||
<link itemprop="availability" href="http://schema.org/InStock">
|
<link itemprop="availability" href="http://schema.org/InStock">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">13 000 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">17 600 ₽</h4><br/>
|
||||||
<div itemprop="description"><p class="card-text">Решение для стабильного и растущего бизнеса.
|
<div itemprop="description"><p class="card-text">Решение для стабильного и растущего бизнеса.
|
||||||
Позволяет вести несколько организаций в одной программе.</p></div><br/>
|
Позволяет вести несколько организаций в одной программе.</p></div><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
|
|||||||
@ -35,7 +35,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">ИТС ТЕХНО (КП Базовый)</h5><br/>
|
<h5 class="card-title text-warning">ИТС ТЕХНО (КП Базовый)</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">19 584 ₽</h4><br/><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">22 320 ₽</h4><br/><br/>
|
||||||
<p class="card-text">Доступ к обновлениям и сервисам 1С:ИТС для коммерческих предприятий. Минимальный тариф для обеспечения официальной поддержки программных продуктов «1С:Предприятие» ПРОФ версий</p><br/>
|
<p class="card-text">Доступ к обновлениям и сервисам 1С:ИТС для коммерческих предприятий. Минимальный тариф для обеспечения официальной поддержки программных продуктов «1С:Предприятие» ПРОФ версий</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/its/tarify/its-tekhno/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/its/tarify/its-tekhno/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">ИТС ПРОФ (КП ПРОФ)</h5><br/>
|
<h5 class="card-title text-warning">ИТС ПРОФ (КП ПРОФ)</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">46 368 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">52 860 ₽</h4><br/>
|
||||||
<p class="card-text">Доступ к обновлениям, консультациям, сервисам 1С:ИТС для коммерческих предприятий. Включает услуги партнеров по регулярному обновлению программных продуктов «1С:Предприятие» и информационно-методическую поддержку бухгалтеров, кадровиков, руководителей и IT-специалистов.</p><br/>
|
<p class="card-text">Доступ к обновлениям, консультациям, сервисам 1С:ИТС для коммерческих предприятий. Включает услуги партнеров по регулярному обновлению программных продуктов «1С:Предприятие» и информационно-методическую поддержку бухгалтеров, кадровиков, руководителей и IT-специалистов.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/its/tarify/its-prof/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/its/tarify/its-prof/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
|
|||||||
@ -94,7 +94,7 @@
|
|||||||
<a href="https://wa.me/79096861756"><i class="bi bi-whatsapp"></i> Написать в Whatsapp</a>
|
<a href="https://wa.me/79096861756"><i class="bi bi-whatsapp"></i> Написать в Whatsapp</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="tg://resolve?domain=@TanyaPetrovaa"><i class="bi bi-telegram"></i> Написать в Telegram</a>
|
<a href="tg://resolve?domain=@tatyanapetrovaa"><i class="bi bi-telegram"></i> Написать в Telegram</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="mailto:manager@klintorg.ru"><i class="bi bi-envelope"></i> manager@klintorg.ru</a>
|
<a href="mailto:manager@klintorg.ru"><i class="bi bi-envelope"></i> manager@klintorg.ru</a>
|
||||||
@ -137,7 +137,7 @@
|
|||||||
<a href="https://wa.me/79096861756"><i class="bi bi-whatsapp"></i> Написать в Whatsapp</a>
|
<a href="https://wa.me/79096861756"><i class="bi bi-whatsapp"></i> Написать в Whatsapp</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="tg://resolve?domain=@TanyaPetrovaa"><i class="bi bi-telegram"></i> Написать в Telegram</a>
|
<a href="tg://resolve?domain=@tatyanapetrovaa"><i class="bi bi-telegram"></i> Написать в Telegram</a>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<a href="mailto:manager@klintorg.ru"><i class="bi bi-envelope"></i> manager@klintorg.ru</a>
|
<a href="mailto:manager@klintorg.ru"><i class="bi bi-envelope"></i> manager@klintorg.ru</a>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
|
|
||||||
<!-- Copyright -->
|
<!-- Copyright -->
|
||||||
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.2);">
|
<div class="text-center p-3" style="background-color: rgba(0, 0, 0, 0.2);">
|
||||||
© 2021 Copyright:
|
© {{ now.year }} Copyright:
|
||||||
<a class="text-dark" href="http://klintorg.ru">klintorg.ru</a>
|
<a class="text-dark" href="http://klintorg.ru">klintorg.ru</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Copyright -->
|
<!-- Copyright -->
|
||||||
|
|||||||
@ -115,7 +115,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С: Розница. Базовая версия электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С: Розница. Базовая версия электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">3 300 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">4 000 ₽</h4><br/>
|
||||||
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p><br/>
|
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/retail/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/retail/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С: Розница. ПРОФ электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С: Розница. ПРОФ электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">13 000 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">17 600 ₽</h4><br/>
|
||||||
<p class="card-text">Автоматизирует торговую деятельность,поддерживает подключение торгового оборудования, настраивается индивидуально под любую торговую точку.</p><br/>
|
<p class="card-text">Автоматизирует торговую деятельность,поддерживает подключение торгового оборудования, настраивается индивидуально под любую торговую точку.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/retail/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/retail/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
|
|||||||
@ -115,7 +115,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С:Управление торговлей. Базовая версия электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С:Управление торговлей. Базовая версия электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">7 400 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">8 200 ₽</h4><br/>
|
||||||
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p><br/>
|
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/trade/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/trade/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С:Управление торговлей. ПРОФ электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С:Управление торговлей. ПРОФ электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">22 600 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">30 500 ₽</h4><br/>
|
||||||
<p class="card-text">Решение для стабильного и растущего бизнеса.
|
<p class="card-text">Решение для стабильного и растущего бизнеса.
|
||||||
Позволяет вести несколько организаций в одной программе. Программа для автоматизации задач оперативного и управленческого учета, анализа и планирования торговых операций.</p><br/>
|
Позволяет вести несколько организаций в одной программе. Программа для автоматизации задач оперативного и управленческого учета, анализа и планирования торговых операций.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
|
|||||||
@ -115,7 +115,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С:Зарплата и управление персоналом. Базовая версия электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С:Зарплата и управление персоналом. Базовая версия электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">7 400 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">9 100 ₽</h4><br/>
|
||||||
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p>
|
<p class="card-text">Универсальное решение для небольших организаций, в которых с программой работает один сотрудник и которым не требуется доработка типовой конфигурации.</p>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
<a href="https://v8.1c.ru/hrm/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
<a href="https://v8.1c.ru/hrm/" class="btn btn-outline-secondary my-2" role="button" aria-disabled="false" target="_blank">Подробнее на сайте 1С</a>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<div class="card h-100 shadow">
|
<div class="card h-100 shadow">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title text-warning">1С:Зарплата и управление персоналом. ПРОФ электронная поставка</h5><br/>
|
<h5 class="card-title text-warning">1С:Зарплата и управление персоналом. ПРОФ электронная поставка</h5><br/>
|
||||||
<h4 class="card-subtitle mb-2 fw-bold">22 600 ₽</h4><br/>
|
<h4 class="card-subtitle mb-2 fw-bold">30 500 ₽</h4><br/>
|
||||||
<p class="card-text">Решение для стабильного и растущего бизнеса.
|
<p class="card-text">Решение для стабильного и растущего бизнеса.
|
||||||
Позволяет вести несколько организаций в одной программе.</p><br/>
|
Позволяет вести несколько организаций в одной программе.</p><br/>
|
||||||
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
<button type="button" class="btn btn-warning my-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Заказать</button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user