Compare commits
104 Commits
92f77aceca
...
bunkerweb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
317e3e215e | ||
|
|
4f999094f3 | ||
|
|
5e32af0148 | ||
|
|
6ff9d67909 | ||
|
|
af9e6bfb82 | ||
|
|
e0419fea4b | ||
|
|
3cc428df43 | ||
|
|
9d1afcdf28 | ||
|
|
adef1a98bb | ||
|
|
3263dbecab | ||
|
|
3c5a5924d6 | ||
|
|
8b911372af | ||
|
|
a3888d10b4 | ||
|
|
8add078e7c | ||
|
|
54f549db62 | ||
|
|
fd67d9c546 | ||
|
|
86bf9fccf5 | ||
|
|
f64f034b7b | ||
|
|
dae9aca295 | ||
|
|
592b954a9f | ||
|
|
4b023ea671 | ||
|
|
4cb55905cc | ||
|
|
d76624ff43 | ||
|
|
27b237a3c7 | ||
|
|
5349d46d71 | ||
|
|
75df7a2554 | ||
|
|
479a65e0dd | ||
|
|
aae561716c | ||
|
|
8a2ec261f5 | ||
|
|
ec4bb73609 | ||
|
|
e37e8a0d1e | ||
|
|
f398decba9 | ||
|
|
ae8b90d66e | ||
|
|
5610859f17 | ||
|
|
598c9abdfb | ||
|
|
5d461cc39b | ||
|
|
8b2c076e2e | ||
|
|
f44fe71c28 | ||
|
|
7e9f0f1074 | ||
|
|
be9c2de988 | ||
|
|
f433895670 | ||
|
|
e2c8835b6b | ||
|
|
751814c48a | ||
|
|
113cd37b9d | ||
|
|
ce83ca97a9 | ||
|
|
bb547d1d9a | ||
|
|
fd667cd08b | ||
|
|
46fb25bcc0 | ||
|
|
bd56dcf5f5 | ||
|
|
cc59572a59 | ||
|
|
bf9de36753 | ||
|
|
56b3c3e5c9 | ||
|
|
c8b0f25247 | ||
|
|
f0086903a3 | ||
|
|
93ac9a2d5d | ||
|
|
08e5b49cab | ||
|
|
4be77a30e1 | ||
|
|
9eea39db23 | ||
|
|
e621c84780 | ||
|
|
ec2e8ca836 | ||
|
|
2b1157b0aa | ||
|
|
e991cf4797 | ||
|
|
66bb1323a9 | ||
|
|
e4624d9398 | ||
|
|
b7e404e18c | ||
|
|
316ca0e292 | ||
|
|
6e7af9ea42 | ||
|
|
06fa9cb9c2 | ||
|
|
93ccae3f18 | ||
|
|
14af530339 | ||
|
|
57594e1a76 | ||
|
|
c25c8d8f64 | ||
|
|
b29a369515 | ||
|
|
7f3b5fdd27 | ||
|
|
221fe29cf0 | ||
|
|
f3b9d33016 | ||
|
|
2f91eee76d | ||
|
|
66e574dd33 | ||
|
|
8e2a9e1f42 | ||
|
|
f01015c05d | ||
|
|
60eac545d6 | ||
|
|
95a0e87271 | ||
|
|
4c51952ee3 | ||
|
|
7402364d0b | ||
|
|
74d516f2ca | ||
|
|
7f969cf6bb | ||
|
|
f18ea4c808 | ||
|
|
dba200787f | ||
|
|
56fab11941 | ||
|
|
62eb67af03 | ||
|
|
6bd321a1da | ||
|
|
5443ea44dd | ||
|
|
9036a02b5b | ||
|
|
c0efc35d34 | ||
|
|
0ecf0ee925 | ||
|
|
645cd8386a | ||
|
|
5067d35524 | ||
|
|
c572522f43 | ||
|
|
d3f7451c9b | ||
|
|
a2988a71d7 | ||
|
|
455223af4b | ||
|
|
4a10c586e1 | ||
|
|
4905975d79 | ||
|
|
d0da95dfc5 |
32
CHANGELOG.md
@@ -2,6 +2,38 @@
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
## [1.9.6.rpm] - Release
|
||||
|
||||
- Fix error on all web and mail domains after Apache 2.4.64 update
|
||||
- Fix error on local php installation and extension activation
|
||||
- Added templates for nginx mod_rewrite activation
|
||||
- Added nginx with mod_rewrite
|
||||
- Fixed database size usage and disk usage output on the info pages
|
||||
- Fixed installation of panel without PHP-FPM
|
||||
- Fixed mod_php, fcgid, fcgi mode
|
||||
|
||||
## [1.9.5.rpm] - Release
|
||||
|
||||
- Added support installation of alternative php not only remi
|
||||
- Fixed separate edition of php.ini in multiphp mode
|
||||
- Added usemirrorclamav for install script for uieng Russian mirror for Clamav databases
|
||||
- Added devel mode of installation for installing not from github by default. With this parameter installation will be from devel repo dev.brepo.ru
|
||||
- Fixed memory calculation in service list
|
||||
|
||||
## [1.9.4.rpm] - Release
|
||||
|
||||
- Fixed sha-512 auth in hestiacp
|
||||
- Added quota support for rpm based os
|
||||
|
||||
## [1.9.2.rpm] - Release
|
||||
|
||||
- Forked from 1.8.6 alpha and reworked for rpm based systems support
|
||||
- Added passenger support (https://hestiadocs.brepo.ru/docs/extensions/extended-modules.html#passenger-manager)
|
||||
- Added unified proxy templates support (https://hestiadocs.brepo.ru/docs/user-guide/web-domains.html#шаблоны-прокси)
|
||||
- Added php-cli-selector (https://hestiadocs.brepo.ru/docs/extensions/php-cli-selector.html#php-cli-selector)
|
||||
- Added alternative extensions support (https://hestiadocs.brepo.ru/docs/extensions/php-cli-selector.html#php-cli-selector)
|
||||
- Added russian documentation (https://hestiadocs.brepo.ru/docs/introduction/getting-started.html)
|
||||
|
||||
## [1.8.6] - Alpha release
|
||||
|
||||
- Added rpm systems support
|
||||
|
||||
97
README.de.md
Normal file
@@ -0,0 +1,97 @@
|
||||
<div align="center">
|
||||
|
||||
# [Hestia Control Panel (RPM-Edition)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## Leistungsstarkes und schlankes Serververwaltungspanel für moderne Hosting-Umgebungen
|
||||
|
||||
**Stabile Version:** 1.9.5 (RPM) |
|
||||
[RPM-Edition](https://hestiadocs.brepo.ru) |
|
||||
[Originalprojekt für Ubuntu/Debian](https://hestiacp.com) |
|
||||
[Änderungsprotokoll](/CHANGELOG.md) |
|
||||
[Support-Forum](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
Die Hestia Control Panel (RPM-Edition) wird von einem unabhängigen Team für RPM-basierte Betriebssysteme entwickelt. Durch Anpassungen nach dem Fork des Originalprojekts ist eine direkte Synchronisation mit der Ubuntu/Debian-Version nicht möglich. Bitte melden Sie Probleme direkt an dieses Projekt.
|
||||
|
||||
## **Willkommen!**
|
||||
|
||||
Hestia bietet Administratoren eine intuitive Weboberfläche und CLI zur zentralisierten Verwaltung von Webdomains, E-Mail-Konten, DNS-Zonen und Datenbanken – ohne manuelle Konfiguration einzelner Komponenten.
|
||||
|
||||
## Funktionen & Dienste
|
||||
|
||||
- Apache2 & NGINX mit PHP-FPM
|
||||
- Mehrere PHP-Versionen (7.4[EOL](https://www.php.net/supported-versions.php)–8.3, Standard 8.2 aus Remi-Repo + Custom Builds)
|
||||
- DNS-Server (Bind)
|
||||
- E-Mail-Services mit Viren-/Spam-Schutz (ClamAV, SpamAssassin, Roundcube)
|
||||
- MariaDB/MySQL & PostgreSQL Datenbanken
|
||||
- Let's Encrypt SSL-Unterstützung
|
||||
- Firewall mit Brute-Force-Schutz (iptables, fail2ban, ipset)
|
||||
|
||||
## Unterstützte Betriebssysteme
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**Hinweise:**
|
||||
|
||||
- Keine Unterstützung für 32-Bit-Systeme!
|
||||
- Bei OpenVZ 7 oder älter können DNS/Firewall-Probleme auftreten – wir empfehlen KVM/LXC-basierte Virtualisierung.
|
||||
|
||||
## Installation
|
||||
|
||||
**Wichtig:** Frische OS-Installation erforderlich!
|
||||
|
||||
### Schritt 1: Anmeldung
|
||||
|
||||
Als **root** per SSH anmelden:
|
||||
|
||||
```bash
|
||||
ssh root@Ihr-Server
|
||||
```
|
||||
|
||||
### Schritt 2: Installationsskript herunterladen
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### Schritt 3: Ausführung
|
||||
|
||||
Skript mit Berechtigungen ausführen:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
### Custom Installation
|
||||
|
||||
Optionen anzeigen:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## Updates
|
||||
|
||||
Automatische Updates sind standardmäßig aktiviert (**Server-Einstellungen > Updates**). Manuelles Update:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## Support
|
||||
|
||||
- Probleme mit RPM-Edition: [GitHub Issues](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- Originalversion: [Hauptrepository](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## Lizenz
|
||||
|
||||
Hestia Control Panel ist unter der [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE)-Lizenz lizenziert und basiert auf [VestaCP](https://vestacp.com/).
|
||||
109
README.en.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<div align="center">
|
||||
|
||||
# [Hestia Control Panel (RPM Edition)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## A lightweight and powerful server control panel for modern web hosting environments
|
||||
|
||||
**Stable Version:** 1.9.5 (RPM) |
|
||||
[RPM Edition](https://hestiadocs.brepo.ru) |
|
||||
[Original Ubuntu/Debian Project](https://hestiacp.com) |
|
||||
[Changelog](/CHANGELOG.md) |
|
||||
[Support Forum](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
Hestia Control Panel (RPM Edition) is maintained and developed by a separate team focused on RPM-based operating systems. Since forking from the original project, this edition has incorporated changes that prevent direct syncing with upstream updates from the Ubuntu/Debian version (not all features are relevant for RPM systems). Therefore, found issues should be reported specifically to this project.
|
||||
|
||||
Below is the general panel description.
|
||||
|
||||
## **Welcome!**
|
||||
|
||||
Hestia Control Panel aims to provide administrators with an easy-to-use web interface and CLI for quickly deploying and managing web domains, email accounts, DNS zones, and databases through a centralized panel - eliminating the need for manual configuration of individual components.
|
||||
|
||||
## Features & Services
|
||||
|
||||
- Apache2 & NGINX with PHP-FPM
|
||||
- Multiple PHP versions (7.4[EOL](https://www.php.net/supported-versions.php) - 8.3, 8.2 default via Remi repo + custom PHP builds)
|
||||
- DNS Server (Bind)
|
||||
- Email services with antivirus/spam protection & webmail (POP/IMAP/SMTP, ClamAV, SpamAssassin, Sieve, Roundcube)
|
||||
- MariaDB/MySQL & PostgreSQL databases
|
||||
- Let's Encrypt SSL support
|
||||
- Firewall with brute-force protection & IP management (iptables, fail2ban, ipset).
|
||||
|
||||
## Supported OS
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**NOTES:**
|
||||
|
||||
- HestiaCP does not support 32-bit OS!
|
||||
- HestiaCP combined with OpenVZ 7 or earlier may have DNS/firewall issues. For VPS, we strongly recommend KVM/LXC-based virtualization.
|
||||
|
||||
## Installing Hestia Control Panel
|
||||
|
||||
- **NOTE:** HestiaCP must be installed on a fresh OS for proper functionality.
|
||||
|
||||
While we strive to make installation and usage intuitive, basic Linux server setup knowledge is assumed.
|
||||
|
||||
### Step 1: Log in
|
||||
|
||||
Login as **root** or a superuser via SSH:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
```
|
||||
|
||||
### Step 2: Download
|
||||
|
||||
Get the latest installer script:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### Step 3: Execute
|
||||
|
||||
Run the script and follow on-screen instructions:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
Upon completion, you'll receive a welcome email (if configured) and login details.
|
||||
|
||||
### Custom Installation
|
||||
|
||||
Use flags to select specific components. View options with:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## Updating Existing Installations
|
||||
|
||||
Automatic updates are enabled by default (managed via **Server Settings > Updates**). Manual updates:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## Issues & Support
|
||||
|
||||
- For RPM edition issues: [Create GitHub Issue](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- Original Debian/Ubuntu version: [Original Repository](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## Copyright
|
||||
|
||||
Original copyrights belong to [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## License
|
||||
|
||||
Hestia Control Panel is licensed under [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) and based on [VestaCP](https://vestacp.com/).
|
||||
99
README.es.md
Normal file
@@ -0,0 +1,99 @@
|
||||
<div align="center">
|
||||
|
||||
# [Panel de Control Hestia (Edición RPM)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## Panel de servidor ligero y potente para entornos modernos de alojamiento web
|
||||
|
||||
**Versión estable:** 1.9.5 (RPM) |
|
||||
[Edición RPM](https://hestiadocs.brepo.ru) |
|
||||
[Proyecto original para Ubuntu/Debian](https://hestiacp.com) |
|
||||
[Registro de cambios](/CHANGELOG.md) |
|
||||
[Foro de soporte](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
El Panel de Control Hestia (Edición RPM) es mantenido por un equipo independiente especializado en sistemas basados en RPM. Debido a cambios implementados tras la bifurcación del proyecto original, esta versión no puede sincronizarse directamente con las actualizaciones de Ubuntu/Debian. Reporte los problemas directamente a este proyecto.
|
||||
|
||||
## **¡Bienvenido!**
|
||||
|
||||
Hestia ofrece una interfaz web intuitiva y CLI para implementar y gestionar dominios web, cuentas de correo, zonas DNS y bases de datos de forma centralizada, sin configuración manual de componentes individuales.
|
||||
|
||||
## Características y servicios
|
||||
|
||||
- Apache2 & NGINX con PHP-FPM
|
||||
- Múltiples versiones de PHP (7.4[EOL](https://www.php.net/supported-versions.php) - 8.3, predeterminado 8.2 desde repositorio Remi + compilaciones personalizadas)
|
||||
- Servidor DNS (Bind)
|
||||
- Servicios de correo con protección antivirus/anti-spam (ClamAV, SpamAssassin, Roundcube)
|
||||
- Bases de datos MariaDB/MySQL & PostgreSQL
|
||||
- Soporte Let's Encrypt SSL
|
||||
- Cortafuegos con protección contra fuerza bruta (iptables, fail2ban, ipset)
|
||||
|
||||
## Sistemas compatibles
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**Notas importantes:**
|
||||
|
||||
- ¡No compatible con sistemas de 32 bits!
|
||||
- Pueden ocurrir problemas de DNS/cortafuegos en OpenVZ 7 o anteriores. Recomendamos virtualización basada en KVM/LXC.
|
||||
|
||||
## Instalación
|
||||
|
||||
**Requisito:** ¡Sistema operativo recién instalado!
|
||||
|
||||
### Paso 1: Iniciar sesión
|
||||
|
||||
Conéctese como **root** vía SSH:
|
||||
|
||||
```bash
|
||||
ssh root@su-servidor
|
||||
```
|
||||
|
||||
### Paso 2: Descargar script
|
||||
|
||||
Obtenga el instalador más reciente:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### Paso 3: Ejecutar
|
||||
|
||||
Ejecute el script con permisos:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
### Instalación personalizada
|
||||
|
||||
Ver opciones disponibles:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## Actualizaciones
|
||||
|
||||
Las actualizaciones automáticas están activadas por defecto (**Configuración del servidor > Actualizaciones**). Actualización manual:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## Soporte técnico
|
||||
|
||||
- Problemas con la edición RPM: [Reportar en GitHub](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- Versión original: [Repositorio principal](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## Licencia
|
||||
|
||||
Hestia Control Panel se distribuye bajo licencia [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) y está basado en [VestaCP](https://vestacp.com/).
|
||||
109
README.hi.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<div align="center">
|
||||
|
||||
# [हेस्टिया कंट्रोल पैनल (RPM संस्करण)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## आधुनिक वेब होस्टिंग वातावरण के लिए हल्का और शक्तिशाली सर्वर नियंत्रण पैनल
|
||||
|
||||
**स्थिर संस्करण:** 1.9.5 (RPM) |
|
||||
[RPM संस्करण](https://hestiadocs.brepo.ru) |
|
||||
[मूल Ubuntu/Debian प्रोजेक्ट](https://hestiacp.com) |
|
||||
[परिवर्तन सूची](/CHANGELOG.md) |
|
||||
[सहायता फोरम](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
हेस्टिया कंट्रोल पैनल (RPM संस्करण) RHEL-आधारित वितरणों पर केंद्रित एक स्वतंत्र टीम द्वारा विकसित और बनाए रखा जाता है। मूल प्रोजेक्ट से फोर्क होने के बाद, यह संस्करण अपस्ट्रीम Ubuntu/Debian संस्करण के साथ सीधे सिंक नहीं होता (कुछ सुविधाएँ RPM सिस्टम के लिए लागू नहीं हैं)। कृपया इस संस्करण से संबंधित समस्याओं को सीधे इस प्रोजेक्ट में रिपोर्ट करें।
|
||||
|
||||
निम्नलिखित पैनल का सामान्य विवरण है।
|
||||
|
||||
## **आपका स्वागत है!**
|
||||
|
||||
हेस्टिया कंट्रोल पैनल का उद्देश्य व्यवस्थापकों को वेबसाइट, ईमेल खाते, DNS ज़ोन और डेटाबेस को तेज़ी से तैनात करने और प्रबंधित करने के लिए एक केंद्रीकृत वेब इंटरफेस और कमांड-लाइन टूल्स प्रदान करना है - बिना अलग-अलग घटकों को मैन्युअल रूप से कॉन्फ़िगर किए।
|
||||
|
||||
## सुविधाएँ और सेवाएँ
|
||||
|
||||
- Apache2 और NGINX PHP-FPM के साथ
|
||||
- बहु-PHP संस्करण समर्थन (7.4[EOL](https://www.php.net/supported-versions.php) - 8.3, डिफ़ॉल्ट 8.2 Remi रिपॉजिटरी से + कस्टम PHP बिल्ड)
|
||||
- DNS सर्वर (Bind)
|
||||
- वायरस/स्पैम सुरक्षा के साथ ईमेल सेवाएँ और वेबमेल (POP/IMAP/SMTP, ClamAV, SpamAssassin, Sieve, Roundcube)
|
||||
- MariaDB/MySQL और PostgreSQL डेटाबेस
|
||||
- Let's Encrypt SSL समर्थन
|
||||
- ब्रूट-फोर्स सुरक्षा और IP प्रबंधन के साथ फ़ायरवॉल (iptables, fail2ban, ipset)
|
||||
|
||||
## समर्थित सिस्टम
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**ध्यान दें:**
|
||||
|
||||
- HestiaCP 32-बिट ऑपरेटिंग सिस्टम को समर्थन नहीं करता!
|
||||
- OpenVZ 7 या पुराने संस्करणों पर HestiaCP का उपयोग करते समय DNS/फ़ायरवॉल समस्याएँ हो सकती हैं। KVM/LXC आधारित वर्चुअलाइजेशन विकल्पों की सिफारिश की जाती है।
|
||||
|
||||
## Hestia कंट्रोल पैनल इंस्टॉल करें
|
||||
|
||||
- **नोट:** पूर्ण कार्यक्षमता सुनिश्चित करने के लिए कृपया एक ताज़ा सर्वर इंस्टॉलेशन पर इंस्टॉल करें।
|
||||
|
||||
हालांकि हम इंस्टॉलेशन प्रक्रिया को सरल बनाने का प्रयास करते हैं, लेकिन उपयोगकर्ताओं को लिनक्स सर्वर प्रबंधन का बुनियादी ज्ञान होना आवश्यक है।
|
||||
|
||||
### चरण 1: लॉगिन
|
||||
|
||||
**root** या सुपरयूजर एक्सेस के साथ SSH के माध्यम से लॉगिन करें:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
```
|
||||
|
||||
### चरण 2: डाउनलोड करें
|
||||
|
||||
नवीनतम इंस्टॉल स्क्रिप्ट प्राप्त करें:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### चरण 3: निष्पादित करें
|
||||
|
||||
स्क्रिप्ट चलाएँ और स्क्रीन निर्देशों का पालन करें:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
इंस्टॉलेशन पूरा होने पर, आपको एक स्वागत ईमेल (यदि कॉन्फ़िगर किया गया हो) और लॉगिन विवरण प्राप्त होंगे।
|
||||
|
||||
### कस्टम इंस्टॉलेशन
|
||||
|
||||
घटकों को चुनने के लिए पैरामीटर का उपयोग करें, विकल्प देखें:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## मौजूदा इंस्टॉलेशन अपडेट करें
|
||||
|
||||
स्वचालित अपडेट डिफ़ॉल्ट रूप से सक्षम हैं (**सर्वर सेटिंग्स > अपडेट** के माध्यम से प्रबंधित)। मैन्युअल अपडेट:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## समस्याएँ और सहायता
|
||||
|
||||
- RPM संस्करण से संबंधित मुद्दे: [GitHub इश्यू दर्ज करें](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- मूल Debian/Ubuntu संस्करण: [मूल प्रोजेक्ट रिपॉजिटरी](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## कॉपीराइट
|
||||
|
||||
मूल कॉपीराइट [HestiaCP](https://github.com/hestiacp/hestiacp) के पास है
|
||||
|
||||
## लाइसेंस
|
||||
|
||||
हेस्टिया कंट्रोल पैनल [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) लाइसेंस के तहत जारी किया गया है, और [VestaCP](https://vestacp.com/) पर आधारित है।
|
||||
97
README.ja.md
Normal file
@@ -0,0 +1,97 @@
|
||||
<div align="center">
|
||||
|
||||
# [Hestia コントロールパネル (RPM版)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## 現代的なWebホスティング環境向け軽量で強力なサーバー管理パネル
|
||||
|
||||
**安定版:** 1.9.5 (RPM) |
|
||||
[RPM版](https://hestiadocs.brepo.ru) |
|
||||
[オリジナルUbuntu/Debian版](https://hestiacp.com) |
|
||||
[更新履歴](/CHANGELOG.md) |
|
||||
[サポートフォーラム](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
Hestia コントロールパネル(RPM版)はRPMベースOS専用の開発チームによってメンテナンスされています。Ubuntu/Debian版との機能同期ができないため、問題報告は本プロジェクト宛てにお願いします。
|
||||
|
||||
## **ようこそ!**
|
||||
|
||||
Hestiaは直感的なWebインターフェースとCLIを提供し、ドメイン管理・メールアカウント・DNSゾーン・データベースの迅速なデプロイを可能にするサーバー管理パネルです。
|
||||
|
||||
## 主な機能
|
||||
|
||||
- Apache2 & NGINX + PHP-FPM連携
|
||||
- マルチPHPバージョン(7.4[EOL](https://www.php.net/supported-versions.php) - 8.3、Remiリポジトリ版+カスタムビルド)
|
||||
- Bind DNSサーバー
|
||||
- ウイルス/スパム対策付きメールサービス(ClamAV, SpamAssassin, Roundcube)
|
||||
- MariaDB/MySQL & PostgreSQLデータベース
|
||||
- Let's Encrypt SSL対応
|
||||
- ブルートフォース攻撃防御機能(iptables, fail2ban, ipset)
|
||||
|
||||
## 対応OS
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**注意事項:**
|
||||
|
||||
- 32ビットOS非対応
|
||||
- OpenVZ 7以前の環境ではDNS/ファイアウォール問題が発生する可能性あり
|
||||
|
||||
## インストール手順
|
||||
|
||||
### ステップ1: rootログイン
|
||||
|
||||
SSHでrootユーザーとしてログイン:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
```
|
||||
|
||||
### ステップ2: インストーラ取得
|
||||
|
||||
最新インストーラをダウンロード:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### ステップ3: 実行
|
||||
|
||||
スクリプトを実行し指示に従う:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
### カスタムインストール
|
||||
|
||||
オプション確認:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## アップデート
|
||||
|
||||
自動更新はデフォルトで有効(**サーバー設定 > 更新**から管理)。手動更新:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## サポート
|
||||
|
||||
- RPM版問題報告: [GitHub Issues](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- オリジナル版: [公式リポジトリ](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## ライセンス
|
||||
|
||||
Hestiaコントロールパネルは[GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE)ライセンスで、[VestaCP](https://vestacp.com/)を基に開発されています。
|
||||
125
README.md
@@ -1,110 +1,123 @@
|
||||
<h1 align="center">Hestia Control Panel</h1>
|
||||
<div align="center">
|
||||
|
||||
<h2 align="center">Lightweight and powerful control panel for the modern web</h2>
|
||||
# [Панель управления Hestia (RPM версия)](https://hestiadocs.brepo.ru)
|
||||
|
||||
<p align="center"><strong>Original project:</strong> | <a href="https://github.com/hestiacp/hestiacp/blob/release/CHANGELOG.md">View Changelog</a> |
|
||||
<a href="https://www.hestiacp.com/">HestiaCP.com</a> |
|
||||
<a href="https://docs.hestiacp.com/">Documentation</a> |
|
||||
<a href="https://forum.hestiacp.com/">Forum</a>
|
||||
<br/><br/></p>
|
||||

|
||||
|
||||
## Легкая и мощная серверная панель для современных веб-сред
|
||||
|
||||
<p align="center">
|
||||
<strong>RPM support project:</strong> |
|
||||
<a href="https://hestiadocs.brepo.ru/">Documentation for version with RPM support</a>
|
||||
</p>
|
||||
**Стабильная версия:** 1.9.5 (RPM) |
|
||||
[RPM версия](https://hestiadocs.brepo.ru) |
|
||||
[Оригинальный проект для Ubuntu/Debian](https://hestiacp.com) |
|
||||
[История изменений](/CHANGELOG.md) |
|
||||
[Форум поддержки](https://forum.hestiacp.com)
|
||||
<br><br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
## **Welcome!**
|
||||
</div>
|
||||
|
||||
Hestia Control Panel is designed to provide administrators an easy to use web and command line interface, enabling them to quickly deploy and manage web domains, mail accounts, DNS zones, and databases from one central dashboard without the hassle of manually deploying and configuring individual components or services.
|
||||
## [English](README.en.md)
|
||||
|
||||
## Features and Services
|
||||
## [Deutsch](README.de.md)
|
||||
|
||||
- Apache2 and NGINX with PHP-FPM
|
||||
- Multiple PHP versions (5.6 - 8.2, 8.0 as default)
|
||||
- DNS Server (Bind) with clustering capabilities
|
||||
- POP/IMAP/SMTP mail services with Anti-Virus, Anti-Spam, and Webmail (ClamAV, SpamAssassin, Sieve, Roundcube)
|
||||
- MariaDB/MySQL and/or PostgreSQL databases
|
||||
- Let's Encrypt SSL support with wildcard certificates
|
||||
- Firewall with brute-force attack detection and IP lists (iptables, fail2ban, and ipset).
|
||||
## [Español](README.es.md)
|
||||
|
||||
## Supported platforms and operating systems
|
||||
## [हिन्दी](README.hi.md)
|
||||
|
||||
## [日本語](README.ja.md)
|
||||
|
||||
## [简体中文](README.zh-Hans.md)
|
||||
|
||||
## [繁體中文](README.zh-Hant.md)
|
||||
|
||||
Панель управления Hestia (RPM версия) разрабатывается и поддерживается независимой командой, специализирующейся на RPM-ориентированных дистрибутивах. После ответвления от оригинального проекта данная версия включает изменения, которые не позволяют синхронизировать обновления с Ubuntu/Debian версией (некоторые функции не применимы к RPM-системам). Пожалуйста, сообщайте о проблемах непосредственно в этот проект.
|
||||
|
||||
Ниже представлено общее описание панели.
|
||||
|
||||
## **Добро пожаловать!**
|
||||
|
||||
Hestia Control Panel предоставляет администраторам простой веб-интерфейс и CLI-инструменты для быстрого развертывания доменов, почтовых аккаунтов, DNS-зон и баз данных через централизованную панель без ручной настройки отдельных компонентов.
|
||||
|
||||
## Функционал и сервисы
|
||||
|
||||
- Apache2 и NGINX с PHP-FPM
|
||||
- Поддержка нескольких версий PHP (7.4[EOL](https://www.php.net/supported-versions.php)-8.3, по умолчанию 8.2 из репозитория Remi + кастомные сборки)
|
||||
- DNS-сервер (Bind)
|
||||
- Почтовый сервис с антивирусом/антиспамом и веб-почтой (POP/IMAP/SMTP, ClamAV, SpamAssassin, Sieve, Roundcube)
|
||||
- Базы данных MariaDB/MySQL и PostgreSQL
|
||||
- Поддержка SSL Let's Encrypt
|
||||
- Фаервол с защитой от брутфорса и IP-менеджментом (iptables, fail2ban, ipset)
|
||||
|
||||
## Поддерживаемые системы
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
Currently stayed support of Debian and Ubuntu, but new functional will be available only for RPM based systems. For full supportin of Debian and Ubuntu use original [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
**Важно:**
|
||||
|
||||
**NOTES:**
|
||||
- HestiaCP не поддерживает 32-битные ОС!
|
||||
- На OpenVZ 7 и старых версиях возможны проблемы с DNS/фаерволом. Рекомендуем KVM/LXC-виртуализацию.
|
||||
|
||||
- Hestia Control Panel does not support 32 bit operating systems!
|
||||
- Hestia Control Panel in combination with OpenVZ 7 or lower might have issues with DNS and/or firewall. If you use a Virtual Private Server we strongly advice you to use something based on KVM or LXC!
|
||||
## Установка Hestia
|
||||
|
||||
## Installing Hestia Control Panel
|
||||
- **Примечание:** Для корректной работы устанавливайте на чистую ОС.
|
||||
|
||||
- **NOTE:** You must install Hestia Control Panel on top of a fresh operating system installation to ensure proper functionality.
|
||||
Требуются базовые знания администрирования Linux-серверов.
|
||||
|
||||
While we have taken every effort to make the installation process and the control panel interface as friendly as possible (even for new users), it is assumed that you will have some prior knowledge and understanding in the basics how to set up a Linux server before continuing.
|
||||
### Шаг 1: Авторизация
|
||||
|
||||
### Step 1: Log in
|
||||
|
||||
To start the installation, you will need to be logged in as **root** or a user with super-user privileges. You can perform the installation either directly from the command line console or remotely via SSH:
|
||||
Войдите как **root** через SSH:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
ssh root@ваш.сервер
|
||||
```
|
||||
|
||||
### Step 2: Download
|
||||
### Шаг 2: Загрузка
|
||||
|
||||
Download the installation script for the latest release:
|
||||
Получите установочный скрипт:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
If the download fails due to an SSL validation error, please be sure you've installed the ca-certificate package on your system - you can do this with the following command:
|
||||
### Шаг 3: Запуск
|
||||
|
||||
```bash
|
||||
yum update
|
||||
```
|
||||
|
||||
### Step 3: Run
|
||||
|
||||
To begin the installation process, simply run the script and follow the on-screen prompts:
|
||||
Выполните скрипт и следуйте инструкциям:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
You will receive a welcome email at the address specified during installation (if applicable) and on-screen instructions after the installation is completed to log in and access your server.
|
||||
После установки вы получите приветственное письмо и данные для входа.
|
||||
|
||||
### Custom installation
|
||||
### Кастомная установка
|
||||
|
||||
You may specify a number of various flags during installation to only install the features in which you need. To view a list of available options, run:
|
||||
Используйте параметры для выбора компонентов:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## How to upgrade an existing installation
|
||||
## Обновление системы
|
||||
|
||||
Automatic Updates are enabled by default on new installations of Hestia Control Panel and can be managed from **Server Settings > Updates**. To manually check for and install available updates, use the system package manager:
|
||||
Автообновления включены по умолчанию (управление: **Настройки сервера > Обновления**). Ручное обновление:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## Issues & Support Requests
|
||||
## Поддержка и отчеты
|
||||
|
||||
- If you encounter a general problem while using Hestia Control Panel for RPM based system use [issue report](https://github.com/bayrepo/hestiacp/issues)
|
||||
- Проблемы с RPM-версией: [GitHub Issues](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- Оригинальная версия: [Репозиторий проекта](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
For original HestiaCP for Debian and Ubuntu use [original version](https://github.com/hestiacp/hestiacp):
|
||||
## Авторские права
|
||||
|
||||
## Copyright
|
||||
Оригинальный код: [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
See original copyright of [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
## Лицензия
|
||||
|
||||
## License
|
||||
|
||||
Hestia Control Panel is licensed under [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) license, and is based on the [VestaCP](https://vestacp.com/) project.<br>
|
||||
Распространяется под лицензией [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE), основан на [VestaCP](https://vestacp.com/).
|
||||
|
||||
109
README.zh-Hans.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<div align="center">
|
||||
|
||||
# [Hestia 控制面板 (RPM 版)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## 面向现代网络托管环境的轻量级强大服务器控制面板
|
||||
|
||||
**稳定版本:** 1.9.5 (RPM) |
|
||||
[RPM 版](https://hestiadocs.brepo.ru) |
|
||||
[原版 Ubuntu/Debian 项目](https://hestiacp.com) |
|
||||
[更新日志](/CHANGELOG.md) |
|
||||
[支持论坛](https://forum.hestiacp.com)
|
||||
<br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
Hestia 控制面板(RPM 版)由专注于RHEL系列发行版的独立团队维护开发。由于从原项目分叉后,此版本已包含与上游 Ubuntu/Debian 版本无法直接同步的变更(部分功能不适用于 RPM 系统),因此相关问题请直接报告至本项目。
|
||||
|
||||
以下是面板的通用描述。
|
||||
|
||||
## **欢迎使用!**
|
||||
|
||||
Hestia 控制面板旨在通过集中式面板为管理员提供易用的网页界面和命令行工具,快速部署和管理网站域名、邮箱账户、DNS 区域和数据库,无需手动配置独立组件。
|
||||
|
||||
## 功能与服务
|
||||
|
||||
- Apache2 和 NGINX 搭配 PHP-FPM
|
||||
- 多版本 PHP 支持(7.4[EOL](https://www.php.net/supported-versions.php) - 8.3,默认 8.2 来自 Remi 仓库 + 自定义 PHP 构建)
|
||||
- DNS 服务器(Bind)
|
||||
- 带病毒/垃圾邮件防护的邮件服务及网页邮箱(POP/IMAP/SMTP,ClamAV,SpamAssassin,Sieve,Roundcube)
|
||||
- MariaDB/MySQL 和 PostgreSQL 数据库
|
||||
- Let's Encrypt SSL 支持
|
||||
- 防火墙含暴力破解防护和 IP 管理(iptables,fail2ban,ipset)
|
||||
|
||||
## 支持系统
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**注意事项:**
|
||||
|
||||
- HestiaCP 不支持 32 位操作系统!
|
||||
- 在 OpenVZ 7 或更早版本上使用 HestiaCP 可能出现 DNS/防火墙问题。建议选择基于 KVM/LXC 的虚拟化方案。
|
||||
|
||||
## 安装 Hestia 控制面板
|
||||
|
||||
- **注意:** 为保证功能完整性,请在新装系统上进行安装。
|
||||
|
||||
尽管我们力求安装过程简单直观,但使用者需具备基础的 Linux 服务器配置知识。
|
||||
|
||||
### 步骤 1:登录
|
||||
|
||||
使用 **root** 或超级用户权限通过 SSH 登录:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
```
|
||||
|
||||
### 步骤 2:下载
|
||||
|
||||
获取最新安装脚本:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### 步骤 3:执行
|
||||
|
||||
运行脚本并遵循屏幕指引:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
安装完成后,您将收到欢迎邮件(如配置)和登录信息。
|
||||
|
||||
### 自定义安装
|
||||
|
||||
使用参数选择组件,查看选项:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## 更新现有安装
|
||||
|
||||
默认启用自动更新(通过 **服务器设置 > 更新** 管理)。手动更新:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## 问题与支持
|
||||
|
||||
- RPM 版本问题反馈:[提交 GitHub Issue](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- 原版 Debian/Ubuntu 版本:[原项目仓库](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## 版权声明
|
||||
|
||||
原始版权归属 [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## 授权协议
|
||||
|
||||
Hestia 控制面板遵循 [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) 协议,基于 [VestaCP](https://vestacp.com/) 开发。
|
||||
109
README.zh-Hant.md
Normal file
@@ -0,0 +1,109 @@
|
||||
<div align="center">
|
||||
|
||||
# [Hestia 控制面板 (RPM 版)](https://hestiadocs.brepo.ru)
|
||||
|
||||

|
||||
|
||||
## 面向現代網絡託管環境的輕量級強大伺服器控制面板
|
||||
|
||||
**穩定版本:** 1.9.5 (RPM) |
|
||||
[RPM 版](https://hestiadocs.brepo.ru) |
|
||||
[原版 Ubuntu/Debian 專案](https://hestiacp.com) |
|
||||
[更新日誌](/CHANGELOG.md) |
|
||||
[支援論壇](https://forum.hestiacp.com)
|
||||
<br>
|
||||
[](https://drone.hestiacp.com/hestiacp/hestiacp)
|
||||
[](https://github.com/hestiacp/hestiacp/actions/workflows/lint.yml)
|
||||
[](https://gurubase.io/g/hestia)
|
||||
|
||||
</div>
|
||||
|
||||
Hestia 控制面板(RPM 版)由專注於 RPM 系統的獨立團隊維護開發。由於從原專案分叉後,此版本已包含與上游 Ubuntu/Debian 版本無法直接同步的變更(部分功能不適用於 RPM 系統),因此相關問題請直接報告至本專案。
|
||||
|
||||
以下是面板的通用描述。
|
||||
|
||||
## **歡迎使用!**
|
||||
|
||||
Hestia 控制面板旨在透過集中式面板為管理員提供易用的網頁介面和命令列工具,快速部署和管理網站域名、郵箱帳戶、DNS 區域和資料庫,無需手動配置獨立元件。
|
||||
|
||||
## 功能與服務
|
||||
|
||||
- Apache2 和 NGINX 搭配 PHP-FPM
|
||||
- 多版本 PHP 支援(7.4[EOL](https://www.php.net/supported-versions.php) - 8.3,預設 8.2 來自 Remi 倉庫 + 自訂 PHP 構建)
|
||||
- DNS 伺服器(Bind)
|
||||
- 帶病毒/垃圾郵件防護的郵件服務及網頁郵箱(POP/IMAP/SMTP,ClamAV,SpamAssassin,Sieve,Roundcube)
|
||||
- MariaDB/MySQL 和 PostgreSQL 資料庫
|
||||
- Let's Encrypt SSL 支援
|
||||
- 防火牆含暴力破解防護和 IP 管理(iptables,fail2ban,ipset)
|
||||
|
||||
## 支援系統
|
||||
|
||||
- **MSVSphere:** 9
|
||||
- **AlmaLinux:** 9
|
||||
- **RockyLinux:** 9
|
||||
|
||||
**注意事項:**
|
||||
|
||||
- HestiaCP 不支援 32 位元作業系統!
|
||||
- 在 OpenVZ 7 或更早版本上使用 HestiaCP 可能出現 DNS/防火牆問題。建議選擇基於 KVM/LXC 的虛擬化方案。
|
||||
|
||||
## 安裝 Hestia 控制面板
|
||||
|
||||
- **注意:** 為保證功能完整性,請在新裝系統上進行安裝。
|
||||
|
||||
儘管我們力求安裝過程簡單直觀,但使用者需具備基礎的 Linux 伺服器配置知識。
|
||||
|
||||
### 步驟 1:登入
|
||||
|
||||
使用 **root** 或超級使用者權限透過 SSH 登入:
|
||||
|
||||
```bash
|
||||
ssh root@your.server
|
||||
```
|
||||
|
||||
### 步驟 2:下載
|
||||
|
||||
取得最新安裝腳本:
|
||||
|
||||
```bash
|
||||
wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh
|
||||
```
|
||||
|
||||
### 步驟 3:執行
|
||||
|
||||
執行腳本並遵循螢幕指引:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh
|
||||
```
|
||||
|
||||
安裝完成後,您將收到歡迎郵件(如配置)和登入資訊。
|
||||
|
||||
### 自訂安裝
|
||||
|
||||
使用參數選擇元件,檢視選項:
|
||||
|
||||
```bash
|
||||
bash hst-install.sh -h
|
||||
```
|
||||
|
||||
## 更新現有安裝
|
||||
|
||||
預設啟用自動更新(透過 **伺服器設定 > 更新** 管理)。手動更新:
|
||||
|
||||
```bash
|
||||
dnf update
|
||||
```
|
||||
|
||||
## 問題與支援
|
||||
|
||||
- RPM 版本問題回饋:[提交 GitHub Issue](https://github.com/bayrepo/hestiacp-rpm/issues)
|
||||
- 原版 Debian/Ubuntu 版本:[原專案倉庫](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## 版權聲明
|
||||
|
||||
原始版權歸屬 [HestiaCP](https://github.com/hestiacp/hestiacp)
|
||||
|
||||
## 授權協議
|
||||
|
||||
Hestia 控制面板遵循 [GPL v3](https://github.com/hestiacp/hestiacp/blob/release/LICENSE) 協議,基於 [VestaCP](https://vestacp.com/) 開發。
|
||||
@@ -79,9 +79,9 @@ EOF
|
||||
chown root:$user $fastcgi
|
||||
chmod 640 $fastcgi
|
||||
|
||||
str="fastcgi_cache_path /var/cache/nginx/micro/$domain levels=1:2"
|
||||
str="fastcgi_cache_path /usr/local/hestia/nginx-system/var/cache/nginx/micro/$domain levels=1:2"
|
||||
str="$str keys_zone=$domain:10m max_size=512m inactive=30m use_temp_path=off;"
|
||||
conf='/etc/nginx/conf.d/fastcgi_cache_pool.conf'
|
||||
conf='/usr/local/hestia/nginx-system/etc/nginx/conf.d/fastcgi_cache_pool.conf'
|
||||
if [ -f "$conf" ]; then
|
||||
if [ -z "$(grep "=${domain}:" $conf)" ]; then
|
||||
echo "$str" >> $conf
|
||||
@@ -90,7 +90,7 @@ else
|
||||
echo "$str" >> $conf
|
||||
fi
|
||||
|
||||
mkdir -p /var/cache/nginx/micro/$domain
|
||||
mkdir -p /usr/local/hestia/nginx-system/var/cache/nginx/micro/$domain
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Hestia #
|
||||
|
||||
@@ -21,28 +21,10 @@ source_conf "$HESTIA/conf/hestia.conf"
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Ensure that quota kernel modules are installed
|
||||
if [ ! -f /etc/redhat-release ]; then
|
||||
kernel_module_check=$(find /lib/modules/$(uname -r) -type f -name '*quota_v*.ko*' | egrep '.*' && [ $? -eq 0 ])
|
||||
if [ -z "$kernel_module_check" ]; then
|
||||
# Install kernel modules for quota support.
|
||||
# Requires reboot to activate updated kernel.
|
||||
echo "Installing required kernel modules for quota support..."
|
||||
reboot_req="Y"
|
||||
apt-get -qq install linux-image-extra-virtual -y
|
||||
check_result $? "kernel module installation failed" "$E_UPDATE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Checking quota package
|
||||
quota=$(which --skip-alias --skip-functions quota 2> /dev/null)
|
||||
if [ $? -ne 0 ]; then
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
dnf -y install quota > /dev/null 2>&1
|
||||
else
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get -y install quota > /dev/null 2>&1
|
||||
fi
|
||||
dnf -y install quota > /dev/null 2>&1
|
||||
check_result $? "quota package installation failed" "$E_UPDATE"
|
||||
fi
|
||||
|
||||
@@ -54,34 +36,70 @@ check_hestia_demo_mode
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Adding group and user quota on /home partition
|
||||
file_system=$(df -T /home | tail -n1 | awk '{print $2}')
|
||||
mnt=$(df -P /home | awk '{print $6}' | tail -n1)
|
||||
lnr=$(cat -n /etc/fstab | grep -v "#" | awk '{print $1,$3}' | grep "$mnt$" | cut -f 1 -d ' ')
|
||||
opt=$(sed -n ${lnr}p /etc/fstab | awk '{print $4}')
|
||||
fnd='usrquota\|grpquota\|usrjquota=aquota.user\|grpjquota=aquota.group\|jqfmt=vfsv0'
|
||||
if [ $(echo $opt | tr ',' '\n' | grep -x $fnd | wc -l) -ne 5 ]; then
|
||||
old=$(echo $(echo $opt | tr ',' '\n' | grep -v 'usrquota\|grpquota\|usrjquota=\|grpjquota=\|jqfmt=') | tr ' ' ',')
|
||||
new='usrquota,grpquota,usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0'
|
||||
sed -i "$lnr s/$opt/$old,$new/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
if [ "$file_system" == "xfs" ]; then
|
||||
fnd='usrquota\|grpquota'
|
||||
if [ $(echo $opt | tr ',' '\n' | grep -x $fnd | wc -l) -ne 2 ]; then
|
||||
old=$(echo $(echo $opt | tr ',' '\n' | grep -v 'usrquota\|grpquota') | tr ' ' ',')
|
||||
new='usrquota,grpquota'
|
||||
sed -i "$lnr s/$opt/$old,$new/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
systemctl daemon-reload
|
||||
if [ "$mnt" == "/" ]; then
|
||||
check_args=$(grubby --info=ALL | grep -oP "rootflags=\S*")
|
||||
if [ -n "$check_args" ]; then
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
YELLOW='\033[1;33m'
|
||||
printf "${RED}!!!!!!!Detected rootflags in grub!!!!!!!${NC}\n"
|
||||
echo "${YELLOW}Add manualy 'uquota,pquota' and reboot the system${NC}\n"
|
||||
else
|
||||
grubby --args="rootflags=uquota,pquota" --update-kernel=ALL
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif [ "$file_system" == "ext4" ]; then
|
||||
fnd='usrquota\|grpquota\|usrjquota=aquota.user\|grpjquota=aquota.group\|jqfmt=vfsv0'
|
||||
if [ $(echo $opt | tr ',' '\n' | grep -x $fnd | wc -l) -ne 5 ]; then
|
||||
old=$(echo $(echo $opt | tr ',' '\n' | grep -v 'usrquota\|grpquota\|usrjquota=\|grpjquota=\|jqfmt=') | tr ' ' ',')
|
||||
new='usrquota,grpquota,usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0'
|
||||
sed -i "$lnr s/$opt/$old,$new/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
else
|
||||
if [ -n "$(grep DISK_QUOTA $HESTIA/conf/hestia.conf)" ]; then
|
||||
sed -i "s/DISK_QUOTA=.*/DISK_QUOTA='no'/g" $HESTIA/conf/hestia.conf
|
||||
fi
|
||||
$BIN/v-log-action "system" "Info" "Plugins" "System Quota not supported."
|
||||
log_history "system quota not supported"
|
||||
log_event "$E_DISK" "$ARGUMENTS"
|
||||
exit
|
||||
fi
|
||||
|
||||
# Adding v2 group and user quota index
|
||||
if [ ! -e "$mnt/aquota.user" ] || [ ! -e "$mnt/aquota.group" ]; then
|
||||
quotacheck -avcugm > /dev/null 2>&1
|
||||
fi
|
||||
if [ "$file_system" == "ext4" ]; then
|
||||
# Adding v2 group and user quota index
|
||||
if [ ! -e "$mnt/aquota.user" ] || [ ! -e "$mnt/aquota.group" ]; then
|
||||
quotacheck -avcugm > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
# Adding quotacheck on reboot
|
||||
touch /forcequotacheck
|
||||
# Adding quotacheck on reboot
|
||||
touch /forcequotacheck
|
||||
|
||||
# Adding cron job
|
||||
echo '#!/bin/bash' > /etc/cron.daily/quotacheck
|
||||
echo 'touch /forcequotacheck' >> /etc/cron.daily/quotacheck
|
||||
chmod a+x /etc/cron.daily/quotacheck
|
||||
# Adding cron job
|
||||
echo '#!/bin/bash' > /etc/cron.daily/quotacheck
|
||||
echo 'touch /forcequotacheck' >> /etc/cron.daily/quotacheck
|
||||
chmod a+x /etc/cron.daily/quotacheck
|
||||
|
||||
# Enabling group and user quota
|
||||
if [ -n "$(quotaon -pa | grep " $mnt " | grep 'user\|group' | grep 'is off')" ]; then
|
||||
quotaon -v $mnt
|
||||
check_result $? "quota can't be enabled in $mnt" "$E_DISK"
|
||||
fi
|
||||
|
||||
# Enabling group and user quota
|
||||
if [ -n "$(quotaon -pa | grep " $mnt " | grep 'user\|group' | grep 'is off')" ]; then
|
||||
quotaon -v $mnt
|
||||
check_result $? "quota can't be enabled in $mnt" "$E_DISK"
|
||||
fi
|
||||
|
||||
# Updating hestia.conf value
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
user=$1
|
||||
restart=$2
|
||||
|
||||
if [ "$user" == "puppet" ]; then
|
||||
exit
|
||||
fi
|
||||
|
||||
# Includes
|
||||
# shellcheck source=/etc/hestiacp/hestia.conf
|
||||
source /etc/hestiacp/hestia.conf
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
# www.domain.tld type will be automatically assigned to the domain unless
|
||||
# "none" is transmited as argument. If ip have associated dns name, this
|
||||
# domain will also get the alias domain-tpl.$ipname. An alias with the ip
|
||||
# name is useful during the site testing while dns isn't moved to server yet.
|
||||
# name is useful during the site testing while dns isn't moved to server yaliet.
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
@@ -111,6 +111,7 @@ $BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/cgi-bin"
|
||||
$BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/private"
|
||||
$BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/stats"
|
||||
$BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/logs"
|
||||
$BIN/v-add-fs-directory "$user" "$HOMEDIR/$user/web/$domain/private/tmp"
|
||||
|
||||
# Creating domain logs
|
||||
touch /var/log/$WEB_SYSTEM/domains/$domain.bytes \
|
||||
@@ -250,6 +251,15 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ]; then
|
||||
$BIN/v-ext-modules-run bunkerweb_module add "$domain" "$ip"
|
||||
if [ -n "%$ALIAS" ]; then
|
||||
$BIN/v-ext-modules-run bunkerweb_module alias "$domain" "$ALIAS"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "Added new web domain (Name: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -108,6 +108,13 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ]; then
|
||||
get_domain_values 'web'
|
||||
$BIN/v-ext-modules-run bunkerweb_module alias "$domain" "$ALIAS"
|
||||
fi
|
||||
|
||||
$BIN/v-log-action "$user" "Info" "Web" "Added new web domain alias (Alias: $aliases, Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
|
||||
@@ -136,6 +136,25 @@ if [ -n "$UPDATE_SSL_SCRIPT" ]; then
|
||||
eval "$UPDATE_SSL_SCRIPT $user $domain"
|
||||
fi
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ] && [ "$BUNKERWEB" = "yes" ]; then
|
||||
BUNKW_DIR=$HOMEDIR/$user/conf/web/$domain/ssl/bunkerweb
|
||||
if [ ! -d "$BUNKW_DIR" ]; then
|
||||
mkdir -p "$BUNKW_DIR"
|
||||
chmod 0755 "$BUNKW_DIR"
|
||||
fi
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.crt" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.key" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.pem" "$BUNKW_DIR/"
|
||||
if [ -e "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" ]; then
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" "$BUNKW_DIR/"
|
||||
fi
|
||||
chown root:nginx "$BUNKW_DIR"/*
|
||||
chmod 0640 "$BUNKW_DIR"/*
|
||||
$BIN/v-ext-modules-run bunkerweb_module addssl "$domain" "$BUNKW_DIR/$domain.pem" "$BUNKW_DIR/$domain.key"
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "Added certificate and enabled SSL (Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -22,11 +22,11 @@ source $HESTIA/func/main.sh
|
||||
source_conf "$HESTIA/conf/hestia.conf"
|
||||
source_conf "$HESTIA/install/upgrade/upgrade.conf"
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
for elem in "${!multiphp_v[@]}"; do
|
||||
multiphp_v[$elem]=$(convert_dot_version_to_non_dot "${multiphp_v[$elem]}")
|
||||
done
|
||||
fi
|
||||
|
||||
for elem in "${!multiphp_v[@]}"; do
|
||||
multiphp_v[$elem]=$(convert_dot_version_to_non_dot "${multiphp_v[$elem]}")
|
||||
done
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
@@ -38,27 +38,22 @@ if [ -z "$WEB_BACKEND" ]; then
|
||||
fi
|
||||
|
||||
# Set file locations
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
php_fpm=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
php_fpm="/usr/lib/systemd/system/brepo-php-fpm$version.service"
|
||||
else
|
||||
php_fpm="/etc/init.d/php$version-fpm"
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
fi
|
||||
|
||||
|
||||
# Verify php version format
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
else
|
||||
if [[ ! $version =~ ^[0-9].[0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9].[0-9]."
|
||||
echo "Example: 7.0, 7.4, 8.0"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
|
||||
|
||||
# Check if php version already exists
|
||||
if [ -f "$php_fpm" ] && [ -f "$HESTIA/data/templates/web/php-fpm/PHP-${version/\./_}.tpl" ]; then
|
||||
echo "ERROR: Specified PHP version is already installed."
|
||||
@@ -77,48 +72,48 @@ check_hestia_demo_mode
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
mph=""
|
||||
php_modules_install="mysqlnd mysqli pdo_mysql pgsql pdo sqlite pdo_sqlite pdo_pgsql imap ldap zip opcache xmlwriter xmlreader gd intl pspell"
|
||||
php_modules_disable=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
mph="brepo-php$version brepo-php$version-fpm"
|
||||
if ! echo "$DB_SYSTEM" | grep -w 'pgsql' > /dev/null; then
|
||||
php_modules_install=$(echo "$php_modules_install" | sed -e "s/pgsql//")
|
||||
php_modules_install=$(echo "$php_modules_install" | sed -e "s/pdo_pgsql//")
|
||||
php_modules_disable="$php_modules_disable pgsql pdo_pgsql"
|
||||
fi
|
||||
else
|
||||
# Packages in Remi repo have names with php$version-php- prefixes
|
||||
mph="php$version-php-fpm php$version-php-cgi php$version-php-mysqlnd php$version-php-pgsql
|
||||
php$version-php-pdo php$version-php-common php$version-php-pecl-imagick php$version-php-imap
|
||||
php$version-php-ldap php$version-php-pecl-apcu php$version-php-pecl-zip php$version-php-cli
|
||||
php$version-php-opcache php$version-php-xml php$version-php-gd php$version-php-intl
|
||||
php$version-php-mbstring php$version-php-pspell php$version-php-readline"
|
||||
if [ "$version" = "56" ]; then
|
||||
mph=$(sed -e "s/php$version-php-pecl-apcu//")
|
||||
fi
|
||||
|
||||
mph="php$version-common php$version-mbstring php$version-bcmath php$version-cli php$version-curl
|
||||
php$version-fpm php$version-gd php$version-intl php$version-mysql
|
||||
php$version-soap php$version-xml php$version-zip php$version-json php$version-bz2
|
||||
php$version-pspell php$version-imagick php$version-pgsql php$version-imap php$version-ldap"
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
# Packages in Remi repo have names with php$version-php- prefixes
|
||||
mph="php$version-php-fpm php$version-php-cgi php$version-php-mysqlnd php$version-php-pgsql
|
||||
php$version-php-pdo php$version-php-common php$version-php-pecl-imagick php$version-php-imap
|
||||
php$version-php-ldap php$version-php-pecl-apcu php$version-php-pecl-zip php$version-php-cli
|
||||
php$version-php-opcache php$version-php-xml php$version-php-gd php$version-php-intl
|
||||
php$version-php-mbstring php$version-php-pspell php$version-php-readline"
|
||||
if [ "$version" = "56" ]; then
|
||||
mph=$(sed -e "s/php$version-php-pecl-apcu//")
|
||||
fi
|
||||
fi
|
||||
# Check is version is 7.1 or below to add mcrypt
|
||||
if [[ $(echo "$version 7.2" | awk '{print ($1 < $2)}') == 1 ]]; then
|
||||
mph="$mph php$version-mcrypt"
|
||||
fi
|
||||
|
||||
# Check is version is 7.1 or below to add mcrypt
|
||||
if [[ $(echo "$version 7.2" | awk '{print ($1 < $2)}') == 1 ]]; then
|
||||
mph="$mph php$version-mcrypt"
|
||||
fi
|
||||
# Check if version is 8.0 or higher and drop php json.
|
||||
if [[ ${version:0:1} == "8" ]]; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-json//")
|
||||
fi
|
||||
|
||||
# Check if version is 8.0 or higher and drop php json.
|
||||
if [[ ${version:0:1} == "8" ]]; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-json//")
|
||||
fi
|
||||
if ! echo "$DB_SYSTEM" | grep -w 'mysql' > /dev/null; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-mysql//")
|
||||
fi
|
||||
|
||||
if ! echo "$DB_SYSTEM" | grep -w 'mysql' > /dev/null; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-mysql//")
|
||||
fi
|
||||
|
||||
if ! echo "$DB_SYSTEM" | grep -w 'pgsql' > /dev/null; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-pgsql//")
|
||||
if ! echo "$DB_SYSTEM" | grep -w 'pgsql' > /dev/null; then
|
||||
mph=$(echo "$mph" | sed -e "s/php$version\(-php\)\{0,1\}-pgsql//")
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install php packages
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
dnf install -q -y $mph > /dev/null 2>&1 &
|
||||
else
|
||||
apt-get -qq update
|
||||
apt-get -y -qq -o Dpkg::Options::="--force-confold" install $mph > /dev/null 2>&1 &
|
||||
fi
|
||||
dnf install -q -y $mph > /dev/null 2>&1 &
|
||||
BACK_PID=$!
|
||||
|
||||
# Check if package installation is done, print a spinner
|
||||
@@ -133,17 +128,27 @@ done
|
||||
# Do a blank echo to get the \n back
|
||||
echo
|
||||
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
for mod in $php_modules_install; do
|
||||
fn_enable_local_php_extension "$version" "$mod"
|
||||
done
|
||||
for mod in $php_modules_disable; do
|
||||
fn_disable_local_php_extension "$version" "$mod"
|
||||
done
|
||||
fi
|
||||
|
||||
# Check if installation was successful
|
||||
if [ ! -f "$php_fpm" ]; then
|
||||
echo "ERROR: Installation failed, please run the following command manually for debugging:"
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
echo "dnf install $mph"
|
||||
else
|
||||
echo "apt-get install $mph"
|
||||
fi
|
||||
echo "dnf install $mph"
|
||||
fi
|
||||
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
result_alt_php=$(alternatives --display php | grep /opt/brepo/php${version}/bin/php)
|
||||
if [ -z "$result_alt_php" ]; then
|
||||
alternatives --install /usr/bin/php php /opt/brepo/php${version}/bin/php 1 > /dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
result_alt_php=$(alternatives --display php | grep /usr/bin/php$version)
|
||||
if [ -z "$result_alt_php" ]; then
|
||||
alternatives --install /usr/bin/php php /usr/bin/php$version 1 > /dev/null 2>&1
|
||||
@@ -151,29 +156,31 @@ if [ -f '/etc/redhat-release' ]; then
|
||||
fi
|
||||
|
||||
# Check if required modules for apache2 are enabled
|
||||
if [ "$WEB_SYSTEM" = "apache2" ]; then
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if ! httpd -M | grep 'proxy_fcgi_module' ; then
|
||||
sed 's/#LoadModule proxy_fcgi_module/LoadModule proxy_fcgi_module/' -i /etc/httpd/conf.modules.d/00-proxy.conf
|
||||
sed 's/#LoadModule proxy_module/LoadModule proxy_module/' -i /etc/httpd/conf.modules.d/00-proxy.conf
|
||||
fi
|
||||
if ! httpd -M | grep 'setenvif_module' ; then
|
||||
sed 's/#LoadModule setenvif_module/LoadModule setenvif_module/' -i /etc/httpd/conf.modules.d/00-base.conf
|
||||
fi
|
||||
else
|
||||
if ! a2query -q -m proxy_fcgi; then
|
||||
a2enmod -q proxy_fcgi
|
||||
fi
|
||||
if ! a2query -q -m setenvif; then
|
||||
a2enmod -q setenvif
|
||||
fi
|
||||
if [ "$WEB_SYSTEM" = "httpd" ]; then
|
||||
if ! httpd -M | grep 'proxy_fcgi_module' ; then
|
||||
sed 's/#LoadModule proxy_fcgi_module/LoadModule proxy_fcgi_module/' -i /etc/httpd/conf.modules.d/00-proxy.conf
|
||||
sed 's/#LoadModule proxy_module/LoadModule proxy_module/' -i /etc/httpd/conf.modules.d/00-proxy.conf
|
||||
fi
|
||||
if ! httpd -M | grep 'setenvif_module' ; then
|
||||
sed 's/#LoadModule setenvif_module/LoadModule setenvif_module/' -i /etc/httpd/conf.modules.d/00-base.conf
|
||||
fi
|
||||
|
||||
$BIN/v-restart-web "yes"
|
||||
fi
|
||||
|
||||
# Configure fpm
|
||||
v_tpl=${version//./}
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
systemctl enable brepo-php-fpm${version}.service
|
||||
rm -f /opt/brepo/php${version}/etc/php-fpm.d/*
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/dummy.conf /opt/brepo/php${version}/etc/php-fpm.d/
|
||||
sed -i "s/9999/99$v_tpl/g" /opt/brepo/php${version}/etc/php-fpm.d/dummy.conf
|
||||
|
||||
# Increase max upload and max post size
|
||||
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 100M/g" /opt/brepo/php${version}/etc/php.ini
|
||||
sed -i "s/post_max_size = 8M/post_max_size = 100M/g" /opt/brepo/php${version}/etc/php.ini
|
||||
sed -i "s/max_execution_time = 30/max_execution_time = 60/g" /opt/brepo/php${version}/etc/php.ini
|
||||
else
|
||||
systemctl enable php${version}-php-fpm
|
||||
rm -f /etc/opt/remi/php${version}/php-fpm.d/*
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/dummy.conf /etc/opt/remi/php${version}/php-fpm.d/
|
||||
@@ -183,19 +190,8 @@ if [ -f /etc/redhat-release ]; then
|
||||
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 100M/g" /etc/opt/remi/php${version}/php.ini
|
||||
sed -i "s/post_max_size = 8M/post_max_size = 100M/g" /etc/opt/remi/php${version}/php.ini
|
||||
sed -i "s/max_execution_time = 30/max_execution_time = 60/g" /etc/opt/remi/php${version}/php.ini
|
||||
else
|
||||
update-rc.d php$version-fpm defaults > /dev/null 2>&1
|
||||
rm -f /etc/php/$version/fpm/pool.d/*
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/dummy.conf /etc/php/$version/fpm/pool.d/
|
||||
sed -i "s/9999/99$v_tpl/g" /etc/php/$version/fpm/pool.d/dummy.conf
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/php-fpm.conf /etc/php/$version/fpm/
|
||||
sed -i "s/fpm_v/$version/g" /etc/php/$version/fpm/php-fpm.conf
|
||||
|
||||
# Increase max upload and max post size
|
||||
sed -i "s/upload_max_filesize = 2M/upload_max_filesize = 100M/g" /etc/php/$version/fpm/php.ini
|
||||
sed -i "s/post_max_size = 8M/post_max_size = 100M/g" /etc/php/$version/fpm/php.ini
|
||||
sed -i "s/max_execution_time = 30/max_execution_time = 60/g" /etc/php/$version/fpm/php.ini
|
||||
fi
|
||||
|
||||
# Install backend template
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/multiphp.tpl \
|
||||
$HESTIA/data/templates/web/php-fpm/PHP-${version/\./_}.tpl
|
||||
|
||||
574
bin/v-bunkerweb-migrate
Executable file
@@ -0,0 +1,574 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: utility to prepare existing server with hestiacp to use bunkerweb
|
||||
# do not run this script n the server, where bunkerweb was installed with hestiacp
|
||||
# installation
|
||||
# options: COMMAND
|
||||
#
|
||||
# example: v-bunkerweb-migrate migrate-nginx
|
||||
#
|
||||
# Commands:
|
||||
# migratenginx - move old nginx configs to the new port and path
|
||||
# migratetobunkerweb - create items of sites in the bunkerweb database
|
||||
#
|
||||
|
||||
#------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
v_command = ARGV[0]
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
require "HestiaBunkerWebApi"
|
||||
|
||||
require 'json' unless defined?(JSON)
|
||||
require 'fileutils'
|
||||
require 'time'
|
||||
require 'pathname'
|
||||
|
||||
|
||||
def copy_nginx_files(src_root, dest_root)
|
||||
FileUtils.mkdir_p(dest_root)
|
||||
Dir.foreach(src_root) do |entry|
|
||||
next if entry == '.' || entry == '..'
|
||||
next if entry == 'modules' || entry == 'modules-enabled'
|
||||
src_path = File.join(src_root, entry)
|
||||
dest_path = File.join(dest_root, entry)
|
||||
if File.directory?(src_path)
|
||||
FileUtils.mkdir_p(dest_path)
|
||||
copy_nginx_files(src_path, dest_path)
|
||||
else
|
||||
FileUtils.cp(src_path, dest_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Function to log and execute migration stages
|
||||
def log_migrate_stage(stage)
|
||||
log_file = '/usr/local/hestia/log/bunkerweb_migrate_stages.log'
|
||||
# Check if the stage has already been recorded
|
||||
if File.exist?(log_file) && File.readlines(log_file).any? { |line| line.strip == stage }
|
||||
hestia_print_error_message_to_cli "Stage #{stage} already completed, skipping."
|
||||
return
|
||||
end
|
||||
# Execute the stage block
|
||||
begin
|
||||
yield
|
||||
# Record the successful stage
|
||||
File.open(log_file, 'a') { |f| f.puts stage }
|
||||
hestia_print_info_message_to_cli "Stage #{stage} completed."
|
||||
rescue => e
|
||||
hestia_print_error_message_to_cli "Stage #{stage} failed: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
# Function to parse and migrate nginx.conf from /usr/local/hestia/nginx-system/etc/nginx/nginx.conf
|
||||
def migrate_nginx_config_from_file(source_path)
|
||||
return false unless File.exist?(source_path)
|
||||
|
||||
hestia_print_info_message_to_cli "Processing nginx config from: #{source_path}"
|
||||
|
||||
content = File.read(source_path)
|
||||
original_content = content.dup
|
||||
|
||||
modified = false
|
||||
|
||||
# Replace all paths starting with /var/ to /usr/local/hestia/nginx-system/var/
|
||||
# This pattern matches any absolute path that starts with /var/ anywhere in the line
|
||||
content = content.gsub(/\/var\//, '/usr/local/hestia/nginx-system/var/')
|
||||
|
||||
# Replace pid path from /run/nginx.pid to /run/nginx-system.pid
|
||||
content = content.gsub(/pid\s+\S+/) { |match| match.gsub('/run/nginx.pid', '/run/nginx-system.pid') }
|
||||
|
||||
if content != original_content
|
||||
File.write(source_path, content)
|
||||
hestia_print_info_message_to_cli "Updated config: #{source_path}"
|
||||
modified = true
|
||||
end
|
||||
|
||||
modified
|
||||
end
|
||||
|
||||
def parse_listen(line)
|
||||
# Попытка найти IP:port
|
||||
m = line.match(/^\s*listen\s+([^\s:]+):(\d+)/i)
|
||||
return [m[1], m[2]] if m
|
||||
# Если только порт после listen
|
||||
m = line.match(/^\s*listen\s+(\d+);?\s*$/i)
|
||||
return [nil, m[1]] if m
|
||||
nil
|
||||
end
|
||||
|
||||
# Helper function to parse and replace ports in listen directives using temp placeholders
|
||||
def parse_and_replace_listen_directive(line, proxy_port, proxy_ssl_port)
|
||||
return line unless line.match?(/\blisten\b/i)
|
||||
|
||||
new_line = line.dup
|
||||
|
||||
# Define target ports (always migrate to these values regardless of input)
|
||||
target_http_port = '8078'
|
||||
target_ssl_port = '8079'
|
||||
|
||||
result = parse_listen(line)
|
||||
return line unless result
|
||||
ip, port = result
|
||||
|
||||
if port == proxy_port
|
||||
if ip
|
||||
new_line.gsub!("#{ip}:#{port}", "#{ip}:#{target_http_port}")
|
||||
else
|
||||
new_line.gsub!(port, target_http_port)
|
||||
end
|
||||
elsif port == proxy_ssl_port
|
||||
if ip
|
||||
new_line.gsub!("#{ip}:#{port}", "#{ip}:#{target_ssl_port}")
|
||||
else
|
||||
new_line.gsub!(port, target_ssl_port)
|
||||
end
|
||||
end
|
||||
|
||||
new_line
|
||||
end
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
#------------------------------------------#
|
||||
# Verifications #
|
||||
#------------------------------------------#
|
||||
|
||||
check_args 1, ARGV, "COMMAND"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#------------------------------------------#
|
||||
# Action #
|
||||
#------------------------------------------#
|
||||
|
||||
case v_command.to_sym
|
||||
when :migratenginx
|
||||
log_migrate_stage('stage0') do
|
||||
# Create backup of /etc/nginx with timestamp
|
||||
|
||||
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
||||
backup_root = "/etc/nginx_backup_#{timestamp}"
|
||||
FileUtils.mkdir_p(backup_root)
|
||||
|
||||
src_root = '/etc/nginx'
|
||||
dest_root = backup_root
|
||||
|
||||
# Custom copy function to handle symlinks in conf.d/domains
|
||||
def copy_with_symlinks(src, dest)
|
||||
Dir.foreach(src) do |entry|
|
||||
next if entry == '.' || entry == '..'
|
||||
src_path = File.join(src, entry)
|
||||
dest_path = File.join(dest, entry)
|
||||
|
||||
if File.symlink?(src_path)
|
||||
# Check if symlink is inside conf.d/domains
|
||||
if src_path.include?(File.join('conf.d', 'domains'))
|
||||
# Resolve the target of the symlink
|
||||
target_path = File.readlink(src_path)
|
||||
# Resolve relative symlink paths
|
||||
unless Pathname.new(target_path).absolute?
|
||||
target_path = File.expand_path(target_path, File.dirname(src_path))
|
||||
end
|
||||
if File.exist?(target_path) && File.file?(target_path)
|
||||
content = File.read(target_path)
|
||||
new_file_name = "#{entry}_content.conf"
|
||||
new_file_path = File.join(dest, new_file_name)
|
||||
File.write(new_file_path, content)
|
||||
end
|
||||
else
|
||||
# Preserve the symlink as is
|
||||
FileUtils.mkdir_p(File.dirname(dest_path))
|
||||
target = File.readlink(src_path)
|
||||
FileUtils.ln_s(target, dest_path)
|
||||
end
|
||||
elsif File.directory?(src_path)
|
||||
FileUtils.mkdir_p(dest_path)
|
||||
copy_with_symlinks(src_path, dest_path)
|
||||
else
|
||||
FileUtils.cp(src_path, dest_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
copy_with_symlinks(src_root, dest_root)
|
||||
end
|
||||
log_migrate_stage('stage1') do
|
||||
if $BUNKERWEB.nil?
|
||||
hestia_change_sys_config_value("BUNKERWEB", "yes")
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage2') do
|
||||
unless system('yum install -y nginx-system')
|
||||
hestia_print_error_message_to_cli "Failed to install nginx-system via yum"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage3') do
|
||||
FileUtils.rm_f Dir.glob('/usr/local/hestia/nginx-system/etc/nginx/conf.d/*.conf')
|
||||
src_root = '/etc/nginx'
|
||||
dest_root = '/usr/local/hestia/nginx-system/etc/nginx'
|
||||
copy_nginx_files(src_root, dest_root)
|
||||
end
|
||||
log_migrate_stage('stage4') do
|
||||
# Find all files under the nginx-system directory
|
||||
nginx_conf_dir = '/usr/local/hestia/nginx-system/etc/nginx'
|
||||
Dir.glob(File.join(nginx_conf_dir, '**', '*')).each do |path|
|
||||
hestia_print_info_message_to_cli "stage 4 processing file #{path}"
|
||||
next if File.directory?(path)
|
||||
content = File.read(path)
|
||||
new_content = content.gsub(/(?<!\/usr\/local\/hestia\/nginx-system)\/etc\/nginx/, '/usr/local/hestia/nginx-system/etc/nginx')
|
||||
if new_content != content
|
||||
hestia_print_info_message_to_cli "Changed path to config in file #{path}"
|
||||
File.open(path, 'w') { |f| f.write(new_content) }
|
||||
end
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage4.1') do
|
||||
# Parse nginx.conf file to replace paths
|
||||
if migrate_nginx_config_from_file("/usr/local/hestia/nginx-system/etc/nginx/nginx.conf")
|
||||
hestia_print_info_message_to_cli "Completed migration of nginx.conf paths"
|
||||
else
|
||||
hestia_print_error_message_to_cli "Warning: Could not migrate nginx.conf from #{File.expand_path('/usr/local/hestia/nginx-system/etc/nginx/nginx.conf')}"
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage5') do
|
||||
nginx_conf_dir = '/usr/local/hestia/nginx-system/etc/nginx'
|
||||
|
||||
# Read proxy ports from configuration
|
||||
#proxy_port = $PROXY_PORT.nil? || $PROXY_PORT.empty? ? '80' : $PROXY_PORT
|
||||
#proxy_ssl_port = $PROXY_SSL_PORT.nil? || $PROXY_SSL_PORT.empty? ? '443' : $PROXY_SSL_PORT
|
||||
|
||||
proxy_port = '80'
|
||||
proxy_ssl_port = '443'
|
||||
|
||||
hestia_print_info_message_to_cli "Migrating ports: #{proxy_port} -> 8078, #{proxy_ssl_port} -> 8079"
|
||||
|
||||
# Find and replace port in all .conf files
|
||||
Dir.glob(File.join(nginx_conf_dir, '**', '*.conf')).each do |conf_file|
|
||||
hestia_print_info_message_to_cli "stage 5 processing file #{conf_file}"
|
||||
content = File.read(conf_file)
|
||||
modified = false
|
||||
|
||||
# Process line by line - only replace ports in listen directives
|
||||
new_lines = []
|
||||
|
||||
content.each_line do |line|
|
||||
# Check if line is a listen directive (starts with optional whitespace then 'listen')
|
||||
if /^\s*listen\s+/i.match?(line) || /^listen\s+/i.match?(line)
|
||||
# This is a listen line - process it
|
||||
new_line = parse_and_replace_listen_directive(line, proxy_port, proxy_ssl_port)
|
||||
modified = true unless new_line == line
|
||||
new_lines << new_line
|
||||
else
|
||||
# Not a listen line, keep as is
|
||||
new_lines << line
|
||||
end
|
||||
end
|
||||
|
||||
# Write changes back if modified
|
||||
if modified
|
||||
File.open(conf_file, 'w') { |f| f.write(new_lines.join) }
|
||||
hestia_print_info_message_to_cli " Updated: #{conf_file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
log_migrate_stage('stage6') do
|
||||
hestia_change_sys_config_value("PROXY_PORT", "8078")
|
||||
hestia_change_sys_config_value("PROXY_SSL_PORT", "8079")
|
||||
end
|
||||
log_migrate_stage('stage7') do
|
||||
if system('/usr/local/hestia/bin/v-ext-modules enable update_module')
|
||||
output = IO.popen("/usr/local/hestia/bin/v-ext-modules state update_module json").read
|
||||
begin
|
||||
parsed = JSON.parse(output)
|
||||
if parsed.is_a?(Array) && parsed.first && parsed.first['STATE'] == 'enabled'
|
||||
system('/usr/local/hestia/bin/v-ext-modules-run update_module synctemplates')
|
||||
else
|
||||
hestia_print_error_message_to_cli "update_module not enabled after enable command"
|
||||
exit 1
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
hestia_print_error_message_to_cli "Failed to parse JSON from state command: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "Failed to enable update_module"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage8') do
|
||||
hestia_change_sys_config_value("PROXY_PORT", "8078")
|
||||
hestia_change_sys_config_value("PROXY_SSL_PORT", "8079")
|
||||
end
|
||||
#stage8 активация из запуск nginx-system
|
||||
log_migrate_stage('stage9') do
|
||||
# Delete all contents inside /etc/nginx
|
||||
FileUtils.rm_rf Dir.glob('/etc/nginx/*')
|
||||
# Stop nginx service
|
||||
system('systemctl stop nginx')
|
||||
# Start nginx-system service
|
||||
system('systemctl enable nginx-system')
|
||||
system('systemctl start nginx-system')
|
||||
end
|
||||
when :migratetobunkerweb
|
||||
log_migrate_stage('stage10') do
|
||||
if system('/usr/local/hestia/bin/v-ext-modules enable bunkerweb_module')
|
||||
output = IO.popen("/usr/local/hestia/bin/v-ext-modules state bunkerweb_module json").read
|
||||
begin
|
||||
parsed = JSON.parse(output)
|
||||
if parsed.is_a?(Array) && parsed.first && parsed.first['STATE'] == 'enabled'
|
||||
result = system('/usr/local/hestia/bin/v-ext-modules-run bunkerweb_module configure')
|
||||
unless result
|
||||
hestia_print_error_message_to_cli "bunkerweb_module configure command failed"
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "bunkerweb_module not enabled after enable command"
|
||||
exit 1
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
hestia_print_error_message_to_cli "Failed to parse JSON from state command: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "Failed to enable bunkerweb_module"
|
||||
exit 1
|
||||
end
|
||||
hestia_print_info_message_to_cli "Ожидаем минуту для перезапуска сервиса bunkerweb..."
|
||||
sleep 60
|
||||
end
|
||||
LIST_DOMAINS=[]
|
||||
|
||||
log_migrate_stage('stage11') do
|
||||
hestia_print_info_message_to_cli "Stage 11: Migrating users and domains to BunkerWeb..."
|
||||
|
||||
# Get all users from HestiaCP in JSON format
|
||||
user_list_output = IO.popen("/usr/local/hestia/bin/v-list-users json").read
|
||||
begin
|
||||
user_data = JSON.parse(user_list_output)
|
||||
rescue JSON::ParserError => e
|
||||
hestia_print_error_message_to_cli "Failed to parse users JSON: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
|
||||
# Iterate over each user
|
||||
user_data.each do |username, user_info|
|
||||
next unless user_info.is_a?(Hash)
|
||||
|
||||
web_domains_count = user_info['U_WEB_DOMAINS']
|
||||
next unless web_domains_count && web_domains_count.to_i > 0
|
||||
|
||||
hestia_print_info_message_to_cli "Processing user: #{username} (#{web_domains_count} domains)"
|
||||
|
||||
# Get web domains for this user in JSON format
|
||||
domain_list_output = IO.popen("/usr/local/hestia/bin/v-list-web-domains #{username} json").read
|
||||
begin
|
||||
domain_data = JSON.parse(domain_list_output)
|
||||
rescue JSON::ParserError => e
|
||||
hestia_print_error_message_to_cli "Failed to parse domains JSON for user #{username}: #{e.message}"
|
||||
next
|
||||
end
|
||||
|
||||
# Process each domain
|
||||
domain_data.each do |domain_name, domain_info|
|
||||
next unless domain_info.is_a?(Hash)
|
||||
|
||||
ssl_status = domain_info['SSL'] || 'no'
|
||||
is_ssl = ssl_status == 'yes'
|
||||
|
||||
# Get IP from domain info - should be available in the parsed JSON
|
||||
proxy_host = domain_info['IP'] || (domain_info['IP6'].present? ? domain_info['IP6'].strip : "127.0.0.1")
|
||||
proxy_host = proxy_host.nil? || proxy_host.empty? ? "127.0.0.1" : proxy_host
|
||||
|
||||
# Create alias list from domain info (ALIAS field contains comma-separated aliases)
|
||||
raw_aliases = domain_info['ALIAS'] || ''
|
||||
if raw_aliases && !raw_aliases.empty?
|
||||
# Hestia uses comma-separated, pass as-is to v-bunkerweb-module (it handles conversion internally)
|
||||
aliases_list = raw_aliases
|
||||
else
|
||||
aliases_list = domain_name # No aliases, use domain name only
|
||||
end
|
||||
|
||||
hestia_print_info_message_to_cli "Processing domain: #{domain_name} (SSL: #{is_ssl}, IP: #{proxy_host})"
|
||||
|
||||
begin
|
||||
# Add domain to BunkerWeb via module script (without SSL)
|
||||
cmd = "/usr/local/hestia/bin/v-bunkerweb-module add #{domain_name} #{proxy_host}"
|
||||
puts_cmd = " Added #{domain_name}: Executing command: #{cmd}"
|
||||
hestia_print_info_message_to_cli puts_cmd
|
||||
|
||||
result = system(cmd)
|
||||
|
||||
if result
|
||||
# Команда успешно выполнена
|
||||
hestia_print_info_message_to_cli " Status: Success"
|
||||
else
|
||||
hestia_print_error_message_to_cli " Failed to add domain #{domain_name}"
|
||||
next
|
||||
end
|
||||
rescue => e
|
||||
hestia_print_error_message_to_cli "Failed to add domain #{domain_name} to BunkerWeb: #{e.message}"
|
||||
next
|
||||
end
|
||||
|
||||
# Add aliases to the domain via module script
|
||||
begin
|
||||
cmd = "/usr/local/hestia/bin/v-bunkerweb-module alias #{domain_name} \"#{aliases_list}\""
|
||||
puts_cmd = " Added aliases for #{domain_name}: Executing command: #{cmd}"
|
||||
hestia_print_info_message_to_cli puts_cmd
|
||||
|
||||
result = system(cmd)
|
||||
|
||||
if result
|
||||
hestia_print_info_message_to_cli " Status: Success"
|
||||
else
|
||||
hestia_print_error_message_to_cli " Failed to set aliases for #{domain_name}"
|
||||
next
|
||||
end
|
||||
rescue => e
|
||||
hestia_print_error_message_to_cli "Failed to set aliases for #{domain_name}: #{e.message}"
|
||||
next
|
||||
end
|
||||
|
||||
# Handle SSL configuration if enabled
|
||||
if is_ssl
|
||||
original_ssl_dir = "/home/#{username}/conf/web/#{domain_name}/ssl"
|
||||
|
||||
# Check if SSL directory and files exist
|
||||
unless Dir.exist?(original_ssl_dir) || File.exist?("#{original_ssl_dir}/#{domain_name}.pem")
|
||||
hestia_print_error_message_to_cli "Warning: SSL files not found for #{domain_name}"
|
||||
LIST_DOMAINS << {
|
||||
user: username,
|
||||
domain: domain_name,
|
||||
is_ssl: true,
|
||||
path_to_ssl: nil
|
||||
}
|
||||
next
|
||||
end
|
||||
|
||||
# Define bunkerweb directory for this domain's certificates
|
||||
bunkerweb_ssl_dir = "/home/#{username}/conf/web/#{domain_name}/ssl/bunkerweb"
|
||||
|
||||
begin
|
||||
# Create bunkerweb SSL directory if it doesn't exist
|
||||
FileUtils.mkdir_p(bunkerweb_ssl_dir)
|
||||
FileUtils.chmod(0755, bunkerweb_ssl_dir)
|
||||
|
||||
# Define paths in bunkerweb directory
|
||||
crt_path_bunkerweb = "#{bunkerweb_ssl_dir}/#{domain_name}.crt"
|
||||
cert_path_bunkerweb = "#{bunkerweb_ssl_dir}/#{domain_name}.pem"
|
||||
key_path_bunkerweb = "#{bunkerweb_ssl_dir}/#{domain_name}.key"
|
||||
|
||||
# Copy all SSL files if they exist (matching v-add-web-domain-ssl behavior)
|
||||
original_crt = "#{original_ssl_dir}/#{domain_name}.crt"
|
||||
original_pem = "#{original_ssl_dir}/#{domain_name}.pem"
|
||||
original_key = "#{original_ssl_dir}/#{domain_name}.key"
|
||||
original_ca = "#{original_ssl_dir}/#{domain_name}.ca"
|
||||
|
||||
# Copy .crt file if exists
|
||||
if File.exist?(original_crt)
|
||||
FileUtils.cp(original_crt, crt_path_bunkerweb)
|
||||
end
|
||||
|
||||
if File.exist?(original_pem)
|
||||
# Only use .pem if .crt doesn't exist (fallback like the backup script)
|
||||
FileUtils.cp(original_pem, cert_path_bunkerweb)
|
||||
end
|
||||
|
||||
# Copy .key file if exists
|
||||
if File.exist?(original_key)
|
||||
FileUtils.cp(original_key, key_path_bunkerweb)
|
||||
end
|
||||
|
||||
# Copy .ca file if exists
|
||||
if File.exist?(original_ca)
|
||||
FileUtils.cp(original_ca, "#{bunkerweb_ssl_dir}/#{domain_name}.ca")
|
||||
end
|
||||
|
||||
# Set ownership and permissions (nginx user can read, others cannot)
|
||||
FileUtils.chown('root', 'nginx', bunkerweb_ssl_dir)
|
||||
FileUtils.chmod(0755, bunkerweb_ssl_dir)
|
||||
|
||||
FileUtils.chown('root', 'nginx', cert_path_bunkerweb) if File.exist?(cert_path_bunkerweb)
|
||||
FileUtils.chmod(0640, cert_path_bunkerweb) if File.exist?(cert_path_bunkerweb)
|
||||
|
||||
FileUtils.chown('root', 'nginx', key_path_bunkerweb) if File.exist?(key_path_bunkerweb)
|
||||
FileUtils.chmod(0640, key_path_bunkerweb) if File.exist?(key_path_bunkerweb)
|
||||
|
||||
FileUtils.chown('root', 'nginx', crt_path_bunkerweb) if File.exist?(crt_path_bunkerweb)
|
||||
FileUtils.chmod(0640, crt_path_bunkerweb) if File.exist?(crt_path_bunkerweb)
|
||||
|
||||
# Add SSL configuration to BunkerWeb via module script (use proxy_host from earlier)
|
||||
|
||||
cmd = "/usr/local/hestia/bin/v-bunkerweb-module addssl #{domain_name} #{crt_path_bunkerweb} #{key_path_bunkerweb}"
|
||||
puts_cmd = " Added SSL for #{domain_name}: Executing command: #{cmd}"
|
||||
hestia_print_info_message_to_cli puts_cmd
|
||||
|
||||
result = system(cmd)
|
||||
|
||||
if result
|
||||
hestia_print_info_message_to_cli " Status: Success"
|
||||
else
|
||||
hestia_print_error_message_to_cli " Failed to configure SSL for #{domain_name}"
|
||||
end
|
||||
|
||||
# Update path_to_ssl to point to bunkerweb directory
|
||||
ssl_cert_path = crt_path_bunkerweb
|
||||
rescue => e
|
||||
hestia_print_error_message_to_cli "Failed to configure SSL for #{domain_name}: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
# Populate LIST_DOMAINS array with domain info
|
||||
LIST_DOMAINS << {
|
||||
user: username,
|
||||
domain: domain_name,
|
||||
proxy_host: proxy_host.to_s,
|
||||
is_ssl: is_ssl == true ? "yes" : "no", # Convert boolean/string to proper string format
|
||||
path_to_ssl: ssl_cert_path ? ssl_cert_path : nil
|
||||
}
|
||||
|
||||
hestia_print_info_message_to_cli "Successfully migrated #{domain_name} for user #{username}"
|
||||
end
|
||||
end
|
||||
|
||||
# Output the populated LIST_DOMAINS array
|
||||
if !LIST_DOMAINS.empty?
|
||||
hestia_print_info_message_to_cli "\n=== Populated LIST_DOMAINS ==="
|
||||
LIST_DOMAINS.each_with_index do |entry, idx|
|
||||
hestia_print_info_message_to_cli "#{idx + 1}. user: #{entry[:user]}, domain: #{entry[:domain]}, is_ssl: #{entry[:is_ssl].to_s}, path_to_ssl: #{entry[:path_to_ssl]}"
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "No domains were migrated to BunkerWeb"
|
||||
end
|
||||
|
||||
hestia_print_info_message_to_cli "Stage 11 completed."
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "unknown command (use migratetobunkerweb or migratenginx)"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
267
bin/v-bunkerweb-module
Executable file
@@ -0,0 +1,267 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: action with bunkerweb API
|
||||
# options: COMMAND [SERVICE_NAME | SSL_CERT | SSL_KEY | FORMAT]
|
||||
#
|
||||
# example: v-bunkerweb-module list json
|
||||
#
|
||||
# This function enables and disables additional modules
|
||||
#
|
||||
# Commands:
|
||||
# add [domain_name] [ip]
|
||||
# addssl [domain_name] [SSL_CERT_PATH] [SSL_KEY_PATH]
|
||||
# delete [domain_name]
|
||||
# updssl [domain] [SSL_CERT_PATH] [SSL_KEY_PATH]
|
||||
# list
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
v_command = ARGV[0]
|
||||
v_format = nil
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
require "HestiaBunkerWebApi"
|
||||
|
||||
require 'json' unless defined?(JSON)
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
check_args 1, ARGV, "COMMAND [COMMAND_OPTIONS] [ACTION]"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
case v_command.to_sym
|
||||
when :add
|
||||
|
||||
v_domain = ARGV[1].strip
|
||||
v_ip = ARGV[2] ? ARGV[2].strip : nil
|
||||
v_format = ARGV[3] unless ARGV[2].nil?
|
||||
|
||||
if v_domain.nil? || v_domain == "" || v_ip.nil? || v_ip == ""
|
||||
hestia_print_error_message_to_cli "domain and ip should not be empty"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
else
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
if existing_services["services"].any? { |s| s["id"] == v_domain }
|
||||
hestia_print_error_message_to_cli "domain already exists"
|
||||
log_event E_EXISTS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
api.create_service(v_domain, {
|
||||
ssl: "no",
|
||||
reverse_proxy_host: "http://#{v_ip}:#{$PROXY_PORT}"
|
||||
})
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
when :alias
|
||||
|
||||
v_domain = ARGV[1].strip
|
||||
v_alias = ARGV[2].strip
|
||||
v_format = ARGV[3] unless ARGV[3].nil?
|
||||
|
||||
if v_domain.nil? || v_domain == ""
|
||||
hestia_print_error_message_to_cli "domain should not be empty"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
else
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
unless result_arr.any? { |s| s["id"] == v_domain }
|
||||
hestia_print_error_message_to_cli "domain does not exist"
|
||||
log_event E_NOTEXIST, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
api.set_alias(v_domain, v_alias)
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
when :delete
|
||||
|
||||
v_domain = ARGV[1].strip
|
||||
v_format = ARGV[2] unless ARGV[2].nil?
|
||||
|
||||
if v_domain.nil? || v_domain == ""
|
||||
hestia_print_error_message_to_cli "domain should not be empty"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
else
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
unless result_arr.any? { |s| s["id"] == v_domain }
|
||||
hestia_print_error_message_to_cli "domain does not exist"
|
||||
log_event E_NOTEXIST, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
api.delete_service(v_domain)
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
when :addssl, :updssl
|
||||
|
||||
v_domain = ARGV[1].strip
|
||||
v_ssl_cert = ARGV[2]
|
||||
v_ssl_key = ARGV[3]
|
||||
v_format = ARGV[4] unless ARGV[4].nil?
|
||||
|
||||
if v_domain.nil? || v_domain == "" || v_ssl_cert.nil? || v_ssl_key.nil? || !File.exist?(v_ssl_cert) || !File.exist?(v_ssl_key)
|
||||
hestia_print_error_message_to_cli "domain, SSL cert and key must be provided and must exist"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
else
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
unless result_arr.any? { |s| s["id"] == v_domain }
|
||||
hestia_print_error_message_to_cli "domain does not exist"
|
||||
log_event E_NOTEXIST, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
api.update_service_ssl(v_domain, v_ssl_cert, v_ssl_key)
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
when :deletessl
|
||||
|
||||
v_domain = ARGV[1].strip
|
||||
v_format = ARGV[2] unless ARGV[2].nil?
|
||||
|
||||
if v_domain.nil? || v_domain == ""
|
||||
hestia_print_error_message_to_cli "domain should not be empty"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
else
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
unless result_arr.any? { |s| s["id"] == v_domain }
|
||||
hestia_print_error_message_to_cli "domain does not exist"
|
||||
log_event E_NOTEXIST, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
api.delete_service_ssl(v_domain)
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
when :list
|
||||
v_format = ARGV[1] unless ARGV[1].nil?
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888")
|
||||
existing_services = api.list_services()
|
||||
if existing_services.nil?
|
||||
result_arr = []
|
||||
else
|
||||
if existing_services["services"]
|
||||
result_arr = existing_services["services"]
|
||||
else
|
||||
result_arr = []
|
||||
end
|
||||
end
|
||||
hestia_print_array_of_hashes(result_arr, v_format, "id, method, is_draft, creation_date, last_update, template, security_mode")
|
||||
rescue BunkerWebApiError => e
|
||||
hestia_print_error_message_to_cli "[ERROR] Ошибка API: #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "unknown command"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
488
bin/v-bunkerweb-module-install
Executable file
@@ -0,0 +1,488 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: action with bunkerweb API
|
||||
# options: [SSL_CERT_PATH SSL_KEY_PATH]
|
||||
#
|
||||
# example: v-bunkerweb-module-install
|
||||
#
|
||||
# This function enables and disables additional modules
|
||||
#
|
||||
#------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
require "HestiaBunkerWebApi"
|
||||
require "securerandom"
|
||||
require "socket"
|
||||
require 'json' unless defined?(JSON)
|
||||
require 'etc'
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#------------------------------------------#
|
||||
# Action #
|
||||
#------------------------------------------#
|
||||
|
||||
puts "========================================================"
|
||||
puts "=== AUTOMATED BUNKERWEB SETUP SCRIPT ==="
|
||||
puts "========================================================"
|
||||
puts ""
|
||||
|
||||
# Parse command line arguments for SSL cert and key paths
|
||||
SSL_CERT_PATH = ARGV[0] || nil # First argument: SSL certificate path
|
||||
SSL_KEY_PATH = ARGV[1] || nil # Second argument: SSL key path
|
||||
|
||||
# Generate secure passwords (meeting BunkerWeb password policy requirements)
|
||||
api_env_file = "/etc/bunkerweb/api.env"
|
||||
api_password = nil
|
||||
if File.exist?(api_env_file)
|
||||
File.foreach(api_env_file) do |line|
|
||||
if line =~ /^\s*API_PASSWORD=(.*)/
|
||||
val = $1.strip
|
||||
api_password = val unless val.empty?
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
specials = '!@#$%^&*()-_=+[]{}|;:,.<>?'
|
||||
API_PASSWORD = api_password || (SecureRandom.alphanumeric(24) + specials.chars.sample(3).join).chars.shuffle.join
|
||||
|
||||
ui_env_file = "/etc/bunkerweb/ui.env"
|
||||
admin_password = nil
|
||||
if File.exist?(ui_env_file)
|
||||
File.foreach(ui_env_file) do |line|
|
||||
if line =~ /^\s*ADMIN_PASSWORD=(.*)/
|
||||
val = $1.strip
|
||||
admin_password = val unless val.empty?
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
ADMIN_PASSWORD = admin_password || (SecureRandom.alphanumeric(24) + specials.chars.sample(3).join).chars.shuffle.join
|
||||
|
||||
puts "[INFO] Get server IP address"
|
||||
|
||||
server_ip_addr = "127.0.0.1" # default fallback
|
||||
# Attempt to retrieve server IP via Hestia utility
|
||||
begin
|
||||
cmd = "/usr/local/hestia/bin/v-list-sys-ips json"
|
||||
ips_output = `#{cmd}`.strip
|
||||
unless ips_output.empty?
|
||||
parsed_ips = JSON.parse(ips_output)
|
||||
parsed_ips.each do |ip, details|
|
||||
if details["OWNER"] == "admin"
|
||||
server_ip_addr = ip
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue JSON::ParserError, Errno::ENOENT
|
||||
# If the command fails or output is invalid, keep default fallback
|
||||
end
|
||||
|
||||
puts ""
|
||||
|
||||
# Compute nginx group ID once
|
||||
nginx_gid = Etc.getgrnam('nginx').gid
|
||||
|
||||
# Step 1: Create /etc/bunkerweb/api.env configuration file
|
||||
puts "[INFO] Creating API configuration at /etc/bunkerweb/api.env..."
|
||||
api_env_content = <<~APIENV
|
||||
# ==============================
|
||||
# BunkerWeb API Configuration
|
||||
# This file lists all supported API environment variables with their defaults.
|
||||
# Uncomment and adjust as needed. Lines starting with # are ignored.
|
||||
# ==============================
|
||||
|
||||
# --- Network & Proxy ---
|
||||
# Listen address/port for the API
|
||||
LISTEN_ADDR=127.0.0.1
|
||||
LISTEN_PORT=8888
|
||||
# Trusted proxy IPs for X-Forwarded-* headers (comma-separated).
|
||||
# Default is restricted to loopback for security.
|
||||
FORWARDED_ALLOW_IPS=127.0.0.1,::1
|
||||
# Trusted proxy IPs for PROXY protocol (comma-separated).
|
||||
# Defaults to FORWARDED_ALLOW_IPS when unset.
|
||||
PROXY_ALLOW_IPS=127.0.0.1,::1
|
||||
|
||||
# --- Logging & Runtime ---
|
||||
# LOG_LEVEL affects most components; CUSTOM_LOG_LEVEL overrides when provided.
|
||||
# LOG_LEVEL=info
|
||||
LOG_TYPES=file
|
||||
LOG_FILE_PATH=/var/log/bunkerweb/api.log
|
||||
# Number of workers/threads (auto if unset).
|
||||
# MAX_WORKERS=<auto>
|
||||
# MAX_THREADS=<auto>
|
||||
|
||||
# --- Authentication & Authorization ---
|
||||
# Optional admin Bearer token (grants full access when provided).
|
||||
# API_TOKEN=#{API_PASSWORD}
|
||||
# Bootstrap admin user (created/validated on startup if provided).
|
||||
API_USERNAME=admin
|
||||
API_PASSWORD=#{API_PASSWORD}
|
||||
# Force re-applying bootstrap admin credentials on startup (use with care).
|
||||
# OVERRIDE_API_CREDS=no
|
||||
# Fine-grained ACLs can be enabled/disabled here.
|
||||
# API_ACL_BOOTSTRAP_FILE=
|
||||
|
||||
# --- IP allowlist ---
|
||||
# Enable and shape inbound IP allowlist for the API.
|
||||
API_WHITELIST_ENABLED=yes
|
||||
WHITELIST_IPS=127.0.0.1
|
||||
|
||||
# --- FastAPI surface ---
|
||||
# Customize or disable documentation endpoints. Use 'disabled' to turn off.
|
||||
# API_TITLE=BunkerWeb API
|
||||
# API_DOCS_URL=/docs
|
||||
# API_REDOC_URL=/redoc
|
||||
# API_OPENAPI_URL=/openapi.json
|
||||
# Mount the API under a subpath (useful behind reverse proxies).
|
||||
# API_ROOT_PATH=
|
||||
|
||||
# --- TLS/SSL ---
|
||||
# Enable TLS for the API listener (requires cert and key).
|
||||
# API_SSL_ENABLED=no
|
||||
# Path to PEM-encoded certificate and private key.
|
||||
# API_SSL_CERTFILE=/etc/ssl/certs/bunkerweb-api.crt
|
||||
# API_SSL_KEYFILE=/etc/ssl/private/bunkerweb-api.key
|
||||
# Optional chain/CA bundle and cipher suite.
|
||||
# API_SSL_CA_CERTS=
|
||||
# API_SSL_CIPHERS_CUSTOM=
|
||||
# API_SSL_CIPHERS_LEVEL=modern # choices: modern|intermediate
|
||||
|
||||
# --- Biscuit keys & policy ---
|
||||
# Bind token to client IP (except private ranges).
|
||||
# CHECK_PRIVATE_IP=yes
|
||||
# Biscuit token lifetime in seconds (0 disables expiry).
|
||||
# API_BISCUIT_TTL_SECONDS=3600
|
||||
# Provide Biscuit keys via env (hex) instead of files.
|
||||
# BISCUIT_PUBLIC_KEY=
|
||||
# BISCUIT_PRIVATE_KEY=
|
||||
|
||||
# --- Rate limiting ---
|
||||
# Enable/disable and shape rate limiting.
|
||||
API_RATE_LIMIT_ENABLED=no
|
||||
API_RATE_LIMIT_HEADERS_ENABLED=no
|
||||
# Global default limit (times per seconds).
|
||||
# API_RATE_LIMIT_TIMES=100
|
||||
# API_RATE_LIMIT_SECONDS=60
|
||||
# Authentication endpoint limit.
|
||||
# API_RATE_LIMIT_AUTH_TIMES=10
|
||||
# API_RATE_LIMIT_AUTH_SECONDS=60
|
||||
# Advanced limits and rules (CSV/JSON/YAML).
|
||||
# API_RATE_LIMIT_DEFAULTS="200/minute"
|
||||
# API_RATE_LIMIT_APPLICATION_LIMITS=
|
||||
# API_RATE_LIMIT_RULES=
|
||||
# Strategy: fixed-window | moving-window | sliding-window-counter
|
||||
# API_RATE_LIMIT_STRATEGY=fixed-window
|
||||
# Key selector: ip | user | path | method | header:<Name>
|
||||
# API_RATE_LIMIT_KEY=ip
|
||||
# Exempt IPs (space or comma-separated CIDRs).
|
||||
# API_RATE_LIMIT_EXEMPT_IPS=
|
||||
# Storage options in JSON (merged with Redis settings if USE_REDIS=yes).
|
||||
# API_RATE_LIMIT_STORAGE_OPTIONS=
|
||||
|
||||
# --- Redis (optional, for rate limiting storage) ---
|
||||
# USE_REDIS=no
|
||||
# REDIS_HOST=
|
||||
# REDIS_PORT=6379
|
||||
# REDIS_DATABASE=0
|
||||
# REDIS_USERNAME=
|
||||
# REDIS_PASSWORD=
|
||||
# REDIS_SSL=no
|
||||
# REDIS_SSL_VERIFY=yes
|
||||
# REDIS_TIMEOUT=1000
|
||||
# REDIS_KEEPALIVE_POOL=10
|
||||
# REDIS_SENTINEL_HOSTS=sentinel1:26379 sentinel2:26379
|
||||
# REDIS_SENTINEL_MASTER=mymaster
|
||||
# REDIS_SENTINEL_USERNAME=
|
||||
# REDIS_SENTINEL_PASSWORD=
|
||||
APIENV
|
||||
|
||||
File.write("/etc/bunkerweb/api.env", api_env_content)
|
||||
File.chmod(0o660, "/etc/bunkerweb/api.env")
|
||||
File.chown(0, nginx_gid, "/etc/bunkerweb/api.env")
|
||||
puts "[SUCCESS] API configuration file created at /etc/bunkerweb/api.env"
|
||||
puts ""
|
||||
|
||||
variables_env_content = <<~VENV
|
||||
DNS_RESOLVERS=9.9.9.9 149.112.112.112 8.8.8.8 8.8.4.4
|
||||
HTTP_PORT=80
|
||||
HTTPS_PORT=443
|
||||
API_LISTEN_IP=127.0.0.1
|
||||
MULTISITE=yes
|
||||
UI_HOST=http://127.0.0.1:7000
|
||||
SERVER_NAME=
|
||||
|
||||
API_WHITELIST_IP=127.0.0.0/8
|
||||
USE_SERVE_FILES=no
|
||||
VENV
|
||||
|
||||
File.write("/etc/bunkerweb/variables.env", variables_env_content)
|
||||
File.chmod(0o660, "/etc/bunkerweb/variables.env")
|
||||
File.chown(0, nginx_gid, "/etc/bunkerweb/variables.env")
|
||||
puts "[SUCCESS] Variables configuration file created at /etc/bunkerweb/variables.env"
|
||||
puts ""
|
||||
|
||||
# Step 2: Enable and start bunkerweb-api service, wait for it to be running
|
||||
puts "[INFO] Enabling bunkerweb-api service..."
|
||||
system("systemctl enable bunkerweb-api")
|
||||
puts "[INFO] Starting bunkerweb-api service..."
|
||||
system("systemctl start bunkerweb-api")
|
||||
|
||||
sleep(30)
|
||||
|
||||
# Wait for the service to be ready (max 30 seconds)
|
||||
puts "[INFO] Waiting for bunkerweb-api service to be running..."
|
||||
max_attempts = 60 # Wait up to 30 seconds (check every half second)
|
||||
attempt = 0
|
||||
|
||||
while attempt < max_attempts
|
||||
status_output = `systemctl is-active bunkerweb-api 2>&1`
|
||||
status = status_output.strip
|
||||
|
||||
if status == "active" || status == "running"
|
||||
puts "[SUCCESS] bunkerweb-api service is running!"
|
||||
break
|
||||
elsif status == "failed"
|
||||
puts "[ERROR] bunkerweb-api service failed to start!"
|
||||
exit 1
|
||||
else
|
||||
print "."
|
||||
sleep(0.5)
|
||||
attempt += 1
|
||||
end
|
||||
end
|
||||
|
||||
if attempt >= max_attempts
|
||||
puts ""
|
||||
puts "[ERROR] bunkerweb-api service did not become active within timeout"
|
||||
puts "[INFO] Current status: #{status_output.strip}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
puts ""
|
||||
|
||||
# Step 3: Configure UI settings based on documentation at https://docs.bunkerweb.io/latest/web-ui/
|
||||
puts "[INFO] Configuring Web UI..."
|
||||
|
||||
# Determine SSL settings for UI
|
||||
ui_ssl_enabled = "no"
|
||||
if SSL_CERT_PATH && SSL_KEY_PATH && File.exist?(SSL_CERT_PATH) && File.exist?(SSL_KEY_PATH)
|
||||
ui_ssl_enabled = "yes"
|
||||
end
|
||||
|
||||
ui_env_content = <<~UIENV
|
||||
# ==============================
|
||||
# BunkerWeb UI Configuration
|
||||
# This file configures the Web UI settings.
|
||||
# ==============================
|
||||
|
||||
# --- Listener & TLS ---
|
||||
# Bind address for the UI (use server IP for external access)
|
||||
UI_LISTEN_ADDR=127.0.0.1
|
||||
# Bind port for the UI
|
||||
UI_LISTEN_PORT=7000
|
||||
# Enable TLS in the UI container
|
||||
UI_SSL_ENABLED=#{ui_ssl_enabled}
|
||||
UIENV
|
||||
|
||||
# Add SSL cert/key paths if provided
|
||||
if ui_ssl_enabled == "yes"
|
||||
ui_env_content += <<~SSLCONF
|
||||
|
||||
# SSL Certificate and Key paths
|
||||
UI_SSL_CERTFILE=#{SSL_CERT_PATH}
|
||||
UI_SSL_KEYFILE=#{SSL_KEY_PATH}
|
||||
SSLCONF
|
||||
end
|
||||
|
||||
ui_env_content += <<~UIENV2
|
||||
|
||||
# --- Admin Authentication ---
|
||||
# Seed admin account
|
||||
ADMIN_USERNAME=admin
|
||||
ADMIN_PASSWORD=#{ADMIN_PASSWORD}
|
||||
|
||||
# --- Proxy settings ---
|
||||
# Trusted proxy IPs for X-Forwarded-* headers
|
||||
# UI_FORWARDED_ALLOW_IPS=127.0.0.1,::1
|
||||
|
||||
UIENV2
|
||||
|
||||
File.write("/etc/bunkerweb/ui.env", ui_env_content)
|
||||
File.chmod(0o660, "/etc/bunkerweb/ui.env")
|
||||
File.chown(0, nginx_gid, "/etc/bunkerweb/ui.env")
|
||||
puts "[SUCCESS] UI configuration file created at /etc/bunkerweb/ui.env"
|
||||
puts ""
|
||||
|
||||
# Step 4: Reload the bunkerweb-ui service to apply new configuration
|
||||
puts "[INFO] Reloading bunkerweb-ui service..."
|
||||
system("systemctl restart bunkerweb-ui")
|
||||
|
||||
# Wait for UI to be ready (max 10 seconds)
|
||||
sleep(2)
|
||||
|
||||
if system("systemctl is-active bunkerweb-ui >/dev/null 2>&1")
|
||||
puts "[SUCCESS] bunkerweb-ui service is running!"
|
||||
else
|
||||
puts "[WARN] bunkerweb-ui service status could not be verified"
|
||||
end
|
||||
|
||||
puts ""
|
||||
|
||||
# Step 5: Now proceed with the original service creation logic
|
||||
puts "[INFO] Connecting to BunkerWeb API..."
|
||||
|
||||
API_URL = "http://127.0.0.1:8888"
|
||||
|
||||
USERNAME = "admin"
|
||||
PASSWORD = API_PASSWORD
|
||||
|
||||
# Default services to create after setup
|
||||
DEFAULT_SERVICES = [
|
||||
{
|
||||
name: "#{server_ip_addr}",
|
||||
options: {
|
||||
ssl: "no",
|
||||
reverse_proxy_host: "http://127.0.0.1:7000",
|
||||
use_template: "ui",
|
||||
reverse_proxy_url: "/kormilo",
|
||||
use_reverse_proxy: "yes"
|
||||
}
|
||||
},
|
||||
# Add more services here if needed:
|
||||
# {
|
||||
# name: "secure.example.com",
|
||||
# options: {
|
||||
# ssl: "yes",
|
||||
# certificate_path: "/etc/ssl/certs/example.crt",
|
||||
# key_path: "/etc/ssl/private/example.key"
|
||||
# }
|
||||
# }
|
||||
]
|
||||
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new(API_URL, USERNAME, PASSWORD)
|
||||
|
||||
puts ""
|
||||
puts "[SUCCESS] API connected successfully!"
|
||||
puts ""
|
||||
|
||||
# List existing services
|
||||
services = api.list_services()
|
||||
services = api.list_services()
|
||||
if services && services.is_a?(Hash) && services.key?('services')
|
||||
services = services['services']
|
||||
services = nil if services.is_a?(Array) && services.empty?
|
||||
else
|
||||
services = nil
|
||||
end
|
||||
if services.nil?
|
||||
puts "[INFO] No services found - creating default configuration..."
|
||||
|
||||
DEFAULT_SERVICES.each do |service_config|
|
||||
begin
|
||||
puts "[INFO] Creating service: #{service_config[:name]}"
|
||||
result = api.create_service(service_config[:name], service_config[:options])
|
||||
puts " ✓ Service '#{service_config[:name]}' created"
|
||||
rescue BunkerWebApiError => e
|
||||
if e.message.include?("already exists")
|
||||
puts " ℹ Service '#{service_config[:name]}' already exists, skipping..."
|
||||
else
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
puts "[SUCCESS] Default services created!"
|
||||
|
||||
else
|
||||
puts "[INFO] Existing services:"
|
||||
services.each { |s| puts " - #{s['server_name']}" }
|
||||
puts ""
|
||||
end
|
||||
|
||||
# Reload configuration on all instances
|
||||
puts "[INFO] Reloading configuration..."
|
||||
api.reload_instance()
|
||||
|
||||
puts "[INFO] Restarting bunkerweb service..."
|
||||
system("systemctl restart bunkerweb")
|
||||
puts "[INFO] Restarting bunkerweb-scheduler service..."
|
||||
system("systemctl restart bunkerweb-scheduler")
|
||||
|
||||
puts ""
|
||||
puts "======================================================"
|
||||
puts "=== SETUP COMPLETED SUCCESSFULLY ==="
|
||||
puts "======================================================"
|
||||
puts ""
|
||||
puts "Web UI is now accessible at:"
|
||||
if ui_ssl_enabled == "yes"
|
||||
puts " https://#{server_ip_addr}/kormilo"
|
||||
else
|
||||
puts " http://#{server_ip_addr}/kormilo"
|
||||
end
|
||||
puts ""
|
||||
puts "API URL: #{API_URL}"
|
||||
puts ""
|
||||
puts "API Credentials:"
|
||||
puts " Username: admin"
|
||||
puts " Password: #{PASSWORD}"
|
||||
puts ""
|
||||
|
||||
puts "UI Credentials:"
|
||||
puts " Username: admin"
|
||||
puts " Password: #{ADMIN_PASSWORD}"
|
||||
puts ""
|
||||
|
||||
rescue BunkerWebApiError => e
|
||||
|
||||
if e.message.include?("Authentication") || e.message.include?("Connection refused")
|
||||
puts "[ERROR] Could not connect to BunkerWeb API"
|
||||
puts "[INFO] This means the setup has NOT been completed correctly"
|
||||
puts ""
|
||||
puts "Please verify that:"
|
||||
puts " 1. bunkerweb-api service is running: systemctl status bunkerweb-api"
|
||||
puts " 2. API configuration file exists at /etc/bunkerweb/api.env"
|
||||
puts " 3. Check logs: journalctl -u bunkerweb-api -f"
|
||||
puts ""
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
|
||||
else
|
||||
puts "[ERROR] #{e.message}"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
rescue => e
|
||||
puts "[ERROR] Unexpected error: #{e.message}"
|
||||
puts "Backtrace:"
|
||||
puts e.backtrace.inspect
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
@@ -68,13 +68,13 @@ if [ "$type" = "pma" ] || [ "$type" = "PMA" ] || [ "$type" = "phpmyadmin" ]; the
|
||||
$BIN/v-restart-service httpd
|
||||
fi
|
||||
|
||||
if [ -e "/etc/nginx/conf.d/phpmyadmin.inc" ]; then
|
||||
rm -f /etc/nginx/conf.d/phpmyadmin.inc
|
||||
cp -f $HESTIA_INSTALL_DIR/nginx/phpmyadmin.inc /etc/nginx/conf.d/phpmyadmin.inc
|
||||
sed -i "s|%pma_alias%|$alias|g" /etc/nginx/conf.d/phpmyadmin.inc
|
||||
if [ -e "/usr/local/hestia/nginx-system/etc/nginx/conf.d/phpmyadmin.inc" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/nginx/conf.d/phpmyadmin.inc
|
||||
cp -f $HESTIA_INSTALL_DIR/nginx/phpmyadmin.inc /usr/local/hestia/nginx-system/etc/nginx/conf.d/phpmyadmin.inc
|
||||
sed -i "s|%pma_alias%|$alias|g" /usr/local/hestia/nginx-system/etc/nginx/conf.d/phpmyadmin.inc
|
||||
|
||||
# Restart services
|
||||
$BIN/v-restart-service nginx
|
||||
$BIN/v-restart-service nginx-system
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -105,13 +105,13 @@ if [ "$type" = "pga" ] || [ "$type" = "PGA" ] || [ "$type" = "phppgadmin" ]; the
|
||||
$BIN/v-restart-service httpd
|
||||
fi
|
||||
|
||||
if [ -e "/etc/nginx/conf.d/phppgadmin.inc" ]; then
|
||||
rm -f /etc/nginx/conf.d/phppgadmin.inc
|
||||
cp -f $HESTIA_INSTALL_DIR/nginx/phppgadmin.inc /etc/nginx/conf.d/phppgadmin.inc
|
||||
sed -i "s|%pga_alias%|$alias|g" /etc/nginx/conf.d/phppgadmin.inc
|
||||
if [ -e "/usr/local/hestia/nginx-system/etc/nginx/conf.d/phppgadmin.inc" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/nginx/conf.d/phppgadmin.inc
|
||||
cp -f $HESTIA_INSTALL_DIR/nginx/phppgadmin.inc /usr/local/hestia/nginx-system/etc/nginx/conf.d/phppgadmin.inc
|
||||
sed -i "s|%pga_alias%|$alias|g" /usr/local/hestia/nginx-system/etc/nginx/conf.d/phppgadmin.inc
|
||||
|
||||
# Restart services
|
||||
$BIN/v-restart-service nginx
|
||||
$BIN/v-restart-service nginx-system
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/bash
|
||||
# info: change hostname
|
||||
# options: HOSTNAME
|
||||
#
|
||||
@@ -37,18 +37,20 @@ check_hestia_demo_mode
|
||||
|
||||
hostname "$domain"
|
||||
|
||||
if [ -d "/etc/sysconfig" ]; then
|
||||
# RHEL/CentOS/Amazon
|
||||
touch /etc/sysconfig/network
|
||||
if [ -z "$(grep HOSTNAME /etc/sysconfig/network)" ]; then
|
||||
echo "HOSTNAME='$domain'" >> /etc/sysconfig/network
|
||||
else
|
||||
sed -i "s/HOSTNAME=.*/HOSTNAME='$domain'/" /etc/sysconfig/network
|
||||
fi
|
||||
if command -v hostnamectl >/dev/null 2>&1; then
|
||||
hostnamectl set-hostname "$domain"
|
||||
echo "$domain" > /etc/hostname
|
||||
else
|
||||
# Debian/Ubuntu
|
||||
hostnamectl set-hostname "$domain"
|
||||
echo "$domain" > /etc/hostname
|
||||
if [ -d "/etc/sysconfig" ]; then
|
||||
touch /etc/sysconfig/network
|
||||
if [ -z "$(grep HOSTNAME /etc/sysconfig/network)" ]; then
|
||||
echo "HOSTNAME='$domain'" >> /etc/sysconfig/network
|
||||
else
|
||||
sed -i "s/HOSTNAME=.*/HOSTNAME='$domain'/" /etc/sysconfig/network
|
||||
fi
|
||||
else
|
||||
echo "$domain" > /etc/hostname
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update Roundcube password plugin configuration
|
||||
|
||||
@@ -21,18 +21,10 @@ source_conf "$HESTIA/conf/hestia.conf"
|
||||
check_args '1' "$#" 'VERSION'
|
||||
|
||||
# Verify php version format
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
else
|
||||
if [[ ! $version =~ ^[0-9].[0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9].[0-9]."
|
||||
echo "Example: 7.0, 7.4, 8.0"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The specified PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
|
||||
# Check if php version exists
|
||||
@@ -50,18 +42,19 @@ check_hestia_demo_mode
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Set file locations
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
php_fpm=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
php_fpm="/usr/lib/systemd/system/brepo-php-fpm$version.service"
|
||||
else
|
||||
php_fpm="/etc/init.d/php$version-fpm"
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
fi
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
rm -f /opt/brepo/php*/etc/php-fpm.d/www.conf
|
||||
cp -f $HESTIA/install/rpm/php-fpm/www.conf /opt/brepo/php${version}/etc/php-fpm.d/www.conf
|
||||
else
|
||||
rm -f /etc/opt/remi/php*/php-fpm.d/www.conf
|
||||
cp -f $HESTIA/install/rpm/php-fpm/www.conf /etc/opt/remi/php$version/php-fpm.d/www.conf
|
||||
else
|
||||
rm -f /etc/php/*/fpm/pool.d/www.conf
|
||||
cp -f $HESTIA/install/deb/php-fpm/www.conf /etc/php/$version/fpm/pool.d/www.conf
|
||||
fi
|
||||
|
||||
for user in $($BIN/v-list-sys-users plain); do
|
||||
@@ -75,17 +68,30 @@ $BIN/v-restart-web-backend
|
||||
$BIN/v-restart-web
|
||||
$BIN/v-restart-proxy
|
||||
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
result_alt_php=$(alternatives --display php | grep /opt/brepo/php${version}/bin/php)
|
||||
if [ -z "$result_alt_php" ]; then
|
||||
alternatives --install /usr/bin/php php /opt/brepo/php${version}/bin/php 1 > /dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
result_alt_php=$(alternatives --display php | grep /usr/bin/php$version)
|
||||
if [ -z "$result_alt_php" ]; then
|
||||
alternatives --install /usr/bin/php php /usr/bin/php$version 1 > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
update-alternatives --set php /usr/bin/php$version
|
||||
if [ $? -eq 0 ]; then
|
||||
update-alternatives --install /usr/bin/php php /usr/bin/php$version 1
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
update-alternatives --set php /opt/brepo/php${version}/bin/php
|
||||
if [ $? -eq 0 ]; then
|
||||
update-alternatives --install /usr/bin/php php /opt/brepo/php${version}/bin/php 1
|
||||
update-alternatives --set php /opt/brepo/php${version}/bin/php
|
||||
fi
|
||||
else
|
||||
update-alternatives --set php /usr/bin/php$version
|
||||
if [ $? -eq 0 ]; then
|
||||
update-alternatives --install /usr/bin/php php /usr/bin/php$version 1
|
||||
update-alternatives --set php /usr/bin/php$version
|
||||
fi
|
||||
fi
|
||||
/usr/bin/hestiacp-php-admin system $version
|
||||
|
||||
|
||||
@@ -40,17 +40,45 @@ check_hestia_demo_mode
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
php_v="82"
|
||||
if [[ "$service" =~ ^php ]];then
|
||||
ver_php=$(echo "$service" | grep -Po "\d+")
|
||||
if [ -z "$ver_php" ]; then
|
||||
php_v=$(get_system_default_php)
|
||||
else
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
if [ -e "/opt/brepo/php${ver_php}" ]; then
|
||||
php_v="$ver_php"
|
||||
else
|
||||
php_v=$(get_system_default_php)
|
||||
fi
|
||||
else
|
||||
if [ -e "/etc/opt/remi/php${ver_php}" ]; then
|
||||
php_v="$ver_php"
|
||||
else
|
||||
php_v=$(get_system_default_php)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
service="php"
|
||||
fi
|
||||
|
||||
# Defining dst config path
|
||||
case $service in
|
||||
nginx) dst='/etc/nginx/nginx.conf' ;;
|
||||
nginx) dst='/usr/local/hestia/nginx-system/etc/nginx/nginx.conf' ;;
|
||||
httpd) dst='/etc/httpd/conf/httpd.conf' ;;
|
||||
apache2) dst='/etc/apache2/apache2.conf' ;;
|
||||
exim) dst='/etc/exim/exim.conf' ;;
|
||||
exim4) dst='/etc/exim4/exim4.conf.template' ;;
|
||||
vsftpd) dst=$(find /etc/vsftpd* -name 'vsftpd.conf') ;;
|
||||
proftpd) dst=$(find /etc/proftpd* -name 'proftpd.conf') ;;
|
||||
php) dst=$(find /etc/php* -name php.ini) ;;
|
||||
php)
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
dst=$(find /opt/brepo/php${php_v} -name php.ini)
|
||||
else
|
||||
dst=$(find /etc/opt/remi/php${php_v} -name php.ini)
|
||||
fi
|
||||
;;
|
||||
mysql) dst=$(find /etc/my* -name my.cnf) ;;
|
||||
mysqld) dst=$(find /etc/my* -name my.cnf) ;;
|
||||
mariadb) dst=$(find /etc/my* -name my.cnf) ;;
|
||||
@@ -103,12 +131,12 @@ if [ "$update" = 'yes' ] && [ "$restart" != 'no' ]; then
|
||||
if [ "$service" = 'php' ]; then
|
||||
if [ "$(multiphp_count)" -gt 0 ]; then
|
||||
service="php-fpm"
|
||||
elif [ "$WEB_SYSTEM" = 'apache2' ]; then
|
||||
elif [ "$WEB_SYSTEM" = 'httpd' ]; then
|
||||
service="$WEB_SYSTEM"
|
||||
fi
|
||||
fi
|
||||
|
||||
$BIN/v-restart-service "$service" > /dev/null 2>&1
|
||||
$BIN/v-restart-service "$service" > /dev/null 2>&1
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
for config in $dst; do
|
||||
|
||||
@@ -88,6 +88,25 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ] && [ "$BUNKERWEB" = "yes" ]; then
|
||||
BUNKW_DIR=$HOMEDIR/$user/conf/web/$domain/ssl/bunkerweb
|
||||
if [ ! -d "$BUNKW_DIR" ]; then
|
||||
mkdir -p "$BUNKW_DIR"
|
||||
chmod 0755 "$BUNKW_DIR"
|
||||
fi
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.crt" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.key" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.pem" "$BUNKW_DIR/"
|
||||
if [ -e "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" ]; then
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" "$BUNKW_DIR/"
|
||||
fi
|
||||
chown root:nginx "$BUNKW_DIR"/*
|
||||
chmod 0640 "$BUNKW_DIR"/*
|
||||
$BIN/v-ext-modules-run bunkerweb_module addssl "$domain" "$BUNKW_DIR/$domain.pem" "$BUNKW_DIR/$domain.key"
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "SSL certificate changed (Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -31,7 +31,7 @@ SERVICE_NAME="$1"
|
||||
|
||||
case "$SERVICE_NAME" in
|
||||
nginx )
|
||||
/usr/sbin/nginx -t >> "$DEBUG_LOG_FILE" 2>&1
|
||||
/usr/local/hestia/nginx-system/sbin/nginx -t >> "$DEBUG_LOG_FILE" 2>&1
|
||||
V_RESULT=$?
|
||||
exit $V_RESULT
|
||||
;;
|
||||
@@ -47,5 +47,3 @@ esac
|
||||
|
||||
# Something like error, we shouldn't be here
|
||||
exit 1
|
||||
|
||||
|
||||
|
||||
105
bin/v-default-domain
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
# info: add web/dns/mail domain
|
||||
# options: USER DOMAIN COMMAND
|
||||
#
|
||||
# example: v-default-domain admin example.com set
|
||||
# v-default-domain admin example.com delete
|
||||
# v-default-domain admin example.com check
|
||||
# v-default-domain admin example.com check-default
|
||||
#
|
||||
# This function set user's domain as default or reset it or get default domain or check is domain default.
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
user=$1
|
||||
domain=$2
|
||||
command=$3
|
||||
|
||||
# Includes
|
||||
# shellcheck source=/etc/hestiacp/hestia.conf
|
||||
source /etc/hestiacp/hestia.conf
|
||||
# shellcheck source=/usr/local/hestia/func/main.sh
|
||||
source $HESTIA/func/main.sh
|
||||
# load config file
|
||||
source_conf "$HESTIA/conf/hestia.conf"
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
check_args '3' "$#" 'USER DOMAIN COMMAND'
|
||||
is_format_valid 'user' 'domain'
|
||||
if [ -n "$ip" ]; then
|
||||
is_format_valid 'ip'
|
||||
fi
|
||||
is_object_valid 'user' 'USER' "$user"
|
||||
is_object_unsuspended 'user' 'USER' "$user"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
confd="conf.h.d"
|
||||
|
||||
if [[ $command == check* ]]; then
|
||||
default_conf="/etc/httpd/$confd/domains/00000000000000000_default.conf"
|
||||
if [ -e "$default_conf" ]; then
|
||||
file_name=$(readlink -f "$default_conf")
|
||||
s_username=$(echo "$file_name" | cut -d"/" -f3 )
|
||||
s_domain=$(echo "$file_name" | rev | cut -d"/" -f2 | rev )
|
||||
if [ "$command" == "check-default" ]; then
|
||||
echo "$s_username:$s_domain"
|
||||
else
|
||||
if [ "$user" == "$s_username" ] && [ "$domain" == "$s_domain" ]; then
|
||||
echo "true"
|
||||
else
|
||||
echo "false"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "no default domain"
|
||||
fi
|
||||
else
|
||||
# Working on web domain
|
||||
if [ -n "$WEB_SYSTEM" ] && [ "$WEB_SYSTEM" == "httpd" ]; then
|
||||
domain_path="/etc/httpd/$confd/domains/$domain.conf"
|
||||
domain_ssl_path="/etc/httpd/$confd/domains/$domain.ssl.conf"
|
||||
if [ -e "$domain_ssl_path" ] || [ -e "$domain_path" ]; then
|
||||
path_name="$domain_path"
|
||||
if [ -e "$domain_ssl_path" ]; then
|
||||
path_name="$domain_ssl_path"
|
||||
fi
|
||||
if [ "$command" == "delete" ]; then
|
||||
if [ -e "/etc/httpd/$confd/domains/00000000000000000_default.conf" ]; then
|
||||
mv -f "/etc/httpd/$confd/domains/00000000000000000_default.conf" "/etc/httpd/$confd/domains/00000000000000000_default.conf.trash"
|
||||
fi
|
||||
else
|
||||
ln -sf "${path_name}" "/etc/httpd/$confd/domains/00000000000000000_default.conf"
|
||||
fi
|
||||
echo "true"
|
||||
else
|
||||
echo "false"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restarting services
|
||||
$BIN/v-restart-web "yes"
|
||||
check_result $? "can't restart web" > /dev/null
|
||||
|
||||
$BIN/v-restart-proxy "yes"
|
||||
check_result $? "can't restart proxy" > /dev/null
|
||||
|
||||
$BIN/v-restart-dns "yes"
|
||||
check_result $? "can't restart dns" > /dev/null
|
||||
fi
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Hestia #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
exit
|
||||
@@ -49,7 +49,7 @@ if [ -f "$HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.fastcgi_cache.conf" ]; then
|
||||
rm -rf $HOMEDIR/$user/conf/web/$domain/$WEB_SYSTEM.fastcgi_cache.conf
|
||||
fi
|
||||
|
||||
conf='/etc/nginx/conf.d/fastcgi_cache_pool.conf'
|
||||
conf='/usr/local/hestia/nginx-system/etc/nginx/conf.d/fastcgi_cache_pool.conf'
|
||||
if [ -f "$conf" ]; then
|
||||
sed -i "/ keys_zone=$domain/d" $conf
|
||||
if [ ! -s "$conf" ]; then
|
||||
@@ -58,7 +58,7 @@ if [ -f "$conf" ]; then
|
||||
fi
|
||||
|
||||
# Delete FastCGI cache folder
|
||||
if [ -d "/var/cache/nginx/micro/$domain" ]; then
|
||||
if [ -d "/usr/local/hestia/nginx-system/var/cache/nginx/micro/$domain" ]; then
|
||||
rm -rf /var/cache/nginx/micro/$domain
|
||||
fi
|
||||
|
||||
|
||||
@@ -30,32 +30,54 @@ check_hestia_demo_mode
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Deleting group and user quota on /home partition
|
||||
file_system=$(df -T /home | tail -n1 | awk '{print $2}')
|
||||
mnt=$(df -P /home | awk '{print $6}' | tail -n1)
|
||||
lnr=$(cat -n /etc/fstab | awk '{print $1,$3}' | grep "$mnt$" | cut -f 1 -d ' ')
|
||||
opt=$(sed -n ${lnr}p /etc/fstab | awk '{print $4}')
|
||||
fnd='usrquota\|grpquota\|usrjquota=\|grpjquota=\|jqfmt='
|
||||
if [ -n "$(echo $opt | grep $fnd)" ]; then
|
||||
rep=$(echo $(echo $opt | tr ',' '\n' | grep -v $fnd) | tr ' ' ',')
|
||||
sed -i "$lnr s/$opt/$rep/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
fi
|
||||
|
||||
# Disabling group and user quota
|
||||
quotaoff=$(which --skip-alias --skip-functions quotaoff 2> /dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ -n "$(quotaon -pa | grep " $mnt " | grep 'user\|group' | grep 'is on')" ]; then
|
||||
$quotaoff $mnt
|
||||
if [ "$file_system" == "xfs" ]; then
|
||||
fnd='usrquota\|grpquota'
|
||||
if [ -n "$(echo $opt | grep $fnd)" ]; then
|
||||
rep=$(echo $(echo $opt | tr ',' '\n' | grep -v $fnd) | tr ' ' ',')
|
||||
sed -i "$lnr s/$opt/$rep/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
fi
|
||||
if [ "$mnt" == "/" ]; then
|
||||
check_args=$(grubby --info=`grubby --default-kernel` | grep -oP "rootflags=[^\"]*" | head -n1)
|
||||
if [ "$check_args" != "rootflags=uquota,pquota" ]; then
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
YELLOW='\033[1;33m'
|
||||
printf "${RED}!!!!!!!Delete uquota,pquota from grub!!!!!!!${NC}\n"
|
||||
echo "${YELLOW}Delete manualy 'uquota,pquota' and reboot the system${NC}\n"
|
||||
else
|
||||
grubby --remove-args="rootflags=uquota,pquota" --update-kernel=ALL
|
||||
fi
|
||||
fi
|
||||
else
|
||||
fnd='usrquota\|grpquota\|usrjquota=\|grpjquota=\|jqfmt='
|
||||
if [ -n "$(echo $opt | grep $fnd)" ]; then
|
||||
rep=$(echo $(echo $opt | tr ',' '\n' | grep -v $fnd) | tr ' ' ',')
|
||||
sed -i "$lnr s/$opt/$rep/" /etc/fstab
|
||||
mount -o remount "$mnt"
|
||||
fi
|
||||
|
||||
# Disabling group and user quota
|
||||
quotaoff=$(which --skip-alias --skip-functions quotaoff 2> /dev/null)
|
||||
if [ $? -eq 0 ]; then
|
||||
if [ -n "$(quotaon -pa | grep " $mnt " | grep 'user\|group' | grep 'is on')" ]; then
|
||||
$quotaoff $mnt
|
||||
fi
|
||||
fi
|
||||
|
||||
# Deleting v1 + v2 group and user quota index
|
||||
for idx in $(echo 'quota.user quota.group aquota.user aquota.group'); do
|
||||
[ -e "$mnt/$idx" ] && rm -f "$mnt/$idx"
|
||||
done
|
||||
|
||||
# Deleting cron job
|
||||
rm -f /etc/cron.daily/quotacheck
|
||||
fi
|
||||
|
||||
# Deleting v1 + v2 group and user quota index
|
||||
for idx in $(echo 'quota.user quota.group aquota.user aquota.group'); do
|
||||
[ -e "$mnt/$idx" ] && rm -f "$mnt/$idx"
|
||||
done
|
||||
|
||||
# Deleting cron job
|
||||
rm -f /etc/cron.daily/quotacheck
|
||||
|
||||
# Updating hestia.conf value
|
||||
if [ -z "$(grep DISK_QUOTA $HESTIA/conf/hestia.conf)" ]; then
|
||||
echo "DISK_QUOTA='no'" >> $HESTIA/conf/hestia.conf
|
||||
|
||||
@@ -146,6 +146,18 @@ if [[ $BACKEND =~ ^.*PHP-([0-9])\_([0-9])$ ]]; then
|
||||
else
|
||||
version=$(multiphp_default_version)
|
||||
fi
|
||||
|
||||
# Delete ruby if exists
|
||||
if [ -e /usr/local/hestia/bin/v-ext-modules ]; then
|
||||
res=$(/usr/local/hestia/bin/v-ext-modules state passenger_manager csv | tail -n 1 | /usr/bin/xargs | cut -d"," -f6 )
|
||||
if [ -n "$res" ]; then
|
||||
enabled=$(echo "$res" | grep enabled)
|
||||
if [ -n "$enabled" ]; then
|
||||
/usr/local/hestia/bin/v-ext-modules-run passenger_manager disable_user "$domain"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Restarting web server
|
||||
$BIN/v-restart-web "$restart"
|
||||
check_result $? "Web restart failed" > /dev/null
|
||||
@@ -158,6 +170,12 @@ check_result $? "Proxy restart failed" > /dev/null
|
||||
$BIN/v-restart-web-backend "$restart" "$version"
|
||||
check_result $? "PHP restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ]; then
|
||||
$BIN/v-ext-modules-run bunkerweb_module delete "$domain"
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "Deleted web domain (Name: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -92,6 +92,13 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ]; then
|
||||
get_domain_values 'web'
|
||||
$BIN/v-ext-modules-run bunkerweb_module alias "$domain" "$ALIAS"
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "Deleted web domain alias (Alias: $dom_alias, Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -52,11 +52,13 @@ get_domain_values 'web'
|
||||
BACKEND="$template"
|
||||
|
||||
# Defining pool directory
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
pool=$(find -L /etc/opt/remi/ -name "$domain.conf" -exec dirname {} \;)
|
||||
pool=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
pool=$(find -L /opt/brepo/ -name "$domain.conf" -exec dirname {} \;)
|
||||
else
|
||||
pool=$(find -L /etc/php/ -name "$domain.conf" -exec dirname {} \;)
|
||||
pool=$(find -L /etc/opt/remi/ -name "$domain.conf" -exec dirname {} \;)
|
||||
fi
|
||||
|
||||
if [ ! -e "$pool" ]; then
|
||||
check_result "$E_NOTEXIST" "php-fpm pool doesn't exist"
|
||||
fi
|
||||
|
||||
@@ -90,6 +90,16 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ] && [ "$BUNKERWEB" = "yes" ]; then
|
||||
BUNKW_DIR=$HOMEDIR/$user/conf/web/$domain/ssl/bunkerweb
|
||||
if [ -d "$BUNKW_DIR" ]; then
|
||||
$BIN/v-ext-modules-run bunkerweb_module deletessl "$domain"
|
||||
rm -f $BUNKW_DIR/$domain.*
|
||||
fi
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Warning" "Web" "SSL disabled (Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
@@ -32,27 +32,21 @@ if [ -z "$WEB_BACKEND" ]; then
|
||||
fi
|
||||
|
||||
# Set file locations
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
php_fpm=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
php_fpm="/usr/lib/systemd/system/brepo-php-fpm$version.service"
|
||||
else
|
||||
php_fpm="/etc/init.d/php$version-fpm"
|
||||
php_fpm="/usr/lib/systemd/system/php$version-php-fpm.service"
|
||||
fi
|
||||
|
||||
# Verify php version format
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
else
|
||||
if [[ ! $version =~ ^[0-9].[0-9]+ ]]; then
|
||||
echo "The PHP version format is invalid, it should look like [0-9].[0-9]."
|
||||
echo "Example: 7.0, 7.4, 8.0"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
if [[ ! $version =~ ^[0-9][0-9]+ ]]; then
|
||||
echo "The PHP version format is invalid, it should look like [0-9][0-9]."
|
||||
echo "Example: 70, 74, 80"
|
||||
exit "$E_INVALID"
|
||||
fi
|
||||
|
||||
|
||||
# Remove backend template
|
||||
[ -f $HESTIA/data/templates/web/php-fpm/PHP-${version/\./_}.tpl ] && rm -f $HESTIA/data/templates/web/php-fpm/PHP-${version/\./_}.tpl
|
||||
|
||||
@@ -70,38 +64,33 @@ check_hestia_demo_mode
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
mph="php$version-common php$version-mbstring php$version-bcmath php$version-cli php$version-curl
|
||||
php$version-fpm php$version-gd php$version-intl php$version-mysql
|
||||
php$version-soap php$version-xml php$version-zip php$version-mbstring
|
||||
php$version-json php$version-bz2 php$version-pspell php$version-imagick php$version-pgsql
|
||||
php$version-imap php$version-ldap"
|
||||
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
# Packages in Remi repo have names with php$version-php- prefixes
|
||||
mph="php$version-php-fpm php$version-php-cgi php$version-php-mysqlnd php$version-php-pgsql
|
||||
php$version-php-pdo php$version-php-common php$version-php-pecl-imagick php$version-php-imap
|
||||
php$version-php-ldap php$version-php-pecl-apcu php$version-php-pecl-zip php$version-php-cli
|
||||
php$version-php-opcache php$version-php-xml php$version-php-gd php$version-php-intl
|
||||
php$version-php-mbstring php$version-php-pspell php$version-php-readline"
|
||||
fi
|
||||
|
||||
# Check is version is 7.1 or below to add mcrypt
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [[ $(echo "$version 72" | awk '{print ($1 < $2)}') == 1 ]]; then
|
||||
mph="$mph php$version-php-mcrypt"
|
||||
fi
|
||||
mph=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
mph="brepo-php$version brepo-php$version-fpm"
|
||||
else
|
||||
if [[ $(echo "$version 7.2" | awk '{print ($1 < $2)}') == 1 ]]; then
|
||||
mph="$mph php$version-mcrypt"
|
||||
fi
|
||||
mph="php$version-common php$version-mbstring php$version-bcmath php$version-cli php$version-curl
|
||||
php$version-fpm php$version-gd php$version-intl php$version-mysql
|
||||
php$version-soap php$version-xml php$version-zip php$version-mbstring
|
||||
php$version-json php$version-bz2 php$version-pspell php$version-imagick php$version-pgsql
|
||||
php$version-imap php$version-ldap"
|
||||
|
||||
# Packages in Remi repo have names with php$version-php- prefixes
|
||||
mph="php$version-php-fpm php$version-php-cgi php$version-php-mysqlnd php$version-php-pgsql
|
||||
php$version-php-pdo php$version-php-common php$version-php-pecl-imagick php$version-php-imap
|
||||
php$version-php-ldap php$version-php-pecl-apcu php$version-php-pecl-zip php$version-php-cli
|
||||
php$version-php-opcache php$version-php-xml php$version-php-gd php$version-php-intl
|
||||
php$version-php-mbstring php$version-php-pspell php$version-php-readline"
|
||||
|
||||
|
||||
# Check is version is 7.1 or below to add mcrypt
|
||||
if [[ $(echo "$version 72" | awk '{print ($1 < $2)}') == 1 ]]; then
|
||||
mph="$mph php$version-php-mcrypt"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Purge php packages
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
dnf remove -y $mph > /dev/null 2>&1 &
|
||||
else
|
||||
apt-get -y purge $mph > /dev/null 2>&1 &
|
||||
fi
|
||||
dnf remove -y $mph > /dev/null 2>&1 &
|
||||
|
||||
BACK_PID=$!
|
||||
|
||||
# Check if package removal is done, print a spinner
|
||||
@@ -119,40 +108,36 @@ echo
|
||||
# Check if installation was successfully
|
||||
if [ -f "$php_fpm" ]; then
|
||||
echo "ERROR: Uninstallation failed, please run the following command manually for debugging:"
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
echo "dnf remove $mph"
|
||||
else
|
||||
echo "apt-get purge $mph"
|
||||
fi
|
||||
echo "dnf remove $mph"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup php folder
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
[[ -d /etc/opt/remi/php$version ]] && rm -rf "/etc/opt/remi/php$version"
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
[[ -d /opt/brepo/php$version ]] && rm -rf "/opt/brepo/php$version"
|
||||
else
|
||||
[[ -d /etc/php/$version ]] && rm -rf "/etc/php/$version"
|
||||
[[ -d /etc/opt/remi/php$version ]] && rm -rf "/etc/opt/remi/php$version"
|
||||
fi
|
||||
|
||||
if [ -f '/etc/redhat-release' ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
if [ "$WEB_BACKEND" = "php-fpm" ]; then
|
||||
conf=$(find /opt/brepo/php* -name www.conf)
|
||||
# Check if www.conf exists
|
||||
if [ -z "$conf" ]; then
|
||||
# If not grab the "last php version
|
||||
last=$($BIN/v-list-sys-php "shell" | tail -n1)
|
||||
cp -f $HESTIA/install/rpm/php-fpm/www.conf /opt/brepo/php$last/etc/php-fpm.d/www.conf
|
||||
$BIN/v-restart-web-backend
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$WEB_BACKEND" = "php-fpm" ]; then
|
||||
conf=$(find /etc/opt/remi/php* -name www.conf)
|
||||
# Check if www.conf exists
|
||||
if [ -z "$conf" ]; then
|
||||
# If not grab the "last php version
|
||||
last=$($BIN/v-list-sys-php "shell" | tail -n1)
|
||||
cp -f $HESTIA/install/rpm/php-fpm/www.conf /etc/opt/remi/php$version/php-fpm.d/www.conf
|
||||
$BIN/v-restart-web-backend
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ "$WEB_BACKEND" = "php-fpm" ]; then
|
||||
conf=$(find /etc/php* -name www.conf)
|
||||
# Check if www.conf exists
|
||||
if [ -z "$conf" ]; then
|
||||
# If not grab the "last php version
|
||||
last=$($BIN/v-list-sys-php "shell" | tail -n1)
|
||||
cp -f $HESTIA/install/deb/php-fpm/www.conf /etc/php/$last/fpm/pool.d/www.conf
|
||||
cp -f $HESTIA/install/rpm/php-fpm/www.conf /etc/opt/remi/php$last/php-fpm.d/www.conf
|
||||
$BIN/v-restart-web-backend
|
||||
fi
|
||||
fi
|
||||
|
||||
152
bin/v-ext-modules
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: action with extended modules
|
||||
# options: COMMAND [COMMAND_OPTION | FORMAT] [FORMAT]
|
||||
#
|
||||
# example: v-ext-modules list json
|
||||
#
|
||||
# This function enables and disables additional modules
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
v_command = ARGV[0]
|
||||
v_ext_option = ARGV[1]
|
||||
v_format = ARGV[2]
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
check_args 1, ARGV, "COMMAND [COMMAND_OPTION] [ACTION]"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
case v_command.to_sym
|
||||
when :list, :state
|
||||
info = []
|
||||
pm = PluginManager.new
|
||||
if v_command.to_sym == :state
|
||||
if v_ext_option.nil?
|
||||
hestia_print_error_message_to_cli "no module name specified"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip
|
||||
pm.load_plugins(nil, load_module)
|
||||
else
|
||||
pm.load_plugins
|
||||
end
|
||||
pm.get_loaded_plugins.each_key do |mod|
|
||||
next if mod == "default"
|
||||
|
||||
inst = pm.get_instance(mod)
|
||||
if inst.key != pm.get_key
|
||||
hestia_print_error_message_to_cli "incorrect module with incorrect rights #{mod}"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
info_result = inst.info
|
||||
info_result[:STATE] = hestia_ext_module_state_in_conf(info_result[:NAME], :get)
|
||||
info << info_result
|
||||
end
|
||||
result_arr = info.sort do |a, b|
|
||||
if a[:ID] < b[:ID]
|
||||
-1
|
||||
elsif a[:ID] > b[:ID]
|
||||
1
|
||||
else
|
||||
a[:ID] < b[:ID]
|
||||
end
|
||||
end
|
||||
if v_command.to_sym == :state
|
||||
format = (v_format.nil? ? "shell" : v_format.strip)
|
||||
else
|
||||
format = (v_ext_option.nil? ? "shell" : v_ext_option.strip)
|
||||
end
|
||||
hestia_print_array_of_hashes(result_arr, format, "ID, NAME, DESCR, STATE, REQ, CONF")
|
||||
when :enable
|
||||
if v_ext_option.nil?
|
||||
hestia_print_error_message_to_cli "no module name specified"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
pm = PluginManager.new
|
||||
load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip
|
||||
pm.load_plugins(nil, load_module)
|
||||
if pm.get_loaded_plugins.key? load_module
|
||||
if hestia_ext_module_state_in_conf(load_module, :get) == "disabled"
|
||||
inst = pm.get_instance(load_module)
|
||||
result = inst.enable()
|
||||
if result == ""
|
||||
hestia_ext_module_state_in_conf(load_module, :enable)
|
||||
log_event OK, $ARGUMENTS
|
||||
else
|
||||
hestia_print_error_message_to_cli "module #{load_module} return error #{result}"
|
||||
log_event E_MODULE, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "no module with name #{load_module} found"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
when :disable
|
||||
if v_ext_option.nil?
|
||||
hestia_print_error_message_to_cli "no module name specified"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
pm = PluginManager.new
|
||||
load_module = v_ext_option.to_s.strip.split(",")[0].to_s.strip
|
||||
pm.load_plugins(nil, load_module)
|
||||
if pm.get_loaded_plugins.key? load_module
|
||||
if hestia_ext_module_state_in_conf(load_module, :get) == "enabled"
|
||||
inst = pm.get_instance(load_module)
|
||||
result = inst.disable()
|
||||
if result == ""
|
||||
hestia_ext_module_state_in_conf(load_module, :disable)
|
||||
log_event OK, $ARGUMENTS
|
||||
else
|
||||
hestia_print_error_message_to_cli "module #{load_module} return error #{result}"
|
||||
log_event E_MODULE, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "no module with name #{load_module} found"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "unknown command"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
82
bin/v-ext-modules-run
Executable file
@@ -0,0 +1,82 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: action with extended modules
|
||||
# options: MODULE_ID [MODULE_RELATED_COMMNDS]
|
||||
#
|
||||
# example: v-ext-modules passenger_manager list json
|
||||
#
|
||||
# This function enables and disables additional modules
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
v_id = ARGV[0]
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
check_args 1, ARGV, "MODULE_ID [MODULE_RELATED_COMMNDS]"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
if v_id.nil?
|
||||
hestia_print_error_message_to_cli "no module name specified"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
pm = PluginManager.new
|
||||
load_module = v_id.strip
|
||||
pm.load_plugins(nil, load_module)
|
||||
if pm.get_loaded_plugins.key? load_module
|
||||
if hestia_ext_module_state_in_conf(load_module, :get) == "enabled"
|
||||
inst = pm.get_instance(load_module)
|
||||
NEW_ARGV = if ARGV.length > 0
|
||||
ARGV.drop(1)
|
||||
else
|
||||
ARGV
|
||||
end
|
||||
result = inst.command(NEW_ARGV)
|
||||
if result == ""
|
||||
log_event OK, $ARGUMENTS
|
||||
else
|
||||
hestia_print_error_message_to_cli "module #{load_module} return error #{result}"
|
||||
log_event E_MODULE, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "module #{load_module} disabled"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "no module with name #{load_module} found"
|
||||
log_event E_INVALID, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
@@ -36,7 +36,8 @@ json_list() {
|
||||
"METHOD": "'$method'",
|
||||
"SALT": "'$salt'",
|
||||
"TIME": "'$time'",
|
||||
"DATE": "'$date'"
|
||||
"DATE": "'$date'",
|
||||
"ROUND":"'$round'"
|
||||
}'
|
||||
echo '}'
|
||||
}
|
||||
@@ -45,17 +46,18 @@ json_list() {
|
||||
shell_list() {
|
||||
echo "METHOD: $method"
|
||||
echo "SALT: $salt"
|
||||
echo "ROUND: $round"
|
||||
}
|
||||
|
||||
# PLAIN list function
|
||||
plain_list() {
|
||||
echo -e "$method\t$salt"
|
||||
echo -e "$method\t$salt\t$round"
|
||||
}
|
||||
|
||||
# CSV list function
|
||||
csv_list() {
|
||||
echo "METHOD,SALT"
|
||||
echo "$method, $salt"
|
||||
echo "METHOD,SALT,ROUND"
|
||||
echo "$method, $salt, $round"
|
||||
}
|
||||
|
||||
#----------------------------------------------------------#
|
||||
@@ -81,6 +83,11 @@ shadow=$(grep "^$user:" /etc/shadow | cut -f 2 -d :)
|
||||
|
||||
if echo "$shadow" | grep -qE '^\$[0-9a-z]+\$[^\$]+\$'; then
|
||||
salt=$(echo "$shadow" | cut -f 3 -d \$)
|
||||
round=""
|
||||
if [[ "$salt" =~ ^rounds= ]]; then
|
||||
round=$salt
|
||||
salt=$(echo "$shadow" | cut -f 4 -d \$)
|
||||
fi
|
||||
method=$(echo "$shadow" | cut -f 2 -d \$)
|
||||
if [ "$method" = "y" ]; then
|
||||
method='yescrypt'
|
||||
|
||||
@@ -67,14 +67,14 @@ csv_list() {
|
||||
|
||||
declare -a versions
|
||||
# List through /etc/php
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
for version in /etc/opt/remi/php*/php-fpm.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
for version in /opt/brepo/php*/etc/php-fpm.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
versions+=("$ver")
|
||||
done
|
||||
else
|
||||
for version in /etc/php/*/fpm/pool.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }')
|
||||
for version in /etc/opt/remi/php*/php-fpm.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
versions+=("$ver")
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -69,8 +69,8 @@ HOSTNAME=$(hostname)
|
||||
# Check OS/Release
|
||||
if [ -d '/etc/sysconfig' ]; then
|
||||
if [ -e '/etc/redhat-release' ]; then
|
||||
OS='CentOS'
|
||||
VERSION=$(cat /etc/redhat-release | tr ' ' '\n' | grep [0-9])
|
||||
OS=$(cat /etc/redhat-release | cut -d' ' -f1)
|
||||
VERSION=$(cat /etc/redhat-release | tr ' ' '\n' | grep -P "\d+(\.\d+)?")
|
||||
else
|
||||
OS="Amazon"
|
||||
VERSION=$(cat /etc/issue | tr ' ' '\n' | grep [0-9])
|
||||
|
||||
@@ -65,7 +65,7 @@ csv_list() {
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Defining config path
|
||||
config_path='/etc/nginx/nginx.conf'
|
||||
config_path='/usr/local/hestia/nginx-system/etc/nginx/nginx.conf'
|
||||
|
||||
# Defining keys
|
||||
keys="worker_processes |worker_connections |send_timeout"
|
||||
|
||||
@@ -67,21 +67,29 @@ csv_list() {
|
||||
|
||||
declare -a versions
|
||||
# List through /etc/php
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
for version in /etc/opt/remi/php*/; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed 's|php||')
|
||||
versions+=("$ver")
|
||||
done
|
||||
else
|
||||
if [ -n "$WEB_BACKEND" ]; then
|
||||
for version in /etc/php/*/fpm; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }')
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
if [ -n "$WEB_BACKEND" ]; then
|
||||
for version in /opt/brepo/php*/; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed 's|php||')
|
||||
versions+=("$ver")
|
||||
done
|
||||
else
|
||||
# Fix for modphp
|
||||
for version in /etc/php/*/cli; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }')
|
||||
for version in /opt/brepo/php*/bin/php; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed 's|php||')
|
||||
versions+=("$ver")
|
||||
done
|
||||
fi
|
||||
else
|
||||
if [ -n "$WEB_BACKEND" ]; then
|
||||
for version in /etc/opt/remi/php*/; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed 's|php||')
|
||||
versions+=("$ver")
|
||||
done
|
||||
else
|
||||
# Fix for modphp
|
||||
for version in /opt/remi/php*/root/bin/php; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed 's|php||')
|
||||
versions+=("$ver")
|
||||
done
|
||||
fi
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# info: list php config parameters
|
||||
# options: [FORMAT]
|
||||
# options: [VERSION] [FORMAT]
|
||||
#
|
||||
# example: v-list-sys-php-config
|
||||
#
|
||||
@@ -11,7 +11,8 @@
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
format=${1-shell}
|
||||
php_ver=${1-default}
|
||||
format=${2-shell}
|
||||
|
||||
# Includes
|
||||
# shellcheck source=/etc/hestiacp/hestia.conf
|
||||
@@ -61,24 +62,53 @@ csv_list() {
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
declare -a versions
|
||||
if [ "$php_ver" == "default" ]; then
|
||||
# List through /etc/php
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
for version in /opt/brepo/php*/etc/php-fpm.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
if [ "$ver" != "php*" ]; then
|
||||
versions+=("$ver")
|
||||
fi
|
||||
done
|
||||
else
|
||||
for version in /etc/opt/remi/php*/php-fpm.d/www.conf; do
|
||||
ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
if [ "$ver" != "php*" ]; then
|
||||
versions+=("$ver")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
ver=$(echo "$php_ver" | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
versions+=("$ver")
|
||||
fi
|
||||
|
||||
if [ ${#versions[@]} -eq 0 ]; then
|
||||
php_ver="82"
|
||||
else
|
||||
php_ver="${versions[0]}"
|
||||
fi
|
||||
|
||||
# Defining config path
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
config_path=$(find /etc/opt/remi/php* -name php.ini)
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
config_path=$(find /opt/brepo/php${php_ver}/* -name php.ini)
|
||||
else
|
||||
config_path=$(find /etc/php* -name php.ini)
|
||||
config_path=$(find /etc/opt/remi/php${php_ver}/* -name php.ini)
|
||||
fi
|
||||
|
||||
config_count=$(echo "$config_path" | wc -l)
|
||||
if [ "$config_count" -gt 1 ]; then
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
multiphp_versions=$(ls -d /etc/opt/remi/php*/php-fpm.d 2> /dev/null | wc -l)
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
multiphp_versions=$(ls -d /opt/brepo/php*/etc/php-fpm.d 2> /dev/null | wc -l)
|
||||
else
|
||||
multiphp_versions=$(ls -d /etc/php/*/fpm/pool.d 2> /dev/null | wc -l)
|
||||
multiphp_versions=$(ls -d /etc/opt/remi/php*/php-fpm.d 2> /dev/null | wc -l)
|
||||
fi
|
||||
if [ "$WEB_BACKEND" = 'php-fpm' ] || [ "$multiphp_versions" -gt 0 ]; then
|
||||
config_path=$(echo "$config_path" | grep fpm)
|
||||
config_path=$(echo "$config_path" | grep "php")
|
||||
else
|
||||
config_path=$(echo "$config_path" | grep apache)
|
||||
config_path=$(echo "$config_path" | grep httpd)
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -88,7 +118,7 @@ keys="$keys |upload_max_filesize |post_max_size"
|
||||
keys="$keys |display_errors |error_reporting "
|
||||
|
||||
# Reading config
|
||||
config=$(cat $config_path | grep -v "^;")
|
||||
config=$(cat "$config_path" | grep -v "^;")
|
||||
|
||||
# Listing data
|
||||
case $format in
|
||||
|
||||
@@ -34,7 +34,8 @@ json_list() {
|
||||
"STATE": "'$STATE'",
|
||||
"CPU": "'$CPU'",
|
||||
"MEM": "'$MEM'",
|
||||
"RTIME": "'$RTIME'"
|
||||
"RTIME": "'$RTIME'",
|
||||
"PMEM": "'$PHM'"
|
||||
}'
|
||||
if [ "$i" -lt "$objects" ]; then
|
||||
echo ','
|
||||
@@ -49,11 +50,11 @@ json_list() {
|
||||
# SHELL list function
|
||||
shell_list() {
|
||||
IFS=$'\n'
|
||||
echo "NAME STATE CPU MEM UPTIME"
|
||||
echo "---- ----- --- --- ------"
|
||||
echo "NAME STATE CPU MEM UPTIME PMEM"
|
||||
echo "---- ----- --- --- ------ ----"
|
||||
while read str; do
|
||||
parse_object_kv_list "$str"
|
||||
echo "$NAME $STATE $CPU $MEM $RTIME"
|
||||
echo "$NAME $STATE $CPU $MEM $RTIME $PHM"
|
||||
done < <(echo -e "$data" | grep NAME)
|
||||
}
|
||||
|
||||
@@ -62,17 +63,17 @@ plain_list() {
|
||||
IFS=$'\n'
|
||||
while read str; do
|
||||
parse_object_kv_list "$str"
|
||||
echo -e "$NAME\t$SYSTEM\t$STATE\t$CPU\t$MEM\t$RTIME"
|
||||
echo -e "$NAME\t$SYSTEM\t$STATE\t$CPU\t$MEM\t$RTIME\t$PHM"
|
||||
done < <(echo -e "$data" | grep NAME)
|
||||
}
|
||||
|
||||
# CSV list function
|
||||
csv_list() {
|
||||
IFS=$'\n'
|
||||
echo "NAME,SYSTEM,STATE,CPU,MEM,RTIME"
|
||||
echo "NAME,SYSTEM,STATE,CPU,MEM,RTIME,PMEM"
|
||||
while read str; do
|
||||
parse_object_kv_list "$str"
|
||||
echo "$NAME,\"$SYSTEM\",$STATE,$CPU,$MEM,$RTIME"
|
||||
echo "$NAME,\"$SYSTEM\",$STATE,$CPU,$MEM,$RTIME,$PHM"
|
||||
done < <(echo -e "$data" | grep NAME)
|
||||
}
|
||||
|
||||
@@ -84,14 +85,19 @@ get_srv_state() {
|
||||
mem=0
|
||||
cpu=0
|
||||
rtime="0"
|
||||
pmem=0
|
||||
|
||||
# Searching related pids
|
||||
if [ -f /etc/redhat-release ] && [ "$name" = "php-fpm" ]; then
|
||||
if [ "$name" = "php-fpm" ]; then
|
||||
pids=''
|
||||
for php_pid in $(pidof php-fpm); do
|
||||
process_info=$(ps -p "$php_pid" -o args | tail -n1 | grep "$srv")
|
||||
if [ -n "$process_info" ]; then
|
||||
pids="${pids}|${php_pid}"
|
||||
if [ -z "$pids" ];then
|
||||
pids="${php_pid}"
|
||||
else
|
||||
pids="${pids}|${php_pid}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
else
|
||||
@@ -123,6 +129,9 @@ get_srv_state() {
|
||||
mem=$(echo "$pids" | awk '{sum += $3} END {print sum/1024 }')
|
||||
mem=$(echo "${mem%%.*}")
|
||||
|
||||
pmem=$(echo "$pids" | awk '{sum += $4} END {print sum/1024 }')
|
||||
pmem=$(echo "${pmem%%.*}")
|
||||
|
||||
# Searching pid file
|
||||
pid_file=''
|
||||
if [ -e "/run/$srv.pid" ]; then
|
||||
@@ -151,6 +160,7 @@ get_srv_state() {
|
||||
mem=0
|
||||
cpu=0
|
||||
rtime="0"
|
||||
pmem=0
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -160,7 +170,7 @@ get_srv_state() {
|
||||
|
||||
# Saving current proccess list
|
||||
tmp_file=$(mktemp)
|
||||
ps -eo pid,pcpu,size > $tmp_file
|
||||
ps -eo pid,pcpu,size,rss > $tmp_file
|
||||
|
||||
# Checking current time
|
||||
ctime=$(date +%s)
|
||||
@@ -169,28 +179,28 @@ ctime=$(date +%s)
|
||||
if [ -n "$WEB_SYSTEM" ] && [ "$WEB_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state $WEB_SYSTEM
|
||||
data="NAME='$WEB_SYSTEM' SYSTEM='web server' STATE='$state' CPU='$cpu'"
|
||||
data="$data MEM='$mem' RTIME='$rtime'"
|
||||
data="$data MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking PHP intepreter
|
||||
if [ -n "$WEB_BACKEND" ] && [ "$WEB_BACKEND" != 'remote' ]; then
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
php_versions=$(ls /opt/brepo/php*/sbin/php-fpm | cut -d'/' -f4 | sed 's|php||')
|
||||
for version in $php_versions; do
|
||||
proc_name="php-fpm"
|
||||
service_name="fpm${version}"
|
||||
get_srv_state "/opt/brepo/php${version}" "$proc_name"
|
||||
data="$data\nNAME='brepo-php-$service_name' SYSTEM='php interpreter' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
done
|
||||
else
|
||||
php_versions=$(ls /opt/remi/php*/root/sbin/php-fpm | cut -d'/' -f4 | sed 's|php||')
|
||||
for version in $php_versions; do
|
||||
proc_name="php-fpm"
|
||||
service_name="php${version}"
|
||||
get_srv_state "$proc_name"
|
||||
get_srv_state "/opt/remi/php${version}" "$proc_name"
|
||||
data="$data\nNAME='$service_name-php-fpm' SYSTEM='php interpreter' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
done
|
||||
else
|
||||
php_versions=$(ls /usr/sbin/php*fpm* | cut -d'/' -f4 | sed 's|php-fpm||')
|
||||
for version in $php_versions; do
|
||||
proc_name="php-fpm${version}"
|
||||
service_name="php${version}-fpm"
|
||||
get_srv_state "$service_name" "$proc_name"
|
||||
data="$data\nNAME='$service_name' SYSTEM='php interpreter' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
@@ -199,7 +209,7 @@ fi
|
||||
if [ -n "$PROXY_SYSTEM" ] && [ "$PROXY_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$PROXY_SYSTEM"
|
||||
data="$data\nNAME='$PROXY_SYSTEM' SYSTEM='reverse proxy' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# DNS
|
||||
@@ -208,21 +218,21 @@ if [ -n "$service" ] && [ "$service" != 'remote' ]; then
|
||||
proc_name='named'
|
||||
get_srv_state $service $proc_name
|
||||
data="$data\nNAME='$service' SYSTEM='dns server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking MAIL system
|
||||
if [ -n "$MAIL_SYSTEM" ] && [ "$MAIL_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$MAIL_SYSTEM"
|
||||
data="$data\nNAME='$MAIL_SYSTEM' SYSTEM='mail server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking MAIL IMAP
|
||||
if [ -n "$IMAP_SYSTEM" ] && [ "$IMAP_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$IMAP_SYSTEM"
|
||||
data="$data\nNAME='$IMAP_SYSTEM' SYSTEM='imap/pop3 server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking MAIL ANTIVIRUS
|
||||
@@ -244,7 +254,7 @@ if [ -n "$ANTIVIRUS_SYSTEM" ] && [ "$ANTIVIRUS_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$ANTIVIRUS_SYSTEM" "$proc_name"
|
||||
fi
|
||||
data="$data\nNAME='$ANTIVIRUS_SYSTEM' SYSTEM='email anti-virus'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
proc_name=''
|
||||
fi
|
||||
|
||||
@@ -252,7 +262,7 @@ fi
|
||||
if [ -n "$ANTISPAM_SYSTEM" ] && [ "$ANTISPAM_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$ANTISPAM_SYSTEM" "spamd"
|
||||
data="$data\nNAME='$ANTISPAM_SYSTEM' SYSTEM='email spam filter'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking DB system
|
||||
@@ -299,7 +309,7 @@ if [ -n "$DB_SYSTEM" ] && [ "$DB_SYSTEM" != 'remote' ]; then
|
||||
fi
|
||||
get_srv_state "$service" "$proc_name"
|
||||
data="$data\nNAME='$service' SYSTEM='database server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
proc_name=''
|
||||
done
|
||||
fi
|
||||
@@ -308,21 +318,21 @@ fi
|
||||
if [ -n "$FTP_SYSTEM" ] && [ "$FTP_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$FTP_SYSTEM"
|
||||
data="$data\nNAME='$FTP_SYSTEM' SYSTEM='ftp server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking CRON system
|
||||
if [ -n "$CRON_SYSTEM" ] && [ "$CRON_SYSTEM" != 'remote' ]; then
|
||||
get_srv_state "$CRON_SYSTEM"
|
||||
data="$data\nNAME='$CRON_SYSTEM' SYSTEM='job scheduler' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking SSH daemon
|
||||
if [ -e "/etc/ssh/sshd_config" ]; then
|
||||
get_srv_state ssh
|
||||
data="$data\nNAME='ssh' SYSTEM='ssh server' STATE='$state'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Checking FIREWALL system
|
||||
@@ -339,7 +349,7 @@ if [ -n "$FIREWALL_SYSTEM" ] && [ "$FIREWALL_SYSTEM" != 'remote' ]; then
|
||||
fi
|
||||
fi
|
||||
data="$data\nNAME='$FIREWALL_SYSTEM' SYSTEM='firewall'"
|
||||
data="$data STATE='$state' CPU='0' MEM='0' RTIME='0'"
|
||||
data="$data STATE='$state' CPU='0' MEM='0' RTIME='0' PHM='0'"
|
||||
fi
|
||||
|
||||
# Checking FIREWALL Fail2ban extention
|
||||
@@ -354,7 +364,7 @@ if [ -n "$FIREWALL_EXTENSION" ]; then
|
||||
get_srv_state "$FIREWALL_EXTENSION" fail2ban-server script
|
||||
fi
|
||||
data="$data\nNAME='$FIREWALL_EXTENSION' SYSTEM='brute-force protection'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime'"
|
||||
data="$data STATE='$state' CPU='$cpu' MEM='$mem' RTIME='$rtime' PHM='$pmem'"
|
||||
fi
|
||||
|
||||
# Listing data
|
||||
|
||||
@@ -48,13 +48,13 @@ conf=$(grep "DOMAIN='$domain'" "$USER_DATA/web.conf")
|
||||
parse_object_kv_list "$conf"
|
||||
|
||||
# Purge nginx FastCGI cache
|
||||
if [ -d "/var/cache/nginx/micro/$domain" ]; then
|
||||
rm -rf /var/cache/nginx/micro/$domain/*
|
||||
if [ -d "/usr/local/hestia/nginx-system/var/cache/nginx/micro/$domain" ]; then
|
||||
rm -rf /usr/local/hestia/nginx-system/var/cache/nginx/micro/$domain/*
|
||||
fi
|
||||
|
||||
# Purge nginx proxy cache
|
||||
if [ -d "/var/cache/nginx/$domain" ]; then
|
||||
rm -rf /var/cache/nginx/$domain/*
|
||||
if [ -d "/usr/local/hestia/nginx-system/var/cache/nginx/$domain" ]; then
|
||||
rm -rf /usr/local/hestia/nginx-system/var/cache/nginx/$domain/*
|
||||
fi
|
||||
|
||||
#----------------------------------------------------------#
|
||||
|
||||
@@ -25,10 +25,14 @@ send_email_report() {
|
||||
email=$(echo "$email" | cut -f 2 -d "'")
|
||||
tmpfile=$(mktemp)
|
||||
subj="$(hostname): $PROXY_SYSTEM restart failed"
|
||||
nginx -t >> $tmpfile 2>&1
|
||||
/usr/local/hestia/nginx-system/sbin/nginx -t >> $tmpfile 2>&1
|
||||
|
||||
if [ "$1" == "DO_RESTART" ]; then
|
||||
service "$PROXY_SYSTEM" restart >> $tmpfile 2>&1
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
service nginx-system restart >> $tmpfile 2>&1
|
||||
else
|
||||
service "$PROXY_SYSTEM" restart >> $tmpfile 2>&1
|
||||
fi
|
||||
fi
|
||||
cat "$tmpfile" | $SENDMAIL -s "$subj" "$email"
|
||||
if [ "$DEBUG_MODE" = "true" ]; then
|
||||
|
||||
@@ -32,6 +32,10 @@ is_format_valid 'service' 'restart'
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
if [ "$service" == "apache2" ]; then
|
||||
service="httpd"
|
||||
fi
|
||||
|
||||
log="/dev/null"
|
||||
if [ "$DEBUG_MODE" = "true" ]; then
|
||||
|
||||
@@ -49,43 +53,52 @@ if [ "$service" = "php-fpm" ]; then
|
||||
php_versions=$($BIN/v-list-sys-php plain)
|
||||
# Substitute php-fpm service name formats
|
||||
for version in $php_versions; do
|
||||
service_list="${service_list} php${version}-fpm"
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
service_list="${service_list} brepo-php-fpm${version}"
|
||||
else
|
||||
service_list="${service_list} php${version}-php-fpm"
|
||||
fi
|
||||
done
|
||||
else
|
||||
service_list="$service"
|
||||
fi
|
||||
|
||||
for service in $service_list; do
|
||||
is_fpm="no"
|
||||
if [[ "$service" =~ ^php[0-9.]+-php-fpm ]] || [[ "$service" =~ brepo-php-fpm[0-9.]+ ]]; then
|
||||
is_fpm="yes"
|
||||
fi
|
||||
if [ "$service" = "iptables" ]; then
|
||||
# Run the restart rules for iptables firewall
|
||||
$BIN/v-stop-firewall
|
||||
$BIN/v-update-firewall
|
||||
elif [ "$restart" = "ssl" ] && [ "$service" = "nginx" ]; then
|
||||
service $service upgrade >> $log 2>&1
|
||||
service nginx-system upgrade >> $log 2>&1
|
||||
elif [ -z "$restart" -o "$restart" = "no" ] && [ \
|
||||
"$service" = "nginx" -o \
|
||||
"$service" = "apache2" -o \
|
||||
"$service" = "httpd" -o \
|
||||
"$service" = "exim4" -o \
|
||||
"$service" = "dovecot" -o \
|
||||
"$service" = "bind9" -o \
|
||||
"$service" = "named" -o \
|
||||
"$service" = "vsftpd" -o \
|
||||
"$service" = "php5.6-fpm" -o \
|
||||
"$service" = "php7.0-fpm" -o \
|
||||
"$service" = "php7.1-fpm" -o \
|
||||
"$service" = "php7.2-fpm" -o \
|
||||
"$service" = "php7.3-fpm" -o \
|
||||
"$service" = "php7.4-fpm" -o \
|
||||
"$service" = "php8.0-fpm" -o \
|
||||
"$service" = "php8.1-fpm" -o \
|
||||
"$service" = "php8.2-fpm" -o \
|
||||
"$is_fpm" = "yes" -o \
|
||||
"$service" = "proftpd" -o \
|
||||
"$service" = "ssh" -o \
|
||||
"$service" = "fail2ban" ]; then
|
||||
systemctl reload-or-restart "$service" >> $log 2>&1
|
||||
if [ "$service" = "nginx" ]; then
|
||||
systemctl reload-or-restart nginx-system >> $log 2>&1
|
||||
else
|
||||
systemctl reload-or-restart "$service" >> $log 2>&1
|
||||
fi
|
||||
else
|
||||
systemctl reset-failed "$service" >> $log 2>&1
|
||||
systemctl restart "$service" >> $log 2>&1
|
||||
if [ "$service" = "nginx" ]; then
|
||||
systemctl reset-failed nginx-system >> $log 2>&1
|
||||
systemctl restart nginx-system >> $log 2>&1
|
||||
else
|
||||
systemctl reset-failed "$service" >> $log 2>&1
|
||||
systemctl restart "$service" >> $log 2>&1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check the result of the service restart and report whether it failed.
|
||||
|
||||
@@ -58,21 +58,21 @@ tmpfile=$(mktemp)
|
||||
if [ -z "$version" ]; then
|
||||
# Substitute php-fpm service name formats
|
||||
for version in $($BIN/v-list-sys-php plain); do
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
v_php="php$version-php-fpm"
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
v_php="brepo-php-fpm$version"
|
||||
else
|
||||
v_php="php$version-fpm"
|
||||
v_php="php$version-php-fpm"
|
||||
fi
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
if [ ! -f "/opt/brepo/php${version}/etc/php-fpm.d/dummy.conf" ]; then
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/dummy.conf /opt/brepo/php${version}/etc/php-fpm.d/
|
||||
sed -i "s/9999/99$v_tpl/g" /opt/brepo/php${version}/etc/php-fpm.d/dummy.conf
|
||||
fi
|
||||
else
|
||||
if [ ! -f "/etc/opt/remi/php${version}/php-fpm.d/dummy.conf" ]; then
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/dummy.conf /etc/opt/remi/php${version}/php-fpm.d/
|
||||
sed -i "s/9999/99$v_tpl/g" /etc/opt/remi/php${version}/php-fpm.d/dummy.conf
|
||||
fi
|
||||
else
|
||||
if [ ! -f "/etc/php/${version}/fpm/pool.d/dummy.conf" ]; then
|
||||
cp -f "$HESTIA_INSTALL_DIR/php-fpm/dummy.conf" "/etc/php/${version}/fpm/pool.d/"
|
||||
sed -i "s/9999/99${version//./}/g" "/etc/php/${version}/fpm/pool.d/dummy.conf"
|
||||
fi
|
||||
fi
|
||||
|
||||
$BIN/v-restart-service "$v_php" "$restart"
|
||||
@@ -82,10 +82,10 @@ if [ -z "$version" ]; then
|
||||
fi
|
||||
done
|
||||
else
|
||||
if [ -f /etc/redhat-release ]; then
|
||||
v_php="php$version-php-fpm"
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
v_php="brepo-php-fpm$version"
|
||||
else
|
||||
v_php="php$version-fpm"
|
||||
v_php="php$version-php-fpm"
|
||||
fi
|
||||
$BIN/v-restart-service "$v_php" "$restart"
|
||||
if [ $? -ne 0 ]; then
|
||||
|
||||
@@ -43,6 +43,15 @@ if [ "$clicmd" = "wp" ]; then
|
||||
clicmd="$homedir/.wp-cli/wp"
|
||||
fi
|
||||
|
||||
if [[ "$clicmd" =~ php[0-9][0-9] ]]; then
|
||||
php_ver=$(echo "$clicmd" | grep -oP "\d+")
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
clicmd="/opt/brepo/php${php_ver}/bin/php"
|
||||
else
|
||||
clicmd="/usr/bin/php${php_ver}"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$(which "$clicmd")" ]; then
|
||||
check_result "$E_NOTEXIST" "Cli command does not exist $clicmd"
|
||||
fi
|
||||
@@ -61,15 +70,6 @@ if [ "$basecmd" != 'ps' -a \
|
||||
"$basecmd" != 'egrep' -a \
|
||||
"$basecmd" != 'sed' -a \
|
||||
"$basecmd" != 'cat' -a \
|
||||
"$basecmd" != 'php5.6' -a \
|
||||
"$basecmd" != 'php7.0' -a \
|
||||
"$basecmd" != 'php7.1' -a \
|
||||
"$basecmd" != 'php7.2' -a \
|
||||
"$basecmd" != 'php7.3' -a \
|
||||
"$basecmd" != 'php7.4' -a \
|
||||
"$basecmd" != 'php8.0' -a \
|
||||
"$basecmd" != 'php8.1' -a \
|
||||
"$basecmd" != 'php8.2' -a \
|
||||
"$basecmd" != 'php' -a \
|
||||
"$basecmd" != "wp" -a \
|
||||
"$basecmd" != 'composer' ]; then
|
||||
|
||||
@@ -47,7 +47,11 @@ for service in $service_list; do
|
||||
if [ "$service" = "iptables" ]; then
|
||||
$BIN/v-stop-firewall
|
||||
else
|
||||
systemctl stop "$service"
|
||||
if [ "$service" = "nginx" ]; then
|
||||
systemctl stop nginx-system
|
||||
else
|
||||
systemctl stop "$service"
|
||||
fi
|
||||
result=$?
|
||||
if [ "$result" -ne 0 ]; then
|
||||
$BIN/v-log-action "system" "Error" "System" "Service failed to stop (Name: $service)."
|
||||
|
||||
282
bin/v-system-nginx-migrate
Executable file
@@ -0,0 +1,282 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
# info: utility to prepare existing server with hestiacp to use new alternative nginx
|
||||
# options: COMMAND
|
||||
#
|
||||
# example: v-system-nginx-migrate migrate-nginx
|
||||
#
|
||||
# Commands:
|
||||
# migratenginx - move old nginx configs to the new port and path
|
||||
#
|
||||
#
|
||||
|
||||
#------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
v_command = ARGV[0]
|
||||
|
||||
require "/usr/local/hestia/func_ruby/global_options"
|
||||
|
||||
load_ruby_options_defaults
|
||||
$HESTIA = load_hestia_default_path_from_env
|
||||
|
||||
require "main"
|
||||
require "modules"
|
||||
|
||||
require 'json' unless defined?(JSON)
|
||||
require 'fileutils'
|
||||
require 'time'
|
||||
require 'pathname'
|
||||
|
||||
|
||||
def copy_nginx_files(src_root, dest_root)
|
||||
FileUtils.mkdir_p(dest_root)
|
||||
Dir.foreach(src_root) do |entry|
|
||||
next if entry == '.' || entry == '..'
|
||||
next if entry == 'modules' || entry == 'modules-enabled'
|
||||
src_path = File.join(src_root, entry)
|
||||
dest_path = File.join(dest_root, entry)
|
||||
if File.directory?(src_path)
|
||||
FileUtils.mkdir_p(dest_path)
|
||||
copy_nginx_files(src_path, dest_path)
|
||||
else
|
||||
FileUtils.cp(src_path, dest_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Function to log and execute migration stages
|
||||
def log_migrate_stage(stage)
|
||||
log_file = '/usr/local/hestia/log/bunkerweb_migrate_stages.log'
|
||||
# Check if the stage has already been recorded
|
||||
if File.exist?(log_file) && File.readlines(log_file).any? { |line| line.strip == stage }
|
||||
hestia_print_error_message_to_cli "Stage #{stage} already completed, skipping."
|
||||
return
|
||||
end
|
||||
# Execute the stage block
|
||||
begin
|
||||
yield
|
||||
# Record the successful stage
|
||||
File.open(log_file, 'a') { |f| f.puts stage }
|
||||
hestia_print_info_message_to_cli "Stage #{stage} completed."
|
||||
rescue => e
|
||||
hestia_print_error_message_to_cli "Stage #{stage} failed: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
# Function to parse and migrate nginx.conf from /usr/local/hestia/nginx-system/etc/nginx/nginx.conf
|
||||
def migrate_nginx_config_from_file(source_path)
|
||||
return false unless File.exist?(source_path)
|
||||
|
||||
hestia_print_info_message_to_cli "Processing nginx config from: #{source_path}"
|
||||
|
||||
content = File.read(source_path)
|
||||
original_content = content.dup
|
||||
|
||||
modified = false
|
||||
|
||||
# Replace all paths starting with /var/ to /usr/local/hestia/nginx-system/var/
|
||||
# This pattern matches any absolute path that starts with /var/ anywhere in the line
|
||||
content = content.gsub(/\/var\//, '/usr/local/hestia/nginx-system/var/')
|
||||
|
||||
# Replace pid path from /run/nginx.pid to /run/nginx-system.pid
|
||||
content = content.gsub(/pid\s+\S+/) { |match| match.gsub('/run/nginx.pid', '/run/nginx-system.pid') }
|
||||
|
||||
if content != original_content
|
||||
File.write(source_path, content)
|
||||
hestia_print_info_message_to_cli "Updated config: #{source_path}"
|
||||
modified = true
|
||||
end
|
||||
|
||||
modified
|
||||
end
|
||||
|
||||
def parse_listen(line)
|
||||
# Попытка найти IP:port
|
||||
m = line.match(/^\s*listen\s+([^\s:]+):(\d+)/i)
|
||||
return [m[1], m[2]] if m
|
||||
# Если только порт после listen
|
||||
m = line.match(/^\s*listen\s+(\d+);?\s*$/i)
|
||||
return [nil, m[1]] if m
|
||||
nil
|
||||
end
|
||||
|
||||
# Helper function to parse and replace ports in listen directives using temp placeholders
|
||||
def parse_and_replace_listen_directive(line, proxy_port, proxy_ssl_port)
|
||||
return line unless line.match?(/\blisten\b/i)
|
||||
|
||||
new_line = line.dup
|
||||
|
||||
# Define target ports (always migrate to these values regardless of input)
|
||||
target_http_port = '8078'
|
||||
target_ssl_port = '8079'
|
||||
|
||||
result = parse_listen(line)
|
||||
return line unless result
|
||||
ip, port = result
|
||||
|
||||
if port == proxy_port
|
||||
if ip
|
||||
new_line.gsub!("#{ip}:#{port}", "#{ip}:#{target_http_port}")
|
||||
else
|
||||
new_line.gsub!(port, target_http_port)
|
||||
end
|
||||
elsif port == proxy_ssl_port
|
||||
if ip
|
||||
new_line.gsub!("#{ip}:#{port}", "#{ip}:#{target_ssl_port}")
|
||||
else
|
||||
new_line.gsub!(port, target_ssl_port)
|
||||
end
|
||||
end
|
||||
|
||||
new_line
|
||||
end
|
||||
|
||||
hestia_check_privileged_user
|
||||
|
||||
load_global_bash_variables "/etc/hestiacp/hestia.conf"
|
||||
if $HESTIA.nil?
|
||||
hestia_print_error_message_to_cli "Can't find HESTIA base path"
|
||||
exit 1
|
||||
end
|
||||
|
||||
load_global_bash_variables "#{$HESTIA}/conf/hestia.conf"
|
||||
|
||||
#------------------------------------------#
|
||||
# Verifications #
|
||||
#------------------------------------------#
|
||||
|
||||
check_args 1, ARGV, "COMMAND"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#------------------------------------------#
|
||||
# Action #
|
||||
#------------------------------------------#
|
||||
|
||||
case v_command.to_sym
|
||||
when :migratenginx
|
||||
log_migrate_stage('nstage0') do
|
||||
# Create backup of /etc/nginx with timestamp
|
||||
|
||||
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
||||
backup_root = "/etc/nginx_backup_#{timestamp}"
|
||||
FileUtils.mkdir_p(backup_root)
|
||||
|
||||
src_root = '/etc/nginx'
|
||||
dest_root = backup_root
|
||||
|
||||
# Custom copy function to handle symlinks in conf.d/domains
|
||||
def copy_with_symlinks(src, dest)
|
||||
Dir.foreach(src) do |entry|
|
||||
next if entry == '.' || entry == '..'
|
||||
src_path = File.join(src, entry)
|
||||
dest_path = File.join(dest, entry)
|
||||
|
||||
if File.symlink?(src_path)
|
||||
# Check if symlink is inside conf.d/domains
|
||||
if src_path.include?(File.join('conf.d', 'domains'))
|
||||
# Resolve the target of the symlink
|
||||
target_path = File.readlink(src_path)
|
||||
# Resolve relative symlink paths
|
||||
unless Pathname.new(target_path).absolute?
|
||||
target_path = File.expand_path(target_path, File.dirname(src_path))
|
||||
end
|
||||
if File.exist?(target_path) && File.file?(target_path)
|
||||
content = File.read(target_path)
|
||||
new_file_name = "#{entry}_content.conf"
|
||||
new_file_path = File.join(dest, new_file_name)
|
||||
File.write(new_file_path, content)
|
||||
end
|
||||
else
|
||||
# Preserve the symlink as is
|
||||
FileUtils.mkdir_p(File.dirname(dest_path))
|
||||
target = File.readlink(src_path)
|
||||
FileUtils.ln_s(target, dest_path)
|
||||
end
|
||||
elsif File.directory?(src_path)
|
||||
FileUtils.mkdir_p(dest_path)
|
||||
copy_with_symlinks(src_path, dest_path)
|
||||
else
|
||||
FileUtils.cp(src_path, dest_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
copy_with_symlinks(src_root, dest_root)
|
||||
end
|
||||
log_migrate_stage('nstage2') do
|
||||
unless system('yum install -y nginx-system')
|
||||
hestia_print_error_message_to_cli "Failed to install nginx-system via yum"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
log_migrate_stage('nstage3') do
|
||||
FileUtils.rm_f Dir.glob('/usr/local/hestia/nginx-system/etc/nginx/conf.d/*.conf')
|
||||
src_root = '/etc/nginx'
|
||||
dest_root = '/usr/local/hestia/nginx-system/etc/nginx'
|
||||
copy_nginx_files(src_root, dest_root)
|
||||
end
|
||||
log_migrate_stage('nstage4') do
|
||||
# Find all files under the nginx-system directory
|
||||
nginx_conf_dir = '/usr/local/hestia/nginx-system/etc/nginx'
|
||||
Dir.glob(File.join(nginx_conf_dir, '**', '*')).each do |path|
|
||||
hestia_print_info_message_to_cli "stage 4 processing file #{path}"
|
||||
next if File.directory?(path)
|
||||
content = File.read(path)
|
||||
new_content = content.gsub(/(?<!\/usr\/local\/hestia\/nginx-system)\/etc\/nginx/, '/usr/local/hestia/nginx-system/etc/nginx')
|
||||
if new_content != content
|
||||
hestia_print_info_message_to_cli "Changed path to config in file #{path}"
|
||||
File.open(path, 'w') { |f| f.write(new_content) }
|
||||
end
|
||||
end
|
||||
end
|
||||
log_migrate_stage('nstage4.1') do
|
||||
# Parse nginx.conf file to replace paths
|
||||
if migrate_nginx_config_from_file("/usr/local/hestia/nginx-system/etc/nginx/nginx.conf")
|
||||
hestia_print_info_message_to_cli "Completed migration of nginx.conf paths"
|
||||
else
|
||||
hestia_print_error_message_to_cli "Warning: Could not migrate nginx.conf from #{File.expand_path('/usr/local/hestia/nginx-system/etc/nginx/nginx.conf')}"
|
||||
end
|
||||
end
|
||||
log_migrate_stage('nstage7') do
|
||||
if system('/usr/local/hestia/bin/v-ext-modules enable update_module')
|
||||
output = IO.popen("/usr/local/hestia/bin/v-ext-modules state update_module json").read
|
||||
begin
|
||||
parsed = JSON.parse(output)
|
||||
if parsed.is_a?(Array) && parsed.first && parsed.first['STATE'] == 'enabled'
|
||||
system('/usr/local/hestia/bin/v-ext-modules-run update_module synctemplates')
|
||||
else
|
||||
hestia_print_error_message_to_cli "update_module not enabled after enable command"
|
||||
exit 1
|
||||
end
|
||||
rescue JSON::ParserError => e
|
||||
hestia_print_error_message_to_cli "Failed to parse JSON from state command: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "Failed to enable update_module"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
log_migrate_stage('stage9') do
|
||||
# Delete all contents inside /etc/nginx
|
||||
FileUtils.rm_rf Dir.glob('/etc/nginx/*')
|
||||
# Stop nginx service
|
||||
system('systemctl stop nginx')
|
||||
system('systemctl disable nginx')
|
||||
# Start nginx-system service
|
||||
system('systemctl enable nginx-system')
|
||||
system('systemctl start nginx-system')
|
||||
end
|
||||
else
|
||||
hestia_print_error_message_to_cli "unknown command (use migratenginx)"
|
||||
log_event E_ARGS, $ARGUMENTS
|
||||
exit 1
|
||||
end
|
||||
|
||||
exit 0
|
||||
@@ -86,7 +86,11 @@ if [ -n "$old_ip" ]; then
|
||||
|
||||
# Updating PROXY
|
||||
if [ -n "$PROXY_SYSTEM" ]; then
|
||||
cd /etc/$PROXY_SYSTEM/$pconfd
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
cd /usr/local/hestia/nginx-system/etc/nginx/$pconfd
|
||||
else
|
||||
cd /etc/$PROXY_SYSTEM/$pconfd
|
||||
fi
|
||||
if [ -e "$old_ip.conf" ]; then
|
||||
mv $old_ip.conf $new_ip.conf
|
||||
sed -i "s/$old_ip/$new_ip/g" $new_ip.conf
|
||||
@@ -95,7 +99,11 @@ if [ -n "$old_ip" ]; then
|
||||
|
||||
# Updating WEB
|
||||
if [ -n "$WEB_SYSTEM" ]; then
|
||||
cd /etc/$WEB_SYSTEM/$confd
|
||||
if [ "$WEB_SYSTEM" = "nginx" ]; then
|
||||
cd /usr/local/hestia/nginx-system/etc/nginx/$confd
|
||||
else
|
||||
cd /etc/$WEB_SYSTEM/$confd
|
||||
fi
|
||||
|
||||
if [ -e "$old_ip.conf" ]; then
|
||||
mv $old_ip.conf $new_ip.conf
|
||||
@@ -161,8 +169,8 @@ for ip in $ips; do
|
||||
prefixlen="$(ip -d -j addr show | jq --arg IP "$ip" -r '.[].addr_info[] | if .local == $IP then .prefixlen else empty end')"
|
||||
netmask="$(convert_cidr "$prefixlen")"
|
||||
$BIN/v-add-sys-ip "$ip" "$netmask" "$interface"
|
||||
elif [ -e "/etc/nginx/conf.d/$ip.conf" ]; then
|
||||
process_http2_directive "/etc/nginx/conf.d/$ip.conf"
|
||||
elif [ -e "/usr/local/hestia/nginx-system/etc/nginx/conf.d/$ip.conf" ]; then
|
||||
process_http2_directive "/usr/local/hestia/nginx-system/etc/nginx/conf.d/$ip.conf"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
84
bin/v-update-web-domain
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# info: update configs for web domain
|
||||
# options: USER DOMAIN TEMPLATE [RESTART]
|
||||
#
|
||||
# example: v-unpdate-web-domain admin acme.com test_template
|
||||
#
|
||||
# This function of updating of the domain's configs and set template or notemplate if just update of configs
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Variables & Functions #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Argument definition
|
||||
user=$1
|
||||
domain=$2
|
||||
domain_idn=$2
|
||||
template=$3
|
||||
restart=$4
|
||||
|
||||
# Includes
|
||||
# shellcheck source=/etc/hestiacp/hestia.conf
|
||||
source /etc/hestiacp/hestia.conf
|
||||
# shellcheck source=/usr/local/hestia/func/main.sh
|
||||
source $HESTIA/func/main.sh
|
||||
# shellcheck source=/usr/local/hestia/func/domain.sh
|
||||
source $HESTIA/func/domain.sh
|
||||
# shellcheck source=/usr/local/hestia/func/ip.sh
|
||||
source $HESTIA/func/ip.sh
|
||||
# load config file
|
||||
source_conf "$HESTIA/conf/hestia.conf"
|
||||
|
||||
# Additional argument formatting
|
||||
format_domain
|
||||
format_domain_idn
|
||||
# TODO: $domain_idn not used in this script - maybe $domain should be converted to $doman_idn ?
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Verifications #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
check_args '3' "$#" 'USER DOMAIN TEMPLATE [RESTART]'
|
||||
is_format_valid 'user' 'domain'
|
||||
is_system_enabled "$WEB_SYSTEM" 'WEB_SYSTEM'
|
||||
is_object_valid 'user' 'USER' "$user"
|
||||
is_object_valid 'web' 'DOMAIN' "$domain"
|
||||
|
||||
# Perform verification if read-only mode is enabled
|
||||
check_hestia_demo_mode
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Action #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Parsing domain values
|
||||
get_domain_values 'web'
|
||||
local_ip=$(get_real_ip $IP)
|
||||
|
||||
# Preparing domain values for the template substitution
|
||||
prepare_web_domain_values
|
||||
|
||||
if [ "$template" != "notemplate" ]; then
|
||||
update_object_value 'web' 'DOMAIN' "$domain" '$PROXY' "$template"
|
||||
$BIN/v-log-action "system" "Info" "Web" "Set new template=$template for $PROXY (User: $user, Domain: $domain)."
|
||||
fi
|
||||
|
||||
#----------------------------------------------------------#
|
||||
# Hestia #
|
||||
#----------------------------------------------------------#
|
||||
|
||||
# Update global configuration files
|
||||
$BIN/v-rebuild-web-domain "$user" "$domain" 'no'
|
||||
|
||||
# Restarting web server
|
||||
$BIN/v-restart-web "$restart"
|
||||
check_result $? "Web restart failed" > /dev/null
|
||||
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "system" "Info" "Web" "Updated web domain (User: $user, Domain: $domain)."
|
||||
log_event "$OK" "$ARGUMENTS"
|
||||
|
||||
exit
|
||||
@@ -90,6 +90,25 @@ check_result $? "Web restart failed" > /dev/null
|
||||
$BIN/v-restart-proxy "$restart"
|
||||
check_result $? "Proxy restart failed" > /dev/null
|
||||
|
||||
# Execute bunkerweb_module if it's enabled
|
||||
module_state=$($BIN/v-ext-modules state bunkerweb_module json | jq -r '.[0].STATE')
|
||||
if [ "$module_state" = "enabled" ] && [ "$BUNKERWEB" = "yes" ]; then
|
||||
BUNKW_DIR=$HOMEDIR/$user/conf/web/$domain/ssl/bunkerweb
|
||||
if [ ! -d "$BUNKW_DIR" ]; then
|
||||
mkdir -p "$BUNKW_DIR"
|
||||
chmod 0755 "$BUNKW_DIR"
|
||||
fi
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.crt" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.key" "$BUNKW_DIR/"
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.pem" "$BUNKW_DIR/"
|
||||
if [ -e "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" ]; then
|
||||
cp -f "$HOMEDIR/$user/conf/web/$domain/ssl/$domain.ca" "$BUNKW_DIR/"
|
||||
fi
|
||||
chown root:nginx "$BUNKW_DIR"/*
|
||||
chmod 0640 "$BUNKW_DIR"/*
|
||||
$BIN/v-ext-modules-run bunkerweb_module updssl "$domain" "$BUNKW_DIR/$domain.pem" "$BUNKW_DIR/$domain.key"
|
||||
fi
|
||||
|
||||
# Logging
|
||||
$BIN/v-log-action "$user" "Info" "Web" "SSL certificate updated (Domain: $domain)."
|
||||
log_event "$OK" "$EVENT"
|
||||
|
||||
@@ -50,11 +50,22 @@ for webtpl_folder in $(ls $HESTIA_INSTALL_DIR/templates/web/* -d 2> /dev/null |
|
||||
cp -rf "${webtpl_folder}" "${WEBTPL}/"
|
||||
done
|
||||
|
||||
versions_list=$(ls -d /etc/php/*)
|
||||
for php_ver in $versions_list; do
|
||||
[ ! -d "/etc/php/$php_ver/fpm/pool.d/" ] && continue
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/multiphp.tpl ${WEBTPL}/php-fpm/PHP-${php_ver/\./_}.tpl
|
||||
done
|
||||
versions_list=""
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
versions_list=$(ls -d /opt/brepo/php*)
|
||||
for php_ver in $versions_list; do
|
||||
[ ! -d "$php_ver/etc/php-fpm.d" ] && continue
|
||||
vers=$(echo "$php_ver" | awk -F"/" '{ print $4 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/multiphp.tpl ${WEBTPL}/php-fpm/PHP-${vers/\./_}.tpl
|
||||
done
|
||||
else
|
||||
versions_list=$(ls -d /etc/opt/remi/php*)
|
||||
for php_ver in $versions_list; do
|
||||
[ ! -d "$php_ver/php-fpm.d" ] && continue
|
||||
vers=$(echo "$php_ver" | awk -F"/" '{ print $5 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
cp -f $HESTIA_INSTALL_DIR/php-fpm/multiphp.tpl ${WEBTPL}/php-fpm/PHP-${vers/\./_}.tpl
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -n "$awstats_patch" ]; then
|
||||
# restore LoadPlugin variable
|
||||
|
||||
@@ -1,156 +1,224 @@
|
||||
import { defineConfig } from 'vitepress';
|
||||
import { version } from '../../package.json';
|
||||
import { defineConfig } from "vitepress";
|
||||
import { version } from "../../package.json";
|
||||
|
||||
export default defineConfig({
|
||||
lang: 'en-US',
|
||||
title: 'Hestia Control Panel',
|
||||
description: 'Open-source web server control panel.',
|
||||
lang: "en-US",
|
||||
title: "Hestia Control Panel",
|
||||
description: "Open-source web server control panel.",
|
||||
|
||||
lastUpdated: true,
|
||||
cleanUrls: false,
|
||||
lastUpdated: true,
|
||||
cleanUrls: false,
|
||||
|
||||
head: [
|
||||
['link', { rel: 'icon', sizes: 'any', href: '/favicon.ico' }],
|
||||
['link', { rel: 'icon', type: 'image/svg+xml', sizes: '16x16', href: '/logo.svg' }],
|
||||
['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }],
|
||||
['link', { rel: 'manifest', href: '/site.webmanifest' }],
|
||||
['meta', { name: 'theme-color', content: '#b7236a' }],
|
||||
],
|
||||
head: [
|
||||
["link", { rel: "icon", sizes: "any", href: "/favicon.ico" }],
|
||||
[
|
||||
"link",
|
||||
{ rel: "icon", type: "image/svg+xml", sizes: "16x16", href: "/logo.svg" },
|
||||
],
|
||||
[
|
||||
"link",
|
||||
{
|
||||
rel: "apple-touch-icon",
|
||||
sizes: "180x180",
|
||||
href: "/apple-touch-icon.png",
|
||||
},
|
||||
],
|
||||
["link", { rel: "manifest", href: "/site.webmanifest" }],
|
||||
["meta", { name: "theme-color", content: "#b7236a" }],
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
logo: '/logo.svg',
|
||||
themeConfig: {
|
||||
logo: "/logo.svg",
|
||||
|
||||
nav: nav(),
|
||||
nav: nav(),
|
||||
|
||||
socialLinks: [
|
||||
{ icon: 'github', link: 'https://dev.brepo.ru/bayrepo/hestiacp' },
|
||||
{ icon: 'github', link: 'https://github.com/bayrepo/hestiacp' },
|
||||
{ icon: 'github', link: 'https://github.com/hestiacp/hestiacp' },
|
||||
],
|
||||
socialLinks: [
|
||||
{ icon: "github", link: "https://dev.brepo.ru/bayrepo/hestiacp" },
|
||||
{ icon: "github", link: "https://github.com/bayrepo/hestiacp-rpm" },
|
||||
{ icon: "github", link: "https://github.com/hestiacp/hestiacp" },
|
||||
],
|
||||
|
||||
sidebar: { '/docs/': sidebarDocs() },
|
||||
sidebar: { "/docs/": sidebarDocs() },
|
||||
|
||||
outline: [2, 3],
|
||||
outline: [2, 3],
|
||||
|
||||
footer: {
|
||||
message: 'Выпущена под лицензией GPLv3.',
|
||||
copyright: 'Copyright © 2019-present Hestia Control Panel и некоторые RPM based компоненты принадлежат bayrepo',
|
||||
},
|
||||
|
||||
},
|
||||
footer: {
|
||||
message: "Выпущена под лицензией GPLv3.",
|
||||
copyright:
|
||||
"Copyright © 2019-present Hestia Control Panel и некоторые RPM based компоненты принадлежат bayrepo",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/** @returns {import("vitepress").DefaultTheme.NavItem[]} */
|
||||
function nav() {
|
||||
return [
|
||||
{ text: 'Характеристики', link: '/features.md' },
|
||||
{ text: 'Установка', link: '/install.md' },
|
||||
{ text: 'Документация', link: '/docs/introduction/getting-started.md', activeMatch: '/docs/' },
|
||||
{
|
||||
text: `v${version}`,
|
||||
items: [
|
||||
{
|
||||
text: 'Changelog',
|
||||
link: 'https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/CHANGELOG.md',
|
||||
},
|
||||
{
|
||||
text: 'Содействие в разработке',
|
||||
link: 'https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/CONTRIBUTING.md',
|
||||
},
|
||||
{
|
||||
text: 'Политика безопасности',
|
||||
link: 'https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/SECURITY.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
return [
|
||||
{ text: "Характеристики", link: "/features.md" },
|
||||
{ text: "Установка", link: "/install.md" },
|
||||
{
|
||||
text: "Документация",
|
||||
link: "/docs/introduction/getting-started.md",
|
||||
activeMatch: "/docs/",
|
||||
},
|
||||
{
|
||||
text: `v${version}`,
|
||||
items: [
|
||||
{
|
||||
text: "Changelog",
|
||||
link: "https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/CHANGELOG.md",
|
||||
},
|
||||
{
|
||||
text: "Содействие в разработке",
|
||||
link: "https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/CONTRIBUTING.md",
|
||||
},
|
||||
{
|
||||
text: "Политика безопасности",
|
||||
link: "https://dev.brepo.ru/bayrepo/hestiacp/src/branch/master/SECURITY.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
/** @returns {import("vitepress").DefaultTheme.SidebarItem[]} */
|
||||
function sidebarDocs() {
|
||||
return [
|
||||
{
|
||||
text: 'Знакомство',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'С чего начать', link: '/docs/introduction/getting-started.md' },
|
||||
{ text: 'Рекомендации', link: '/docs/introduction/best-practices.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Инструкция пользователя',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Аккаунт', link: '/docs/user-guide/account.md' },
|
||||
{ text: 'Резервные копии', link: '/docs/user-guide/backups.md' },
|
||||
{ text: 'Cron задачи', link: '/docs/user-guide/cron-jobs.md' },
|
||||
{ text: 'Базы данных', link: '/docs/user-guide/databases.md' },
|
||||
{ text: 'DNS', link: '/docs/user-guide/dns.md' },
|
||||
{ text: 'Менеджер файлов', link: '/docs/user-guide/file-manager.md' },
|
||||
{ text: 'Почтовые домены', link: '/docs/user-guide/mail-domains.md' },
|
||||
{ text: 'Оповещения', link: '/docs/user-guide/notifications.md' },
|
||||
{ text: 'Пакеты', link: '/docs/user-guide/packages.md' },
|
||||
{ text: 'Статистика', link: '/docs/user-guide/statistics.md' },
|
||||
{ text: 'Пользователи', link: '/docs/user-guide/users.md' },
|
||||
{ text: 'Веб домены', link: '/docs/user-guide/web-domains.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Администрирование сервера',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Создание резервных копий и восстановление', link: '/docs/server-administration/backup-restore.md' },
|
||||
{ text: 'Конфигурация', link: '/docs/server-administration/configuration.md' },
|
||||
{ text: 'Персональная настройка', link: '/docs/server-administration/customisation.md' },
|
||||
{ text: 'Базы данных и phpMyAdmin', link: '/docs/server-administration/databases.md' },
|
||||
{ text: 'DNS кластера & DNSSEC', link: '/docs/server-administration/dns.md' },
|
||||
{ text: 'Email', link: '/docs/server-administration/email.md' },
|
||||
{ text: 'Менеджер файлов', link: '/docs/server-administration/file-manager.md' },
|
||||
{ text: 'Firewall', link: '/docs/server-administration/firewall.md' },
|
||||
{ text: 'Обновления ОС', link: '/docs/server-administration/os-upgrades.md' },
|
||||
{ text: 'Rest API', link: '/docs/server-administration/rest-api.md' },
|
||||
{ text: 'SSL сертификаты', link: '/docs/server-administration/ssl-certificates.md' },
|
||||
{ text: 'Веб шаблоны и кэширование', link: '/docs/server-administration/web-templates.md' },
|
||||
{ text: 'Troubleshooting', link: '/docs/server-administration/troubleshooting.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Содейтсвие в разработке',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Сборка пакетов', link: '/docs/contributing/building.md' },
|
||||
{ text: 'Разработка', link: '/docs/contributing/development.md' },
|
||||
{ text: 'Документация', link: '/docs/contributing/documentation.md' },
|
||||
{ text: 'Установка приложений', link: '/docs/contributing/quick-install-app.md' },
|
||||
{ text: 'Тестирование', link: '/docs/contributing/testing.md' },
|
||||
{ text: 'Переводы', link: '/docs/contributing/translations.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Сообщество',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'Hestia Nginx Cache', link: '/docs/community/hestia-nginx-cache.md' },
|
||||
{
|
||||
text: 'Ioncube installer for Hestia',
|
||||
link: '/docs/community/ioncube-hestia-installer.md',
|
||||
},
|
||||
{ text: 'Генератор установочной команды', link: '/docs/community/install-script-generator.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Ссылки',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'API', link: '/docs/reference/api.md' },
|
||||
{ text: 'CLI', link: '/docs/reference/cli.md' },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: 'Дополнения',
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: 'PHP cli селектор', link: '/docs/extensions/php-cli-selector.md' },
|
||||
],
|
||||
},
|
||||
];
|
||||
return [
|
||||
{
|
||||
text: "Знакомство",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: "С чего начать",
|
||||
link: "/docs/introduction/getting-started.md",
|
||||
},
|
||||
{ text: "Рекомендации", link: "/docs/introduction/best-practices.md" },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Инструкция пользователя",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: "Аккаунт", link: "/docs/user-guide/account.md" },
|
||||
{ text: "Резервные копии", link: "/docs/user-guide/backups.md" },
|
||||
{ text: "Cron задачи", link: "/docs/user-guide/cron-jobs.md" },
|
||||
{ text: "Базы данных", link: "/docs/user-guide/databases.md" },
|
||||
{ text: "DNS", link: "/docs/user-guide/dns.md" },
|
||||
{ text: "Менеджер файлов", link: "/docs/user-guide/file-manager.md" },
|
||||
{ text: "Почтовые домены", link: "/docs/user-guide/mail-domains.md" },
|
||||
{ text: "Оповещения", link: "/docs/user-guide/notifications.md" },
|
||||
{ text: "Пакеты", link: "/docs/user-guide/packages.md" },
|
||||
{ text: "Статистика", link: "/docs/user-guide/statistics.md" },
|
||||
{ text: "Пользователи", link: "/docs/user-guide/users.md" },
|
||||
{ text: "Веб домены", link: "/docs/user-guide/web-domains.md" },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Администрирование сервера",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: "Создание резервных копий и восстановление",
|
||||
link: "/docs/server-administration/backup-restore.md",
|
||||
},
|
||||
{
|
||||
text: "Конфигурация",
|
||||
link: "/docs/server-administration/configuration.md",
|
||||
},
|
||||
{
|
||||
text: "Персональная настройка",
|
||||
link: "/docs/server-administration/customisation.md",
|
||||
},
|
||||
{
|
||||
text: "Базы данных и phpMyAdmin",
|
||||
link: "/docs/server-administration/databases.md",
|
||||
},
|
||||
{
|
||||
text: "DNS кластера & DNSSEC",
|
||||
link: "/docs/server-administration/dns.md",
|
||||
},
|
||||
{ text: "Email", link: "/docs/server-administration/email.md" },
|
||||
{
|
||||
text: "Менеджер файлов",
|
||||
link: "/docs/server-administration/file-manager.md",
|
||||
},
|
||||
{ text: "Firewall", link: "/docs/server-administration/firewall.md" },
|
||||
{
|
||||
text: "Обновления ОС",
|
||||
link: "/docs/server-administration/os-upgrades.md",
|
||||
},
|
||||
{ text: "Rest API", link: "/docs/server-administration/rest-api.md" },
|
||||
{
|
||||
text: "SSL сертификаты",
|
||||
link: "/docs/server-administration/ssl-certificates.md",
|
||||
},
|
||||
{
|
||||
text: "Веб шаблоны и кэширование",
|
||||
link: "/docs/server-administration/web-templates.md",
|
||||
},
|
||||
{
|
||||
text: "Troubleshooting",
|
||||
link: "/docs/server-administration/troubleshooting.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Содейтсвие в разработке",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: "Сборка пакетов", link: "/docs/contributing/building.md" },
|
||||
{ text: "Разработка", link: "/docs/contributing/development.md" },
|
||||
{ text: "Документация", link: "/docs/contributing/documentation.md" },
|
||||
{
|
||||
text: "Установка приложений",
|
||||
link: "/docs/contributing/quick-install-app.md",
|
||||
},
|
||||
{ text: "Тестирование", link: "/docs/contributing/testing.md" },
|
||||
{ text: "Переводы", link: "/docs/contributing/translations.md" },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Сообщество",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: "Hestia Nginx Cache",
|
||||
link: "/docs/community/hestia-nginx-cache.md",
|
||||
},
|
||||
{
|
||||
text: "Ioncube installer for Hestia",
|
||||
link: "/docs/community/ioncube-hestia-installer.md",
|
||||
},
|
||||
{
|
||||
text: "Генератор установочной команды",
|
||||
link: "/docs/community/install-script-generator.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Ссылки",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{ text: "API", link: "/docs/reference/api.md" },
|
||||
{ text: "CLI", link: "/docs/reference/cli.md" },
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "Дополнения",
|
||||
collapsed: false,
|
||||
items: [
|
||||
{
|
||||
text: "PHP cli селектор",
|
||||
link: "/docs/extensions/php-cli-selector.md",
|
||||
},
|
||||
{
|
||||
text: "Расширенные модули",
|
||||
link: "/docs/extensions/extended-modules.md",
|
||||
},
|
||||
{ text: "Настройка Local PHP", link: "/docs/extensions/local-php.md" },
|
||||
{
|
||||
text: "nginx+mod_rewrite",
|
||||
link: "/docs/extensions/nginx-mod-rewrite.md",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ export default {
|
||||
return {
|
||||
pageloader: false,
|
||||
hestia_wget:
|
||||
"wget https://raw.githubusercontent.com/bayrepo/hestiacp-rpm/refs/heads/rhel-version/install/hst-install.sh",
|
||||
hestia_wget_devel:
|
||||
"wget https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/hst-install.sh",
|
||||
hestia_install: "sudo bash hst-install.sh",
|
||||
installStr: "",
|
||||
@@ -27,10 +29,7 @@ export default {
|
||||
if (item.selectField) {
|
||||
return item.selected ? `${item.param} '${item.text}'` : "";
|
||||
}
|
||||
|
||||
return item.param.includes("force") && item.selected
|
||||
? item.param
|
||||
: `${item.param}${item.selected ? " yes" : " no"}`;
|
||||
return `${item.param}${item.selected ? " yes" : " no"}`;
|
||||
},
|
||||
generateString() {
|
||||
const installStr = this.items.map(this.getOptionString).filter(Boolean);
|
||||
@@ -156,6 +155,23 @@ export default {
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<p class="u-mb10">For downloading devel version use:</p>
|
||||
<div class="u-pos-relative">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control u-monospace u-mb10"
|
||||
v-model="hestia_wget_devel"
|
||||
readonly
|
||||
/>
|
||||
<button
|
||||
class="button-positioned"
|
||||
@click="copyToClipboard(hestia_wget_devel, $event.target)"
|
||||
type="button"
|
||||
title="Copy to Clipboard"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<p class="u-mb10">Then run the following command:</p>
|
||||
<div class="u-pos-relative">
|
||||
<textarea class="form-control u-min-height100" v-model="installStr" readonly />
|
||||
|
||||
@@ -22,6 +22,7 @@ export const webDomains = [
|
||||
{ text: 'PHP 8.2' },
|
||||
{ text: 'PHP 8.3' },
|
||||
{ text: 'PHP 8.4' },
|
||||
{ text: 'PHP 8.5' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -84,17 +84,17 @@ export const options = [
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
name: ' --mariadb',
|
||||
name: ' --mysql',
|
||||
id: 'mariadb',
|
||||
param: '--mariadb',
|
||||
param: '--mysql',
|
||||
desc: 'Ответление MySQL с дополнительными усовершенствованиями.',
|
||||
selected: true,
|
||||
conflicts: 'mysql8',
|
||||
},
|
||||
{
|
||||
name: ' --mysql8',
|
||||
name: ' --mysql-classic',
|
||||
id: 'mysql8',
|
||||
param: '--mysql8',
|
||||
param: '--mysql-classic',
|
||||
desc: 'База данных с открытым исходным кодом',
|
||||
selected: false,
|
||||
conflicts: 'mariadb',
|
||||
@@ -136,6 +136,14 @@ export const options = [
|
||||
desc: 'Сканировать почту на вирусы.',
|
||||
selected: true,
|
||||
depends: 'exim',
|
||||
},
|
||||
{
|
||||
name: ' --usemirrorclamav',
|
||||
id: 'usemirrorclamav',
|
||||
param: '--usemirrorclamav',
|
||||
desc: 'Использовать русское зеркало баз данных ClamaV',
|
||||
selected: false,
|
||||
depends: 'clamav',
|
||||
},
|
||||
{
|
||||
name: ' --spamassassin',
|
||||
@@ -146,12 +154,33 @@ export const options = [
|
||||
depends: 'exim',
|
||||
},
|
||||
{
|
||||
name: ' --iptables',
|
||||
id: 'iptables',
|
||||
param: '--iptables',
|
||||
name: ' --firewall',
|
||||
id: 'firewall',
|
||||
param: '--firewall',
|
||||
desc: 'Управлять фаерволом.',
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
name: ' --nopublicip',
|
||||
id: 'nopublicip',
|
||||
param: '--nopublicip',
|
||||
desc: 'Использовать локальный IP сервера',
|
||||
selected: false,
|
||||
},
|
||||
{
|
||||
name: ' --uselocalphp',
|
||||
id: 'uselocalphp',
|
||||
param: '--uselocalphp',
|
||||
desc: 'Использовать PHP из текущего репозитория HestiaCP',
|
||||
selected: false,
|
||||
},
|
||||
{
|
||||
name: ' --usemirrorclamav',
|
||||
id: 'usemirrorclamav',
|
||||
param: '--usemirrorclamav',
|
||||
desc: 'Использовать clamav с базами скачанными с зеркала в России',
|
||||
selected: false,
|
||||
},
|
||||
{
|
||||
name: ' --fail2ban',
|
||||
id: 'fail2ban',
|
||||
|
||||
151
docs/docs/extensions/extended-modules.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Расширенные модули
|
||||
|
||||
## Что такое модули
|
||||
|
||||
Модули расширения панели позволяют расширять функционал панели.
|
||||
|
||||
## Как управлять модулями
|
||||
|
||||
Для доступа к модулям расширения необходимо из-под пользователя `admin` перейти в `Настройки сервера`:
|
||||
|
||||

|
||||
|
||||
Далее в строке выбора настроек выбрать `Доп. модули`:
|
||||
|
||||

|
||||
|
||||
Далее откроется страинца достпных модулей и их сотояния.
|
||||
|
||||
Пример страницы с демонстрационными модулями приведен ниже:
|
||||
|
||||

|
||||
|
||||
Данная страница содержит следующую информацию:
|
||||
|
||||
- **ID модуля** - числовой идентификатор модуля
|
||||
- **Имя модуля** - сивольный идентификатор модуля
|
||||
- **Описание модуля** - краткая ифнормация о модуле
|
||||
- **Состояние** - включен(enabled) или выключен(disabled)
|
||||
- **Зависимости** - список модулей, которые должны быть включены для работы текущего модуля
|
||||
- **Конфигурация** - дополнительные настройки модуля (при наличии)
|
||||
|
||||
Если модуль выключен, его состояние отображается как disabled.
|
||||
|
||||
Для включения модуля необходимо нажать на кнопку <i class="fas fa-play"></i>, для выключения модуля необходимо нажать на кнопку <i class="fas fa-stop"></i>.
|
||||
|
||||
## Список предустановленных модулей
|
||||
|
||||
- **puppet_installer** - установить puppet, для большинства модулей требуется puppet для изменения конфигурации системы, поэтому требуется, чтоб этот модуль был включен, при включении он установит puppet в систему.
|
||||
- **empty_module** - пустой модуль, его включение или выключение не начто не влияет, является примером написания модулей
|
||||
- **passenger_manager** - модуль по установке и настройке passenger в систему.
|
||||
- **php_brepo_modules** - модуль по управлению расширениями Local PHP. [Описание интерфейса](/docs/extensions/local-php.md)
|
||||
|
||||
## Управление модулями из командной строки
|
||||
|
||||
Для управления модулями используется утилита `v-ext-modules`.
|
||||
|
||||
Доступные команды:
|
||||
|
||||
- **list** - вывести список доступных модулей
|
||||
- **enable module_name** - включить модуль
|
||||
- **disable module_name** - выключить модуль
|
||||
- **state module_name** - состояние модуля
|
||||
|
||||
Примеры:
|
||||
|
||||
```
|
||||
# v-ext-modules list csv
|
||||
1,puppet_installer,"Added puppet support, needed for another modules","","",enabled
|
||||
2,passenger_manager,Added passenger support for nginx,puppet_installer,yes,enabled
|
||||
3,empty_module,Just empty module for storing max module id,"","",disabled
|
||||
```
|
||||
|
||||
```
|
||||
# v-ext-modules state passenger_manager
|
||||
ID NAME DESCR STATE REQ CONF
|
||||
-- ---- ----- ----- --- ----
|
||||
2 passenger_manager Added passenger support for nginx enabled puppet_installer yes
|
||||
```
|
||||
|
||||
## passenger_manager
|
||||
|
||||
Модуль, для добавления поддержки passenger+nginx для запуска (пока что только) ruby приложений.
|
||||
|
||||
### passenger_manager настройка
|
||||
|
||||
Для настройки модуля нажмите на ссылку `Изменить`:
|
||||
|
||||

|
||||
|
||||
Откроется страница вида:
|
||||
|
||||

|
||||
|
||||
- **Добавить новый путь ruby** - добавить путь к бинарному файлу интерпретатору ruby, если его еще нет в списке ниже
|
||||
- **Ruby list** - список достпных для выбора ruby интерпретаторов. Для удаления ruby из списка необходимо нажать на значек <i class="fas fa-trash-can"></i>.
|
||||
|
||||
При активации `passenger_manager` в меню настройки домена для пользователя появляется кнопка `Настройки passenger`:
|
||||
|
||||

|
||||
|
||||
При нажатии на которую открывается форма:
|
||||
|
||||

|
||||
|
||||
Где можно активировать passenger для домена установкой галочки `Включить passenger для домена`, а так же выбрать из списка ruby.
|
||||
|
||||
Галочка `Включить логирование в браузер`, активирует вывод лога ошибки приложения в браузер, рекомендуется ее включать только при настройке приложения.
|
||||
|
||||
Пример установки приложения:
|
||||
|
||||
пусть есть пользователь `test2` и домен `ttt142.my.brp`, для него активируется passenger.
|
||||
|
||||
Для него генерируются следующие настройки:
|
||||
|
||||
```
|
||||
location / {
|
||||
passenger_base_uri /;
|
||||
passenger_app_root /home/test2/web/ttt142.my.brp/private;
|
||||
passenger_document_root /home/test2/web/ttt142.my.brp/public_html;
|
||||
passenger_startup_file config.rb;
|
||||
passenger_app_type rack;
|
||||
}
|
||||
```
|
||||
|
||||
В `config.rb` необходимо поместить инструкции запуска приложения:
|
||||
|
||||
```
|
||||
# encoding: UTF-8
|
||||
require './test'
|
||||
run Sinatra::Application
|
||||
```
|
||||
|
||||
и соновное приложение разметсить в каталоге `/home/test2/web/ttt142.my.brp/private`.
|
||||
|
||||
Остальная логика будет размещена в `test.rb`, для примера вот так:
|
||||
|
||||
```
|
||||
!/usr/bin/env ruby
|
||||
|
||||
require 'sinatra'
|
||||
get '/' do
|
||||
"Hello #{Process.uid}"
|
||||
end
|
||||
```
|
||||
|
||||
Статические файлы располагать в каталоге `/home/test2/web/ttt142.my.brp/public_html`, а так же из этого каталога удалить файл `index.html` создаваемый как заглушка для пустого сайта.
|
||||
|
||||
Так же создать файл `Gemfile` в каталоге `/home/test2/web/ttt142.my.brp/private` и выполнить от пользователя:
|
||||
|
||||
```
|
||||
bundle config set --local path 'vendor'
|
||||
bundle install
|
||||
```
|
||||
|
||||
или по старому:
|
||||
|
||||
```
|
||||
bundle install --path=vendor
|
||||
```
|
||||
|
||||
для установки пользователю необходимых гемов локально.
|
||||
35
docs/docs/extensions/local-php.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Local PHP
|
||||
|
||||
PHP интерпретатор из репозитория, из которого ставится HestiaCP RPM Edition.
|
||||
HestiaCP RPM Edition имеет возможность работать или с PHP из Remi репозитория или с PHP из т.н. локального репозитория - Local PHP.
|
||||
|
||||
Если требуется более расширенный функционал пакетов из Remi репозитория, то следует отказаться при установке панели от опции `uselocalphp yes` и установить панель с опцией `uselocalphp no`.
|
||||
|
||||
Local PHP более ограниченный в наборе расширений, но занимает меньше места на диске и приносит меньше RPM пакетов. Подходит для большинства сборок CMS таких как Wordpress, Drupal и т.д.
|
||||
|
||||
Есть еще одна особенность, для данного типа PHP разработан графический интерфейс по управлению подключенными расширениями.
|
||||
|
||||
## Графический интерфейс управления расширениями PHP
|
||||
|
||||
Для включения графического интерфейса необходимо перейти в настройки панели под администратором и выбрать закладку "Дополнительные модули".
|
||||
|
||||

|
||||
|
||||
На окрывшейся веб странице необходимо активировать модуль **php_brepo_modules**.
|
||||
|
||||

|
||||
|
||||
Справа от названия модуля появится пункт меню - `Изменить`.
|
||||
|
||||
При нажатии мышкой на ссылку `Изменить`, откроется окно выбора версии PHP, для которой требуется перенастройка расширений.
|
||||
|
||||

|
||||
|
||||
Здесь будут отображаться все установленные на сервере версии Local PHP. Для настройки модулей необходимо нажать мышкой на шестеренке справа от версии PHP (<i class="fa-solid fa-gear icon-purple"></i>), в пункте меню `Изменить список модулей` <i class="fa-solid fa-gear icon-purple"></i>.
|
||||
|
||||
Откроется страница выбора расширений.
|
||||
|
||||

|
||||
|
||||
Здесь приведен список установленных расширений. Галочками подсвечены активные расширения.
|
||||
Здесь можно убрать галочки напротив названия модуля или наоборот установить галочку. И нажать `Сохранить` для изменения конфигурации расширений для выбранной версии PHP или `Назад`, для отмены изменений.
|
||||
15
docs/docs/extensions/nginx-mod-rewrite.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# nginx с поддержкой mdo_rewrite
|
||||
|
||||
HestiaCP RPM edition поддерживает установку приложений для доменов, таких как Wordpress, Joomla, Drupal и т.д.
|
||||
|
||||
Данные приложения написаны на PHP и требуют особого режима доступа к файлам, который реализуется с помощью .htaccess файла, в котором опианы эти правила преобразования URL.
|
||||
|
||||
Но .htaccess файл доступен только для Apache, для реализации работоспособнсти приложений в контрольной панели организованы шаблоны конфигурации nginx, которые по сути являются аналогами конфигурации из .htaccess.
|
||||
|
||||
Эти шаблоны размещены в каталоге `/usr/local/hestia/data/templates/web/nginx/php-fpm`.
|
||||
|
||||
# nginx + mod_rewrite
|
||||
|
||||
Но с версии 1.28.2 nginx добавлен экспериментальный модуль mod_rewrite для nginx, который позволяет понимать конфигурации из .htaccess и для nginx.
|
||||
|
||||
Для активации данной конфигурации, необходимо в настройках домена в `Расширенных настройках` выбрать в поле `Шаблон прокси` шаблон `nginx-php-rewrite`. Данный шаблон автоматически определит версию PHP-FPM для домена и активирует работу модуля mod_rewrite для nginx. Для данного домена Apache больше не будет принимать участие в обработке запроса, все будет обрабатываться в связке nginx-PHP-FPM.
|
||||
@@ -58,5 +58,7 @@
|
||||
|
||||
## Дополнения
|
||||
|
||||
- [PHP cli селектор](/docs/extensions/php-cli-selector.md')
|
||||
|
||||
- [PHP cli селектор](/docs/extensions/php-cli-selector.md)
|
||||
- [Расширенные модули](/docs/extensions/extended-modules.md)
|
||||
- [Настройка Local PHP](/docs/extensions/local-php.md)
|
||||
- [nginx + mod_rewrite](/docs/extensions/nginx-mod-rewrite.md)
|
||||
|
||||
@@ -93,14 +93,16 @@ bash hst-install.sh -h
|
||||
-Z, --sieve Install Sieve [yes|no] default: no
|
||||
-c, --clamav Install ClamAV [yes|no] default: no
|
||||
-t, --spamassassin Install SpamAssassin [yes|no] default: yes
|
||||
-i, --iptables Install Iptables [yes|no] default: yes
|
||||
-i, --firewall Install firewalld [yes|no] default: yes
|
||||
-b, --fail2ban Install Fail2ban [yes|no] default: yes
|
||||
-q, --quota Filesystem Quota [yes|no] default: no
|
||||
-d, --api Activate API [yes|no] default: yes
|
||||
-r, --port Change Backend Port default: 8083
|
||||
-l, --lang Default language default: en
|
||||
-y, --interactive Interactive install [yes|no] default: yes
|
||||
-I, --nopublicip Use local ip [yes|no] default: yes
|
||||
-I, --nopublicip Use local ip [yes|no] default: no
|
||||
-u, --uselocalphp Use PHP from local repo [yes|no] default: no
|
||||
-C, --usemirrorclamav Use mirrored clamav [yes|no] default: no
|
||||
-s, --hostname Set hostname
|
||||
-e, --email Set admin email
|
||||
-p, --password Set admin password
|
||||
@@ -118,14 +120,14 @@ bash hst-install.sh \
|
||||
--hostname host.domain.tld \
|
||||
--email email@domain.tld \
|
||||
--password p4ssw0rd \
|
||||
--lang fr \
|
||||
--lang ru \
|
||||
--apache no \
|
||||
--named no \
|
||||
--clamav no \
|
||||
--spamassassin no
|
||||
```
|
||||
|
||||
Эта команда установит Hestia на французском с такой конфигурацией:
|
||||
Эта команда установит Hestia на русском с такой конфигурацией:
|
||||
|
||||
- Nginx веб сервер
|
||||
- PHP-FPM сервер приложений
|
||||
@@ -140,3 +142,11 @@ bash hst-install.sh \
|
||||
К настоящему моменту у вас должна быть установлена Hestia на вашем сервере. Вы готовы добавлять новых пользователей, чтобы вы (или они) могли добавлять новые веб-сайты на вашем сервере.
|
||||
|
||||
Чтобы получить доступ к панели управления, перейдите по адресу `https://host.domain.tld:8083` или `http://your.public.ip.address:8083`
|
||||
|
||||
## Расширенные опции RPM версии
|
||||
|
||||
Данная реадкция HestiaCP RPM Edition включает дополнительные оции такие как:
|
||||
|
||||
- `-I, --nopublicip` - если установлена данная опция, то установщик панели не получает внешний IP адрес сервера, где контрольная панель устанавливается (на случай если ваш сервер за NAT). Данную опцию можно включать, если у вас на сервере публичный IP или необходима внутрисетевая установка без внешнего доступа.
|
||||
|
||||
- `-u, --uselocalphp` - включить установку пакетов PHP из того-же репозитория, откуда ставится HestiaCP RPM Edition. Если не включать данную опцию, то PHP пакеты будут установлены из репозитория Remi. Если включить, то будет произведена так называемая установка локальных пакетов. Есть отличия в способе упаковке Local PHP и Remi PHP. Если сервера требуется расширенный набор PHP из Remi репозитория, то данную опцию лучше отключить, т.е задать `--uselocalphp no`. Local PHP более простая сборка с меньшим числом поддерживаемых модулей PHP, но подходит для большинства конфигураций CMS и имеет [страницу настройки подключаемых модулей](/docs/extensions/local-php.md)
|
||||
@@ -83,13 +83,13 @@ cp original.sh new.sh
|
||||
## Установка модулей PHP
|
||||
|
||||
```bash
|
||||
apt install php-package-name
|
||||
dnf install php-package-name
|
||||
```
|
||||
|
||||
Например, следующая команда установит `php-memcached` и `php-redis`, включая необходимые дополнительные пакеты для PHP.
|
||||
|
||||
```bash
|
||||
apt install php-memcached php-redis
|
||||
dnf install php-memcached php-redis
|
||||
```
|
||||
|
||||
## Nginx FastCGI Cache
|
||||
@@ -102,12 +102,6 @@ FastCGI применяется только для сервера Nginx + PHP-FP
|
||||
|
||||
Кэш FastCGI лучше всего подходит для сайтов, получающих много запросов и страницы которых не так часто меняются, например, новостной сайт. Для более динамичных сайтов могут потребоваться изменения в конфигурации или полное его отключение.
|
||||
|
||||
### Почему программные пакеты x и y не работают с кэшем FastCGI
|
||||
|
||||
Поскольку у нас более 20 различных шаблонов, и мы не используем их все, мы решили прекратить выпуск новых в будущем и надеемся, что сообщество поможет улучшить шаблоны, [отправив запрос на извлечение](https://github.com/hestiacp/hestiacp/pulls).
|
||||
|
||||
Если вы хотите добавить поддержку определенного шаблона, следуйте инструкциям ниже.
|
||||
|
||||
### Как включить кэш FastCGI для моего пользовательского шаблона
|
||||
|
||||
Найдите блок, в котором вы вызываете `fastcgi_pass`:
|
||||
@@ -118,11 +112,11 @@ fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
try_files $uri =404;
|
||||
fastcgi_pass %backend_lsnr%;
|
||||
fastcgi_index index.php;
|
||||
include /etc/nginx/fastcgi_params;
|
||||
include /usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/etc/nginx/fastcgi_params;
|
||||
}
|
||||
```
|
||||
|
||||
Добавьте следующие строки под `include /etc/nginx/fastcgi_params;`:
|
||||
Добавьте следующие строки под `include /usr/local/hestia/nginx-system/usr/local/hestia/nginx-system/etc/nginx/fastcgi_params;`:
|
||||
|
||||
```bash
|
||||
include %home%/%user%/conf/web/%domain%/nginx.fastcgi_cache.conf*;
|
||||
@@ -153,7 +147,7 @@ v-purge-nginx-cache user domain.tld
|
||||
Да, Hestia отлично работает с веб-сокетами, однако наши шаблоны по умолчанию включают по умолчанию:
|
||||
|
||||
```bash
|
||||
proxy_hide_header Обновление
|
||||
proxy_hide_header Upgrade
|
||||
```
|
||||
|
||||
Это решило проблему с загрузкой веб-сайтов Safari.
|
||||
|
||||
@@ -123,8 +123,12 @@
|
||||
|
||||
Здесь также будут отображаться любые пользовательские шаблоны.
|
||||
|
||||
- **srvproxy**: шаблон для конфигурации прокси для любого внутреннего сервиса, например gitea, который запускается и присоединеятся к порту или создает unix-сокет. При выборе данного шаблона, появляется дополнительное поле `Установить порт для локального сервиса`, в котором нужно указать путь к unix-сокету или порт внутреннего сервиса. В качестве шаблона Backend в данном случае можно выбрать `no-php`, т.к. в данном случае бакэндом будет сервис.
|
||||
|
||||

|
||||
|
||||
::: tip
|
||||
Любые пользовательские шаблоны, начинающиеся с `caching-`, позволят использовать кнопку **<i class="fas fa-fw fa-trash"></i> Очистить кэш Nginx**. Убедитесь, что файл `.sh` существует для `caching-my-template` с как минимум [этим содержимым](https://github.com/hestiacp/hestiacp/blob/main/install/deb/templates/web/nginx/caching.sh)
|
||||
Любые пользовательские шаблоны, начинающиеся с `caching-`, позволят использовать кнопку **<i class="fas fa-fw fa-trash"></i> Очистить кэш Nginx**. Убедитесь, что файл `.sh` существует для `caching-my-template` с как минимум [этим содержимым](https://dev.brepo.ru/bayrepo/hestiacp/raw/branch/master/install/rpm/templates/web/nginx/caching.sh)
|
||||
:::
|
||||
|
||||
### Веб-шаблоны
|
||||
@@ -137,4 +141,14 @@
|
||||
|
||||
Когда включено кэширование Nginx (с использованием кэша FastCGI или с шаблоном с поддержкой кэширования), вы можете очистить кэш с помощью кнопки **<i class="fas fa-fw fa-trash"></i> Очистить кэш Nginx**.
|
||||
|
||||
При использовании только Nginx вы можете включить кэширование FastCGI с помощью поля **Включить кэш FastCGI**. Если этот флажок установлен, отображается опция, позволяющая определить, в течение какого времени кэш считается действительным.
|
||||
При использовании только Nginx вы можете включить кэширование FastCGI с помощью поля **Включить кэш FastCGI**. Если этот флажок установлен, отображается опция, позволяющая определить, в течение какого времени кэш считается действительным.
|
||||
|
||||
### Домен по умолчанию
|
||||
|
||||
Для вебсервера Apache при обращении по IP адресу без указания домена доменом по умолчанию является первый загруженный виртуальный хост.
|
||||
|
||||
Для изменения домена по умолчанию необходимо выбрать среди доменов интересующий и в настройках домена необходимо установить флажок:
|
||||
|
||||
**Установить текущий домен как домент по умолчанию при обращении к серверу по IP**
|
||||
|
||||
затем нажмите кнопку **<i class="fas fa-fw fa-save"></i> Сохранить** в правом верхнем углу.
|
||||
0
docs/public/images/demo.png
Normal file
BIN
docs/public/images/ext_modules_step1.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/public/images/ext_modules_step2.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
docs/public/images/ext_modules_step3.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
docs/public/images/ext_modules_step4.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/public/images/ext_modules_step5.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
docs/public/images/ext_modules_step6.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
docs/public/images/ext_modules_step7.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/public/images/local_php_1.png
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
docs/public/images/local_php_2.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
docs/public/images/local_php_3.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/public/images/proxy_domain.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
234
func/domain.sh
@@ -101,34 +101,33 @@ is_web_alias_new() {
|
||||
prepare_web_backend() {
|
||||
# Accept first function argument as backend template otherwise fallback to $template global variable
|
||||
local backend_template=${1:-$template}
|
||||
php_type=$(cat "$HESTIA/conf/hestia.conf" | grep "LOCAL_PHP" | grep "yes")
|
||||
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
pool=$(find -L /etc/opt/remi/php80/ -name "$domain.conf" -exec dirname {} \; 2>/dev/null)
|
||||
if [ -n "$php_type" ]; then
|
||||
pool=$(find -L /opt/brepo/ -name "$domain.conf" -exec dirname {} \; 2>/dev/null)
|
||||
else
|
||||
pool=$(find -L /etc/php/ -name "$domain.conf" -exec dirname {} \;)
|
||||
pool=$(find -L /etc/opt/remi/php80/ -name "$domain.conf" -exec dirname {} \; 2>/dev/null)
|
||||
fi
|
||||
# Check if multiple-PHP installed
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
regex="^.*PHP-([0-9])([0-9])$"
|
||||
else
|
||||
regex="^.*PHP-([0-9])\_([0-9])$"
|
||||
fi
|
||||
regex="^.*PHP-([0-9])([0-9])$"
|
||||
|
||||
if [[ $backend_template =~ $regex ]]; then
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
if [ -n "$php_type" ]; then
|
||||
backend_version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
|
||||
pool=$(find -L /opt/brepo/php$backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
else
|
||||
backend_version="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
|
||||
pool=$(find -L /etc/opt/remi/php$backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
else
|
||||
backend_version="${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
|
||||
pool=$(find -L /etc/php/$backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
fi
|
||||
else
|
||||
backend_version=$(multiphp_default_version)
|
||||
if [ -z "$pool" ] || [ -z "$BACKEND" ]; then
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
if [ -n "$php_type" ]; then
|
||||
m_backend_version="${backend_version//./}"
|
||||
pool=$(find -L /opt/brepo/php$m_backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
else
|
||||
m_backend_version="${backend_version//./}"
|
||||
pool=$(find -L /etc/opt/remi/php$m_backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
else
|
||||
pool=$(find -L /etc/php/$backend_version -type d \( -name "pool.d" -o -name "*fpm.d" \))
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -151,11 +150,12 @@ prepare_web_backend() {
|
||||
|
||||
# Delete web backend
|
||||
delete_web_backend() {
|
||||
if [ -f "/etc/redhat-release" ]; then
|
||||
find -L /etc/opt/remi/ -name "$backend_type.conf" -exec rm -f {} \;
|
||||
else
|
||||
find -L /etc/php/ -type f -name "$backend_type.conf" -exec rm -f {} \;
|
||||
fi
|
||||
php_type=$(cat "$HESTIA/conf/hestia.conf" | grep "LOCAL_PHP" | grep "yes")
|
||||
if [ -n "$php_type" ]; then
|
||||
find -L /opt/brepo/php* -name "$backend_type.conf" -exec rm -f {} \;
|
||||
else
|
||||
find -L /etc/opt/remi/ -name "$backend_type.conf" -exec rm -f {} \;
|
||||
fi
|
||||
}
|
||||
|
||||
# Prepare web aliases
|
||||
@@ -193,6 +193,7 @@ prepare_web_domain_values() {
|
||||
fi
|
||||
group="$user"
|
||||
docroot="$HOMEDIR/$user/web/$domain/public_html"
|
||||
docrtpriv="$HOMEDIR/$user/web/$domain/private"
|
||||
sdocroot="$docroot"
|
||||
if [ "$SSL_HOME" = 'single' ]; then
|
||||
sdocroot="$HOMEDIR/$user/web/$domain/public_shtml"
|
||||
@@ -271,6 +272,7 @@ convert_proxy_ngix_internal_redirect(){
|
||||
# Add web config
|
||||
add_web_config() {
|
||||
# Check if folder already exists
|
||||
TPLNM="$2"
|
||||
if [ "$1" = "httpd" ]; then
|
||||
confd="conf.h.d"
|
||||
else
|
||||
@@ -281,8 +283,30 @@ add_web_config() {
|
||||
mkdir -p "$HOMEDIR/$user/conf/web/$domain/"
|
||||
fi
|
||||
|
||||
PASS_TPL=""
|
||||
if [[ "$TPLNM" =~ ^passenger ]]; then
|
||||
#Passenger generator
|
||||
if [ -e /usr/local/hestia/bin/v-ext-modules ]; then
|
||||
res=$(/usr/local/hestia/bin/v-ext-modules state passenger_manager csv | tail -n 1 | /usr/bin/xargs | cut -d"," -f6 )
|
||||
if [ -n "$res" ]; then
|
||||
enabled=$(echo "$res" | grep enabled)
|
||||
if [ -n "$enabled" ]; then
|
||||
RUBY_RES=$(/usr/local/hestia/bin/v-ext-modules-run passenger_manager get_user_ruby "$domain" csv | tail -n1 | /usr/bin/xargs | cut -d"," -f1)
|
||||
RUBY_RES_LOG=$(/usr/local/hestia/bin/v-ext-modules-run passenger_manager get_user_ruby "$domain" csv | tail -n1 | /usr/bin/xargs | cut -d"," -f2)
|
||||
if [ -n "$RUBY_RES" ]; then
|
||||
pass_tpl_dir=$(/usr/local/hestia/bin/v-ext-modules-run passenger_manager get_tpl_path | tail -n1 | /usr/bin/xargs)
|
||||
if [ -n "$pass_tpl_dir" ]; then
|
||||
pass_tpl_dir=${pass_tpl_dir%/}
|
||||
PASS_TPL="$pass_tpl_dir"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
conf="$HOMEDIR/$user/conf/web/$domain/$1.conf"
|
||||
if [[ "$2" =~ stpl$ ]]; then
|
||||
if [[ "$TPLNM" =~ stpl$ ]]; then
|
||||
conf="$HOMEDIR/$user/conf/web/$domain/$1.ssl.conf"
|
||||
fi
|
||||
|
||||
@@ -291,17 +315,21 @@ add_web_config() {
|
||||
|
||||
WEBTPL_LOCATION="$WEBTPL/$1"
|
||||
if [ "$1" != "$PROXY_SYSTEM" ] && [ -n "$WEB_BACKEND" ] && [ -d "$WEBTPL_LOCATION/$WEB_BACKEND" ]; then
|
||||
if [ -f "$WEBTPL_LOCATION/$WEB_BACKEND/$2" ]; then
|
||||
if [ -f "$WEBTPL_LOCATION/$WEB_BACKEND/$TPLNM" ]; then
|
||||
# check for backend specific template
|
||||
WEBTPL_LOCATION="$WEBTPL/$1/$WEB_BACKEND"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$TPLNM" =~ ^passenger ]] && [ -n "$PASS_TPL" ]; then
|
||||
WEBTPL_LOCATION="$PASS_TPL"
|
||||
fi
|
||||
|
||||
# Note: Removing or renaming template variables will lead to broken custom templates.
|
||||
# -If possible custom templates should be automatically upgraded to use the new format
|
||||
# -Alternatively a depreciation period with proper notifications should be considered
|
||||
|
||||
cat "${WEBTPL_LOCATION}/$2" \
|
||||
cat "${WEBTPL_LOCATION}/$TPLNM" \
|
||||
| sed -e "s|%ip%|$local_ip|g" \
|
||||
-e "s|%domain%|$domain|g" \
|
||||
-e "s|%domain_idn%|$domain_idn|g" \
|
||||
@@ -329,9 +357,10 @@ add_web_config() {
|
||||
-e "s|%ssl_pem%|$ssl_pem|g" \
|
||||
-e "s|%ssl_ca_str%|$ssl_ca_str|g" \
|
||||
-e "s|%ssl_ca%|$ssl_ca|g" \
|
||||
-e "s|%docrtpriv%|$docrtpriv|g" \
|
||||
> $conf
|
||||
|
||||
if [ "$2" == "srvproxy.tpl" -o "$2" == "srvproxy.stpl" ];then
|
||||
|
||||
if [ "$TPLNM" == "srvproxy.tpl" -o "$TPLNM" == "srvproxy.stpl" ];then
|
||||
proxy_backend_port_internal=$(convert_proxy_ngix_internal_redirect "$3")
|
||||
cat "$conf" \
|
||||
| sed -e "s|%proxy_backend_srv_port%|$proxy_backend_port_internal|g" \
|
||||
@@ -339,14 +368,26 @@ add_web_config() {
|
||||
mv -f ${conf}.tmp $conf
|
||||
fi
|
||||
|
||||
if [[ "$TPLNM" =~ ^passenger ]] && [ -n "$PASS_TPL" ]; then
|
||||
cat "$conf" \
|
||||
| sed -e "s|%rubypath%|$RUBY_RES|g" \
|
||||
-e "s|%rubylog%|$RUBY_RES_LOG|g" \
|
||||
> $conf.tmp
|
||||
mv -f ${conf}.tmp $conf
|
||||
fi
|
||||
|
||||
process_http2_directive "$conf"
|
||||
|
||||
chown root:$user $conf
|
||||
chmod 640 $conf
|
||||
|
||||
if [[ "$2" =~ stpl$ ]]; then
|
||||
if [[ "$TPLNM" =~ stpl$ ]]; then
|
||||
rm -f /etc/$1/$confd/domains/$domain.ssl.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$domain.ssl.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$domain.ssl.conf
|
||||
else
|
||||
ln -s $conf /etc/$1/$confd/domains/$domain.ssl.conf
|
||||
fi
|
||||
|
||||
# Rename/Move extra SSL config files
|
||||
find=$(find $HOMEDIR/$user/conf/web/*.$domain.org* 2> /dev/null)
|
||||
@@ -362,8 +403,13 @@ add_web_config() {
|
||||
fi
|
||||
done
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$domain.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$domain.conf
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$domain.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$domain.conf
|
||||
fi
|
||||
# Rename/Move extra config files
|
||||
find=$(find $HOMEDIR/$user/conf/web/*.$domain.org* 2> /dev/null)
|
||||
for f in $find; do
|
||||
@@ -382,11 +428,41 @@ add_web_config() {
|
||||
done
|
||||
fi
|
||||
|
||||
trigger="${2/.*pl/.sh}"
|
||||
#----
|
||||
|
||||
php_type=$(cat "$HESTIA/conf/hestia.conf" | grep "LOCAL_PHP" | grep "yes")
|
||||
|
||||
MOD_CONF="/etc/httpd/conf.modules.d/09-mod-php.conf"
|
||||
PHP_DEFAULT="/usr/bin/php-cgi"
|
||||
if [ -e $MOD_CONF ]; then
|
||||
php_ver=$(grep -m1 '^LoadModule php_module ' "$MOD_CONF" | grep -oP 'php\d{2}')
|
||||
else
|
||||
php_ver=$(find /etc/httpd/conf.modules.d -maxdepth 1 -type f -name '*-php*-php.conf' -print -quit | sed -n 's/.*-\(php[0-9]\+\)-php\.conf$/\1/p')
|
||||
fi
|
||||
php_cgi_path=$PHP_DEFAULT
|
||||
|
||||
if [ -n "$php_ver" ]; then
|
||||
if [ -n "$php_type" ]; then
|
||||
php_cgi_path="/opt/brepo/${php_ver}/bin/php-cgi"
|
||||
else
|
||||
php_cgi_path="/opt/remi/${php_ver}/root/bin/php-cgi"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -x "$php_cgi_path" ]]; then
|
||||
:
|
||||
else
|
||||
php_cgi_path=$PHP_DEFAULT
|
||||
fi
|
||||
|
||||
#----
|
||||
|
||||
trigger="${TPLNM/.*pl/.sh}"
|
||||
if [ -x "${WEBTPL_LOCATION}/$trigger" ]; then
|
||||
$WEBTPL_LOCATION/$trigger \
|
||||
$user $domain $local_ip $HOMEDIR \
|
||||
$HOMEDIR/$user/web/$domain/public_html
|
||||
$HOMEDIR/$user/web/$domain/public_html \
|
||||
$php_cgi_path
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -451,17 +527,29 @@ del_web_config() {
|
||||
rm -f $legacyconf
|
||||
|
||||
# Remove old global includes file
|
||||
rm -f /etc/$1/$confd/hestia.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/hestia.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/hestia.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remove domain configuration files and clean up symbolic links
|
||||
rm -f "$conf"
|
||||
|
||||
if [ -n "$WEB_SYSTEM" ] && [ "$WEB_SYSTEM" = "$1" ]; then
|
||||
rm -f "/etc/$WEB_SYSTEM/$confd/domains/$confname"
|
||||
if [ "$WEB_SYSTEM" = "nginx" ]; then
|
||||
rm -f "/usr/local/hestia/nginx-system/etc/$WEB_SYSTEM/$confd/domains/$confname"
|
||||
else
|
||||
rm -f "/etc/$WEB_SYSTEM/$confd/domains/$confname"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$PROXY_SYSTEM" ] && [ "$PROXY_SYSTEM" = "$1" ]; then
|
||||
rm -f "/etc/$PROXY_SYSTEM/$confd/domains/$confname"
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
rm -f "/usr/local/hestia/nginx-system/etc/$PROXY_SYSTEM/$confd/domains/$confname"
|
||||
else
|
||||
rm -f "/etc/$PROXY_SYSTEM/$confd/domains/$confname"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -850,8 +938,16 @@ del_mail_ssl_config() {
|
||||
|
||||
# Remove SSL vhost configuration
|
||||
rm -f $HOMEDIR/$user/conf/mail/$domain/*.*ssl.conf
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
if [ "$WEB_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
|
||||
# Remove SSL certificates
|
||||
rm -f $HOMEDIR/$user/conf/mail/$domain/ssl/*
|
||||
@@ -939,13 +1035,23 @@ add_webmail_config() {
|
||||
if [[ "$2" =~ stpl$ ]]; then
|
||||
if [ -n "$WEB_SYSTEM" ]; then
|
||||
forcessl="$HOMEDIR/$user/conf/mail/$domain/$WEB_SYSTEM.forcessl.conf"
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
fi
|
||||
if [ -n "$PROXY_SYSTEM" ]; then
|
||||
forcessl="$HOMEDIR/$user/conf/mail/$domain/$PROXY_SYSTEM.forcessl.conf"
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
# Add rewrite rules to force HTTPS/SSL connections
|
||||
@@ -960,12 +1066,22 @@ add_webmail_config() {
|
||||
find $HOMEDIR/$user/conf/mail/ -maxdepth 1 -type f \( -name "$domain.*" -o -name "ssl.$domain.*" -o -name "*nginx.$domain.*" \) -exec rm {} \;
|
||||
else
|
||||
if [ -n "$WEB_SYSTEM" ]; then
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
fi
|
||||
fi
|
||||
if [ -n "$PROXY_SYSTEM" ]; then
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
if [ "$1" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /usr/local/hestia/nginx-system/etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
else
|
||||
rm -f /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
ln -s $conf /etc/$1/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
fi
|
||||
fi
|
||||
# Clear old configurations
|
||||
find $HOMEDIR/$user/conf/mail/ -maxdepth 1 -type f \( -name "$domain.*" \) -exec rm {} \;
|
||||
@@ -986,12 +1102,20 @@ del_webmail_config() {
|
||||
fi
|
||||
if [ -n "$WEB_SYSTEM" ]; then
|
||||
rm -f $HOMEDIR/$user/$confd/mail/$domain/$WEB_SYSTEM.conf
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
if [ "$WEB_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
else
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$PROXY_SYSTEM" ]; then
|
||||
rm -f $HOMEDIR/$user/conf/mail/$domain/$PROXY_SYSTEM.*conf
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
else
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.conf
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1009,12 +1133,20 @@ del_webmail_ssl_config() {
|
||||
fi
|
||||
if [ -n "$WEB_SYSTEM" ]; then
|
||||
rm -f $HOMEDIR/$user/conf/mail/$domain/$WEB_SYSTEM.*ssl.conf
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
if [ "$WEB_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$WEB_SYSTEM/$confd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$PROXY_SYSTEM" ]; then
|
||||
rm -f $HOMEDIR/$user/conf/mail/$domain/$PROXY_SYSTEM.*ssl.conf
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
if [ "$PROXY_SYSTEM" = "nginx" ]; then
|
||||
rm -f /usr/local/hestia/nginx-system/etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
else
|
||||
rm -f /etc/$PROXY_SYSTEM/$pconfd/domains/$WEBMAIL_ALIAS.$domain.ssl.conf
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1120,14 +1252,14 @@ is_base_domain_owner() {
|
||||
#----------------------------------------------------------#
|
||||
|
||||
process_http2_directive() {
|
||||
if [ -e /etc/nginx/conf.d/http2-directive.conf ]; then
|
||||
if [ -e /usr/local/hestia/nginx-system/etc/nginx/conf.d/http2-directive.conf ]; then
|
||||
while IFS= read -r old_param; do
|
||||
new_param="$(echo "$old_param" | sed 's/\shttp2//')"
|
||||
sed -i "s/$old_param/$new_param/" "$1"
|
||||
done < <(grep -E "listen.*(\bssl\b(\s|.+){1,}\bhttp2\b|\bhttp2\b(\s|.+){1,}\bssl\b).*;" "$1")
|
||||
else
|
||||
if version_ge "$(nginx -v 2>&1 | cut -d'/' -f2)" "1.25.1"; then
|
||||
echo "http2 on;" > /etc/nginx/conf.d/http2-directive.conf
|
||||
if version_ge "$(/usr/local/hestia/nginx-system/sbin/nginx -v 2>&1 | cut -d'/' -f2)" "1.25.1"; then
|
||||
echo "http2 on;" > /usr/local/hestia/nginx-system/etc/nginx/conf.d/http2-directive.conf
|
||||
|
||||
while IFS= read -r old_param; do
|
||||
new_param="$(echo "$old_param" | sed 's/\shttp2//')"
|
||||
|
||||
98
func/main.sh
@@ -1449,6 +1449,56 @@ check_backup_conditions() {
|
||||
done
|
||||
}
|
||||
|
||||
fn_get_link_name(){
|
||||
str_result=""
|
||||
ext_name=$1
|
||||
pattern=("01-ioncube.ini" "10-opcache.ini" "20-bcmath.ini" "20-bz2.ini" "20-calendar.ini" "20-ctype.ini" "20-curl.ini" "20-dba.ini" "20-dom.ini" "20-enchant.ini" "20-exif.ini" "20-ffi.ini" "20-fileinfo.ini" "20-ftp.ini" "20-gd.ini" "20-gettext.ini" "20-gmp.ini" "20-iconv.ini" "20-imap.ini" "20-intl.ini" "20-ldap.ini" "20-mbstring.ini" "20-mysqlnd.ini" "20-odbc.ini" "20-pdo.ini" "20-phar.ini" "20-posix.ini" "20-pspell.ini" "20-shmop.ini" "20-simplexml.ini" "20-sockets.ini" "20-sqlite3.ini" "20-sysvmsg.ini" "20-sysvsem.ini" "20-sysvshm.ini" "20-tokenizer.ini" "20-xml.ini" "20-xmlwriter.ini" "20-xsl.ini" "30-mysqli.ini" "30-pdo_dblib.ini" "30-pdo_firebird.ini" "30-pdo_mysql.ini" "30-pdo_odbc.ini" "30-pdo_sqlite.ini" "30-xmlreader.ini" "30-zip.ini" "40-apcu.ini" "40-ast.ini" "40-bolt.ini" "40-brotli.ini" "40-geos.ini" "40-imagick.ini" "40-libvirt-php.ini" "40-lz4.ini" "40-pdlib.ini")
|
||||
check="^[0-9]+-${ext_name}.ini"
|
||||
for str in ${pattern[@]}; do
|
||||
if [[ $str =~ $check ]]; then
|
||||
str_result="$str"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ -z "$str_result" ]; then
|
||||
echo "50-${ext_name}.ini"
|
||||
else
|
||||
echo "$str_result"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
fn_enable_local_php_extension(){
|
||||
vers=$1
|
||||
ext_name=$2
|
||||
ext_nm=$(fn_get_link_name "$ext_name")
|
||||
if [ -e "/opt/brepo/php${vers}/etc/php.d/" ]; then
|
||||
if [ ! -e "/opt/brepo/php${vers}/etc/php.d/${ext_nm}" -a -e "/opt/brepo/php${vers}/etc/mod-installed/${ext_name}.ini" ]; then
|
||||
pushd "/opt/brepo/php${vers}/etc/php.d/"
|
||||
ln -s ../mod-installed/${ext_name}.ini /opt/brepo/php${vers}/etc/php.d/${ext_nm}
|
||||
popd
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
fn_disable_local_php_extension(){
|
||||
vers=$1
|
||||
ext_name=$2
|
||||
ext_nm=$(fn_get_link_name "$ext_name")
|
||||
if [ -e "/opt/brepo/php${vers}/etc/php.d/" ]; then
|
||||
if [ -e "/opt/brepo/php${vers}/etc/php.d/${ext_nm}" ]; then
|
||||
rm -f "/opt/brepo/php${vers}/etc/php.d/${ext_nm}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
fn_enable_mod_php(){
|
||||
vers=$1
|
||||
if [ -e "/etc/httpd/conf.d.prep/php${vers}.conf" ]; then
|
||||
ln -s /etc/httpd/conf.d.prep/php${vers}.conf /etc/httpd/conf.h.d/mod_php${vers}.conf
|
||||
fi
|
||||
}
|
||||
|
||||
# Define download function
|
||||
download_file() {
|
||||
local url=$1
|
||||
@@ -1511,9 +1561,16 @@ multiphp_count() {
|
||||
multiphp_versions() {
|
||||
local -a php_versions_list
|
||||
local php_ver
|
||||
local php_type_internal=$(cat "$HESTIA/conf/hestia.conf" | grep "LOCAL_PHP" | grep "yes")
|
||||
local pool_internal=""
|
||||
if [ "$(multiphp_count)" -gt 0 ]; then
|
||||
for php_ver in $($BIN/v-list-sys-php plain); do
|
||||
[ ! -d "/etc/php/$php_ver/fpm/pool.d/" ] && continue
|
||||
if [ -n "$php_type_internal" ]; then
|
||||
pool_internal="/opt/brepo/php$php_ver/etc/php-fpm.d"
|
||||
else
|
||||
pool_internal="/etc/opt/remi/php$php_ver/php-fpm.d"
|
||||
fi
|
||||
[ ! -d "$pool_internal" ] && continue
|
||||
php_versions_list+=($php_ver)
|
||||
done
|
||||
echo "${php_versions_list[@]}"
|
||||
@@ -1522,11 +1579,19 @@ multiphp_versions() {
|
||||
|
||||
multiphp_default_version() {
|
||||
# Get system wide default php version (set by update-alternatives)
|
||||
local sys_phpversion=$(php -r "echo substr(phpversion(),0,3);")
|
||||
local sys_phpversion_l=$(php -r "echo substr(phpversion(),0,3);")
|
||||
local sys_phpversion="${sys_phpversion_l//./}"
|
||||
local php_type_internal=$(cat "$HESTIA/conf/hestia.conf" | grep "LOCAL_PHP" | grep "yes")
|
||||
local pool_internal=""
|
||||
if [ -n "$php_type_internal" ]; then
|
||||
pool_internal="/opt/brepo/php$sys_phpversion/etc/php-fpm.d"
|
||||
else
|
||||
pool_internal="/etc/opt/remi/php$sys_phpversion/php-fpm.d"
|
||||
fi
|
||||
|
||||
# Check if the system php also has php-fpm enabled, otherwise return
|
||||
# the most recent php version which does have it installed.
|
||||
if [ ! -d "/etc/php/$sys_phpversion/fpm/pool.d/" ]; then
|
||||
if [ ! -d "$pool_internal" ]; then
|
||||
local all_versions="$(multiphp_versions)"
|
||||
if [ -n "$all_versions" ]; then
|
||||
sys_phpversion="${all_versions##*\ }"
|
||||
@@ -1730,4 +1795,31 @@ get_conf_d_name(){
|
||||
else
|
||||
echo "conf.d"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get default php version
|
||||
# hestia.conf should be enabled before function
|
||||
get_system_default_php(){
|
||||
declare -a local_versions
|
||||
if [ "$LOCAL_PHP" == "yes" ]; then
|
||||
for version in /opt/brepo/php*/etc/php-fpm.d/www.conf; do
|
||||
local_ver=$(echo "$version" | awk -F"/" '{ print $4 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
if [ "$local_ver" != "php*" ]; then
|
||||
local_versions+=("$local_ver")
|
||||
fi
|
||||
done
|
||||
else
|
||||
for version in /etc/opt/remi/php*/php-fpm.d/www.conf; do
|
||||
local_ver=$(echo "$version" | awk -F"/" '{ print $5 }' | sed "s/php\([[:digit:]]\+\)/\1/g")
|
||||
if [ "$local_ver" != "php*" ]; then
|
||||
local_versions+=("$local_ver")
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ ${#local_versions[@]} -eq 0 ]; then
|
||||
local_php_ver="82"
|
||||
else
|
||||
local_php_ver="${local_versions[0]}"
|
||||
fi
|
||||
echo "$local_php_ver"
|
||||
}
|
||||
@@ -56,11 +56,12 @@ upgrade_health_check() {
|
||||
|
||||
upgrade_welcome_message() {
|
||||
echo
|
||||
echo ' _ _ _ _ ____ ____ '
|
||||
echo ' | | | | ___ ___| |_(_) __ _ / ___| _ \ '
|
||||
echo ' | |_| |/ _ \/ __| __| |/ _` | | | |_) | '
|
||||
echo ' | _ | __/\__ \ |_| | (_| | |___| __/ '
|
||||
echo ' |_| |_|\___||___/\__|_|\__,_|\____|_| '
|
||||
echo ' _ _ _ _ ____ ____ '
|
||||
echo ' | | | | ___ ___| |_(_) __ _ / ___| _ \ _ _ . . '
|
||||
echo ' | |_| |/ _ \/ __| __| |/ _` | | | |_) | | \| \|\/| '
|
||||
echo ' | _ | __/\__ \ |_| | (_| | |___| __/ |_/|_/| | '
|
||||
echo ' |_| |_|\___||___/\__|_|\__,_|\____|_| | \| | | '
|
||||
echo " "
|
||||
echo " "
|
||||
echo " Hestia Control Panel Software Update "
|
||||
echo " Version: ${DISPLAY_VER}"
|
||||
@@ -118,11 +119,6 @@ upgrade_complete_message() {
|
||||
echo "============================================================================="
|
||||
echo
|
||||
echo "Upgrade complete! If you encounter any issues or find a bug, "
|
||||
echo "please take a moment to report it to us on GitHub at the URL below: "
|
||||
echo "https://github.com/hestiacp/hestiacp/issues "
|
||||
echo
|
||||
echo "Read the release notes to learn about new fixes and features: "
|
||||
echo "https://github.com/hestiacp/hestiacp/blob/release/CHANGELOG.md "
|
||||
echo
|
||||
echo "We hope that you enjoy using this version of Hestia Control Panel, "
|
||||
echo "have a wonderful day! "
|
||||
@@ -130,13 +126,6 @@ upgrade_complete_message() {
|
||||
echo "Sincerely, "
|
||||
echo "The Hestia Control Panel development team "
|
||||
echo
|
||||
echo "Web: https://www.hestiacp.com/ "
|
||||
echo "Docs: https://docs.hestiacp.com/ "
|
||||
echo "Forum: https://forum.hestiacp.com/ "
|
||||
echo "GitHub: https://github.com/hestiacp/hestiacp/ "
|
||||
echo
|
||||
echo "Help support the Hestia Control Panel project by donating via PayPal: "
|
||||
echo "https://www.hestiacp.com/donate "
|
||||
echo
|
||||
echo "Made with love & pride by the open-source community around the world. "
|
||||
echo
|
||||
@@ -148,8 +137,6 @@ upgrade_complete_message_log() {
|
||||
echo
|
||||
echo "============================================================================="
|
||||
echo "UPGRADE COMPLETE. "
|
||||
echo "Please report any issues on GitHub: "
|
||||
echo "https://github.com/hestiacp/hestiacp/issues "
|
||||
echo "============================================================================="
|
||||
echo
|
||||
$BIN/v-log-action "system" "Info" "Updates" "Update installed (Version: $new_version)."
|
||||
@@ -219,17 +206,6 @@ upgrade_send_notification_to_email() {
|
||||
echo "" >> $message_tmp_file
|
||||
fi
|
||||
|
||||
echo "What's new: https://github.com/hestiacp/hestiacp/blob/$RELEASE_BRANCH/CHANGELOG.md" >> $message_tmp_file
|
||||
echo >> $message_tmp_file
|
||||
echo "What to do if you run into issues:" >> $message_tmp_file
|
||||
echo "- Check our forums for possible solutions: https://forum.hestiacp.com" >> $message_tmp_file
|
||||
echo "- File an issue report on GitHub: https://github.com/hestiacp/hestiacp/issues" >> $message_tmp_file
|
||||
echo "" >> $message_tmp_file
|
||||
echo "Help support the Hestia Control Panel project by donating via PayPal: https://www.hestiacp.com/donate" >> $message_tmp_file
|
||||
echo "===================================================" >> $message_tmp_file
|
||||
echo "Have a wonderful day," >> $message_tmp_file
|
||||
echo "The Hestia Control Panel development team" >> $message_tmp_file
|
||||
|
||||
# Read back message from file and pass through to sendmail
|
||||
cat $message_tmp_file | $send_mail -s "Update Installed - v${new_version}" $admin_email
|
||||
rm -f $message_tmp_file
|
||||
@@ -560,7 +536,7 @@ upgrade_cloudflare_ip() {
|
||||
cf_ips="$(curl -fsLm5 --retry 2 https://api.cloudflare.com/client/v4/ips)"
|
||||
|
||||
if [ -n "$cf_ips" ] && [ "$(echo "$cf_ips" | jq -r '.success//""')" = "true" ]; then
|
||||
cf_inc="/etc/nginx/conf.d/cloudflare.inc"
|
||||
cf_inc="/usr/local/hestia/nginx-system/etc/nginx/conf.d/cloudflare.inc"
|
||||
|
||||
echo "[ * ] Updating Cloudflare IP Ranges for NGINX..."
|
||||
echo "# Cloudflare IP Ranges" > $cf_inc
|
||||
|
||||
2
func_ruby/.bundle/config
Normal file
@@ -0,0 +1,2 @@
|
||||
---
|
||||
BUNDLE_PATH: "gems"
|
||||
7
func_ruby/Gemfile
Normal file
@@ -0,0 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem "envbash"
|
||||
gem "interface"
|
||||
gem "shell"
|
||||
22
func_ruby/Gemfile.lock
Normal file
@@ -0,0 +1,22 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
e2mmap (0.1.0)
|
||||
envbash (1.0.1)
|
||||
interface (1.0.5)
|
||||
shell (0.8.1)
|
||||
e2mmap
|
||||
sync
|
||||
sync (0.5.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
envbash
|
||||
interface
|
||||
shell
|
||||
|
||||
BUNDLED WITH
|
||||
2.5.16
|
||||
630
func_ruby/HestiaBunkerWebApi.rb
Normal file
@@ -0,0 +1,630 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
require 'net/http'
|
||||
require 'uri'
|
||||
require 'openssl'
|
||||
|
||||
class BunkerWebApiError < StandardError; end
|
||||
class HestiaBunkerWebApi
|
||||
# Override puts to accumulate logs into @extra_info
|
||||
def puts(*args)
|
||||
@extra_info ||= ""
|
||||
@extra_info << args.join("\n") << "\n"
|
||||
end
|
||||
|
||||
# Accessor for @extra_info
|
||||
def extra_info
|
||||
@extra_info || ""
|
||||
end
|
||||
end
|
||||
|
||||
# Hook to wrap methods of HestiaBunkerWebApi to reset @extra_info at start
|
||||
class Module
|
||||
alias_method :orig_method_added, :method_added
|
||||
def method_added(name)
|
||||
orig_method_added(name)
|
||||
# Skip wrapping for the overridden puts method
|
||||
return if name == :puts
|
||||
if self.name == 'HestiaBunkerWebApi'
|
||||
@__wrapping ||= false
|
||||
return if @__wrapping
|
||||
@__wrapping = true
|
||||
original = instance_method(name)
|
||||
define_method(name) do |*args, &block|
|
||||
@extra_info = ""
|
||||
original.bind(self).call(*args, &block)
|
||||
end
|
||||
@__wrapping = false
|
||||
end
|
||||
end
|
||||
end
|
||||
class HestiaBunkerWebApi
|
||||
# Retrieve API username and password from /etc/bunkerweb/api.env if available
|
||||
def get_api_user_password
|
||||
env_path = "/etc/bunkerweb/api.env"
|
||||
return nil unless File.file?(env_path)
|
||||
|
||||
username = nil
|
||||
password = nil
|
||||
|
||||
File.foreach(env_path) do |line|
|
||||
line.strip!
|
||||
next if line.empty? || line.start_with?('#')
|
||||
key, value = line.split('=', 2)
|
||||
next unless key && value
|
||||
case key
|
||||
when 'API_USERNAME'
|
||||
username = value
|
||||
when 'API_PASSWORD'
|
||||
password = value
|
||||
end
|
||||
end
|
||||
|
||||
if username && password
|
||||
[username, password]
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(api_url, username = nil, password = nil)
|
||||
@api_base = api_url
|
||||
if username.nil?
|
||||
result = get_api_user_password
|
||||
if result.nil?
|
||||
raise BunkerWebApiError.new("Authentication error: no username or password")
|
||||
else
|
||||
@username = result[0]
|
||||
@password = result[1]
|
||||
end
|
||||
else
|
||||
@username = username
|
||||
@password = password
|
||||
end
|
||||
@token = nil
|
||||
@extra_info = ""
|
||||
|
||||
# Authenticate and get token
|
||||
authenticate!
|
||||
|
||||
puts "[INFO] Successfully authenticated with BunkerWeb API"
|
||||
end
|
||||
|
||||
def authenticate!
|
||||
uri = URI(@api_base)
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = (uri.scheme == "https")
|
||||
|
||||
# Try both Basic Auth and JSON body with credentials
|
||||
request = Net::HTTP::Post.new("/auth")
|
||||
request.content_type = "application/json"
|
||||
request.body = { username: @username, password: @password }.to_json
|
||||
|
||||
response = http.request(request)
|
||||
|
||||
if response.code != '200'
|
||||
raise BunkerWebApiError.new("Authentication failed: #{response.code} - #{response.message}")
|
||||
end
|
||||
|
||||
body = JSON.parse(response.body)
|
||||
|
||||
unless body['token']
|
||||
raise BunkerWebApiError.new("Authentication succeeded but no token received")
|
||||
end
|
||||
|
||||
@token = body['token']
|
||||
rescue => e
|
||||
raise BunkerWebApiError.new("Authentication error: #{e.message}")
|
||||
end
|
||||
|
||||
def api_call(method, path, headers = {}, body = nil)
|
||||
uri = URI(@api_base + path)
|
||||
http = Net::HTTP.new(uri.host, uri.port)
|
||||
http.use_ssl = (uri.scheme == "https")
|
||||
|
||||
request = case method
|
||||
when "GET"
|
||||
Net::HTTP::Get.new(uri.path)
|
||||
when "POST"
|
||||
req = Net::HTTP::Post.new(uri.path)
|
||||
req.body = body if body
|
||||
req
|
||||
when "PATCH"
|
||||
req = Net::HTTP::Patch.new(uri.path)
|
||||
req.body = body if body
|
||||
req
|
||||
when "DELETE"
|
||||
Net::HTTP::Delete.new(uri.path)
|
||||
else
|
||||
raise BunkerWebApiError.new("Unsupported HTTP method: #{method}")
|
||||
end
|
||||
|
||||
# Add Authorization header with token for most operations (except /auth)
|
||||
unless path == "/auth"
|
||||
headers["Authorization"] = "Bearer #{@token}" if @token
|
||||
end
|
||||
|
||||
# Add Content-Type if not already set and we have a body
|
||||
if body && !headers.key?("Content-Type")
|
||||
headers["Content-Type"] = "application/json"
|
||||
end
|
||||
|
||||
headers.each { |k, v| request[k] = v }
|
||||
|
||||
response = http.request(request)
|
||||
parsed_body = begin
|
||||
JSON.parse(response.body)
|
||||
rescue => e
|
||||
nil
|
||||
end
|
||||
|
||||
{ status: response.code.to_i, body: parsed_body || {}, raw_body: response.body }
|
||||
rescue => e
|
||||
raise BunkerWebApiError.new("API call to #{path} failed: #{e.message}")
|
||||
end
|
||||
|
||||
# === Service Operations ===
|
||||
|
||||
def create_service(service_name, options = {})
|
||||
@extra_info = ""
|
||||
# Create a new service with the given configuration.
|
||||
#
|
||||
# Args:
|
||||
# service_name (String): The domain name for this service (server_name)
|
||||
# options (Hash): Service configuration including:
|
||||
# - USE_TEMPLATE (default: "high")
|
||||
# - USE_SSL (default: "no") - if not "no", you need CERTIFICATE and KEY paths
|
||||
# - REVERSE_PROXY_HOST (optional)
|
||||
# - REVERSE_PROXY_URL (optional, default: "~ ^/(.*)$")
|
||||
# - Additional options like:
|
||||
# - USE_REVERSE_PROXY (default: "yes" if REVERSE_PROXY_HOST is set)
|
||||
# - USE_REAL_IP, REAL_IP_FROM
|
||||
# - USE_MODSECURITY, USE_ANTIBOT
|
||||
# - LISTEN_HTTP_PORT, LISTEN_HTTPS_PORT
|
||||
# - CERTIFICATE_FILE_PATH (if USE_SSL != "no")
|
||||
# - KEY_FILE_PATH (if USE_SSL != "no")
|
||||
# Returns: Hash with creation response
|
||||
|
||||
variables = {
|
||||
"USE_TEMPLATE" => options[:use_template] || "high",
|
||||
"USE_REVERSE_PROXY" => options[:reverse_proxy_host].nil? ? "no" : "yes",
|
||||
"LIMIT_REQ_RATE" => options[:limit_req_rate] || "10r/s",
|
||||
}
|
||||
|
||||
# SSL configuration - only if USE_SSL != "no"
|
||||
ssl_enabled = options[:ssl] && options[:ssl] != "no"
|
||||
variables["USE_CUSTOM_SSL"] = ssl_enabled ? "yes" : "no"
|
||||
|
||||
if ssl_enabled
|
||||
unless options[:certificate_path] && options[:key_path]
|
||||
raise BunkerWebApiError.new("Certificate and Key paths are required when USE_SSL is enabled")
|
||||
end
|
||||
|
||||
# Set certificate paths in variables
|
||||
variables["CUSTOM_SSL_CERT"] = options[:certificate_path]
|
||||
variables["CUSTOM_SSL_KEY"] = options[:key_path]
|
||||
|
||||
variables["LISTEN_HTTPS_PORT"] = (options[:https_port] || "443").to_s
|
||||
variables["USE_REVERSE_PROXY_SSL"] = options[:reverse_proxy_ssl] || "yes"
|
||||
else
|
||||
# No SSL - HTTP only
|
||||
# API expects string "null", not nil/JSON null
|
||||
variables["LISTEN_HTTPS_PORT"] = "null"
|
||||
variables["LISTEN_HTTP_PORT"] = (options[:http_port] || "80").to_s
|
||||
end
|
||||
|
||||
# Reverse proxy configuration if specified
|
||||
if options[:reverse_proxy_host]
|
||||
variables["REVERSE_PROXY_HOST"] = options[:reverse_proxy_host]
|
||||
variables["REVERSE_PROXY_URL"] = options[:reverse_proxy_url] || "~ ^(?!/challenge)(.*)$"
|
||||
|
||||
# Real IP settings for reverse proxy
|
||||
unless options[:real_ip_from].nil?
|
||||
variables["USE_REAL_IP"] = "yes"
|
||||
variables["REAL_IP_FROM"] = options[:real_ip_from]
|
||||
end
|
||||
|
||||
# Additional security settings from High template
|
||||
variables["USE_MODSECURITY"] = options[:use_modsecurity] || "yes"
|
||||
variables["USE_ANTIBOT"] = options[:anti_bot] || "captcha"
|
||||
end
|
||||
|
||||
variables["ANTIBOT_IGNORE_URI"] = options[:anti_bot_ignore_uri] || "^/\.well-known/acme-challenge/.+$"
|
||||
variables["LETS_ENCRYPT_PASSTHROUGH"] = options[:lets_encrypt_passthrough] || "yes"
|
||||
|
||||
|
||||
service_body = {
|
||||
server_name: service_name,
|
||||
is_draft: false,
|
||||
variables: variables
|
||||
}
|
||||
|
||||
response = api_call("POST", "/services", {}, JSON.generate(service_body))
|
||||
|
||||
# Accept both 201 (Created) and 200 (OK) for successful creation
|
||||
if [201, 200].include?(response[:status])
|
||||
puts "[INFO] Service '#{service_name}' created successfully"
|
||||
elsif response[:status] == 409
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' already exists")
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to create service: status=#{response[:status]}, body=#{response[:raw_body]}")
|
||||
end
|
||||
|
||||
return response[:body] || {}
|
||||
end
|
||||
|
||||
def update_service_ssl(service_name, certificate_path, key_path, https_port = nil)
|
||||
# Update or change the SSL certificate path for an existing service.
|
||||
#
|
||||
# Args:
|
||||
# service_name (String): Name of the service to update
|
||||
# certificate_path (String): Path to the SSL certificate file
|
||||
# key_path (String): Path to the SSL private key file
|
||||
# https_port (Integer, optional): HTTPS port (default 443)
|
||||
# Returns: Hash with update response
|
||||
|
||||
@extra_info = ""
|
||||
|
||||
# First get current service configuration to preserve existing settings
|
||||
get_service_response = api_call("GET", "/services/#{service_name}", {})
|
||||
|
||||
if get_service_response[:status] != 200
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' not found")
|
||||
end
|
||||
|
||||
# Extract variables from config - API stores them in 'config' not 'variables'
|
||||
# Each variable is a hash with 'value' as the actual setting value
|
||||
current_vars = {}
|
||||
if get_service_response[:body]["config"]
|
||||
get_service_response[:body]["config"].each do |key, value_hash|
|
||||
if value_hash.is_a?(Hash) && value_hash.key?("value")
|
||||
current_vars[key] = value_hash["value"]
|
||||
else
|
||||
current_vars[key] = value_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Update SSL settings
|
||||
updated_vars = {
|
||||
"USE_CUSTOM_SSL" => "yes",
|
||||
"CUSTOM_SSL_CERT" => certificate_path,
|
||||
"CUSTOM_SSL_KEY" => key_path,
|
||||
"LISTEN_HTTPS_PORT" => (https_port || "443").to_s,
|
||||
"USE_REVERSE_PROXY_SSL" => "yes"
|
||||
}
|
||||
|
||||
# Merge with existing variables (keep non-SSL settings)
|
||||
final_vars = current_vars.merge(updated_vars)
|
||||
|
||||
service_body = {
|
||||
server_name: nil, # Not changing name
|
||||
is_draft: false, # Keep as online
|
||||
variables: final_vars
|
||||
}
|
||||
|
||||
response = api_call("PATCH", "/services/#{service_name}", {}, JSON.generate(service_body))
|
||||
|
||||
if response[:status] == 200
|
||||
puts "[INFO] SSL configuration updated for service '#{service_name}'"
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to update SSL configuration: status=#{response[:status]}, body=#{response[:raw_body]}")
|
||||
end
|
||||
|
||||
return response[:body] || {}
|
||||
end
|
||||
|
||||
|
||||
def set_alias(service_name, list_aliases)
|
||||
@extra_info = ""
|
||||
|
||||
# First get current service configuration to preserve existing settings
|
||||
get_service_response = api_call("GET", "/services/#{service_name}", {})
|
||||
|
||||
if get_service_response[:status] != 200
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' not found")
|
||||
end
|
||||
|
||||
# Save the entire current configuration (except server_name which will be replaced)
|
||||
current_config = get_service_response[:body]
|
||||
|
||||
# Extract variables from config - API stores them in 'config' not 'variables'
|
||||
# Each variable is a hash with 'value' as the actual setting value
|
||||
current_vars = {}
|
||||
if current_config["config"]
|
||||
current_config["config"].each do |key, value_hash|
|
||||
if key != "SERVER_NAME"
|
||||
if value_hash.is_a?(Hash) && value_hash.key?("value")
|
||||
current_vars[key] = value_hash["value"]
|
||||
else
|
||||
current_vars[key] = value_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Clean the list_aliases string according to the rules
|
||||
cleaned_aliases = list_aliases.to_s
|
||||
|
||||
# Replace commas (with or without space) with a single space
|
||||
cleaned_aliases.gsub!(/,\s?/, ' ')
|
||||
|
||||
# Replace multiple spaces with a single space
|
||||
cleaned_aliases.gsub!(/\s{2,}/, ' ')
|
||||
|
||||
# Strip leading/trailing whitespace
|
||||
cleaned_aliases.strip!
|
||||
|
||||
# Ensure the main service name appears first in the alias list
|
||||
aliases_array = cleaned_aliases.split(' ')
|
||||
if aliases_array.include?(service_name)
|
||||
aliases_array.delete(service_name)
|
||||
end
|
||||
# Rebuild cleaned string
|
||||
cleaned_aliases = aliases_array.join(' ')
|
||||
current_vars["SERVER_NAME"]=cleaned_aliases
|
||||
|
||||
# Step 1: Delete the old service
|
||||
delete_response = api_call("DELETE", "/services/#{service_name}")
|
||||
if delete_response[:status] != 200 && delete_response[:status] != 204
|
||||
raise BunkerWebApiError.new("Failed to delete service '#{service_name}': status=#{delete_response[:status]}")
|
||||
end
|
||||
puts "[INFO] Service '#{service_name}' deleted"
|
||||
|
||||
# Step 2: Create a new service with the cleaned alias list as server_name
|
||||
# and preserve all existing configuration variables
|
||||
service_body = {
|
||||
server_name: service_name, # Use the full alias list including service_name first
|
||||
is_draft: current_config["is_draft"] || false,
|
||||
variables: current_vars # Preserve all existing variables from the original service
|
||||
}
|
||||
|
||||
post_response = api_call("POST", "/services", {}, JSON.generate(service_body))
|
||||
|
||||
if post_response[:status] == 200 || post_response[:status] == 201
|
||||
puts "[INFO] Service recreated successfully with aliases: #{cleaned_aliases}"
|
||||
elsif post_response[:status] == 409
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' already exists")
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to create service: status=#{post_response[:status]}, body=#{post_response[:raw_body]}")
|
||||
end
|
||||
|
||||
return post_response || {}
|
||||
end
|
||||
|
||||
|
||||
def delete_service_ssl(service_name)
|
||||
|
||||
@extra_info = ""
|
||||
|
||||
# First get current service configuration to preserve existing settings
|
||||
get_service_response = api_call("GET", "/services/#{service_name}", {})
|
||||
|
||||
if get_service_response[:status] != 200
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' not found")
|
||||
end
|
||||
|
||||
# Extract variables from config - API stores them in 'config' not 'variables'
|
||||
# Each variable is a hash with 'value' as the actual setting value
|
||||
current_vars = {}
|
||||
if get_service_response[:body]["config"]
|
||||
get_service_response[:body]["config"].each do |key, value_hash|
|
||||
if value_hash.is_a?(Hash) && value_hash.key?("value")
|
||||
current_vars[key] = value_hash["value"]
|
||||
else
|
||||
current_vars[key] = value_hash
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Update SSL settings
|
||||
updated_vars = {
|
||||
"USE_CUSTOM_SSL" => "no",
|
||||
"CUSTOM_SSL_CERT" => "",
|
||||
"CUSTOM_SSL_KEY" => ""
|
||||
}
|
||||
|
||||
# Merge with existing variables (keep non-SSL settings)
|
||||
final_vars = current_vars.merge(updated_vars)
|
||||
|
||||
service_body = {
|
||||
server_name: nil, # Not changing name
|
||||
is_draft: false, # Keep as online
|
||||
variables: final_vars
|
||||
}
|
||||
|
||||
response = api_call("PATCH", "/services/#{service_name}", {}, JSON.generate(service_body))
|
||||
|
||||
if response[:status] == 200
|
||||
puts "[INFO] SSL configuration updated for service '#{service_name}'"
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to update SSL configuration: status=#{response[:status]}, body=#{response[:raw_body]}")
|
||||
end
|
||||
|
||||
return response[:body] || {}
|
||||
end
|
||||
|
||||
def delete_service(service_name)
|
||||
# Delete a service by its name.
|
||||
#
|
||||
# Args:
|
||||
# service_name (String): Name of the service to delete
|
||||
# Returns: Hash with deletion response
|
||||
|
||||
@extra_info = ""
|
||||
# Verify service exists first
|
||||
get_response = api_call("GET", "/services/#{service_name}", {})
|
||||
|
||||
if get_response[:status] != 200
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' not found")
|
||||
end
|
||||
|
||||
response = api_call("DELETE", "/services/#{service_name}")
|
||||
|
||||
if response[:status] == 200 || response[:status] == 204
|
||||
puts "[INFO] Service '#{service_name}' deleted successfully"
|
||||
return response[:body] || {}
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to delete service: status=#{response[:status]}, body=#{response[:raw_body]}")
|
||||
end
|
||||
end
|
||||
|
||||
# === Additional Utility Methods ===
|
||||
|
||||
def list_services(drafts = false)
|
||||
# List all services.
|
||||
#
|
||||
# Args:
|
||||
# drafts (Boolean): Include draft services (default: false, set to true to include drafts)
|
||||
# Returns: Array of service objects
|
||||
|
||||
@extra_info = ""
|
||||
response = api_call("GET", "/services")
|
||||
|
||||
if response[:status] != 200
|
||||
raise BunkerWebApiError.new("Failed to list services: status=#{response[:status]}")
|
||||
end
|
||||
|
||||
return response[:body] || []
|
||||
end
|
||||
|
||||
def get_service(service_name)
|
||||
# Get details of a specific service.
|
||||
#
|
||||
# Args:
|
||||
# service_name (String): Name of the service to retrieve
|
||||
# Returns: Hash with service configuration
|
||||
|
||||
@extra_info = ""
|
||||
response = api_call("GET", "/services/#{service_name}")
|
||||
|
||||
if response[:status] != 200
|
||||
raise BunkerWebApiError.new("Service '#{service_name}' not found")
|
||||
end
|
||||
|
||||
return response[:body] || {}
|
||||
end
|
||||
|
||||
def reload_instance(instance_hostname = nil)
|
||||
# Reload configuration on an instance.
|
||||
#
|
||||
# Args:
|
||||
# instance_hostname (String, optional): Instance hostname to reload (if nil, reloads all instances)
|
||||
# Returns: Hash with reload response
|
||||
|
||||
@extra_info = ""
|
||||
path = if instance_hostname.nil?
|
||||
"/instances/reload"
|
||||
else
|
||||
"/instances/#{instance_hostname}/reload"
|
||||
end
|
||||
|
||||
response = api_call("POST", "#{path}?test=no")
|
||||
|
||||
if response[:status] == 200 || response[:status] == 201
|
||||
puts "[INFO] Configuration reloaded successfully"
|
||||
return response[:body] || {}
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to reload configuration: status=#{response[:status]}")
|
||||
end
|
||||
end
|
||||
|
||||
def list_instances()
|
||||
# List all registered instances.
|
||||
# Returns: Array of instance objects
|
||||
|
||||
@extra_info = ""
|
||||
response = api_call("GET", "/instances")
|
||||
|
||||
if response[:status] != 200
|
||||
raise BunkerWebApiError.new("Failed to list instances: status=#{response[:status]}")
|
||||
end
|
||||
|
||||
return response[:body] || []
|
||||
end
|
||||
|
||||
def create_instance(hostname, name = nil, port = 8888, https_port = nil)
|
||||
# Create/register a new BunkerWeb instance (worker node).
|
||||
#
|
||||
# Args:
|
||||
# hostname (String): IP address or hostname of the worker node
|
||||
# name (String, optional): Human-readable name for the instance
|
||||
# port (Integer): API port on the worker node (default 8888)
|
||||
# https_port (Integer, optional): HTTPS port
|
||||
# Returns: Hash with creation response
|
||||
|
||||
@extra_info = ""
|
||||
instance_body = {
|
||||
hostname: hostname,
|
||||
name: name || "BunkerWeb Instance",
|
||||
port: port,
|
||||
listen_https: !https_port.nil?,
|
||||
https_port: https_port,
|
||||
server_name: hostname,
|
||||
method: "api" # Using API deployment method
|
||||
}
|
||||
|
||||
response = api_call("POST", "/instances", {}, JSON.generate(instance_body))
|
||||
|
||||
if response[:status] == 201
|
||||
puts "[INFO] Instance '#{hostname}' registered successfully"
|
||||
elsif response[:status] == 409
|
||||
# Instance already exists - that's OK, we just want to use it
|
||||
puts "[INFO] Instance '#{hostname}' already exists, will be used for this service"
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to create instance: status=#{response[:status]}, body=#{response[:raw_body]}")
|
||||
end
|
||||
|
||||
return response[:body] || {}
|
||||
end
|
||||
|
||||
def delete_instance(hostname)
|
||||
"""
|
||||
Delete a registered instance.
|
||||
|
||||
Args:
|
||||
hostname (String): Hostname of the instance to delete
|
||||
"""
|
||||
|
||||
@extra_info = ""
|
||||
response = api_call("DELETE", "/instances/#{hostname}")
|
||||
|
||||
if response[:status] == 200 || response[:status] == 204
|
||||
puts "[INFO] Instance '#{hostname}' deleted successfully"
|
||||
return true
|
||||
else
|
||||
raise BunkerWebApiError.new("Failed to delete instance: status=#{response[:status]}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# === Example Usage (can be run as script) ===
|
||||
|
||||
if __FILE__ == $0
|
||||
# Example usage demonstration
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new(
|
||||
"http://127.0.0.1:8888",
|
||||
"admin",
|
||||
"your_password"
|
||||
)
|
||||
|
||||
puts ""
|
||||
puts "[INFO] Creating service 'example.my.domain'"
|
||||
result = api.create_service("example.my.domain", {
|
||||
reverse_proxy_host: "http://192.168.3.51:8078",
|
||||
ssl: "no",
|
||||
use_template: "high"
|
||||
})
|
||||
|
||||
puts ""
|
||||
puts "[INFO] Listing services:"
|
||||
services = api.list_services()
|
||||
services.each { |s| puts "- #{s['server_name']}" }
|
||||
|
||||
rescue BunkerWebApiError => e
|
||||
puts "[ERROR] #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
467
func_ruby/docs/BunkerWebApiDoc.md
Normal file
@@ -0,0 +1,467 @@
|
||||
# HestiaBunkerWebApi - Ruby класс для работы с BunkerWeb API
|
||||
|
||||
## Описание
|
||||
|
||||
Класс `HestiaBunkerWebApi` предоставляет простой интерфейс для управления сервисами BunkerWeb через REST API. Класс реализует:
|
||||
|
||||
- **Аутентификацию** с получением токена
|
||||
- **Управление сервисами** (создание, обновление, удаление)
|
||||
- **Управление SSL сертификатами**
|
||||
- **Управление instances** (worker nodes)
|
||||
- **Полное исключение ошибок** при любых проблемах
|
||||
|
||||
## Установка и импорт
|
||||
|
||||
```bash
|
||||
# Ruby 3.3+ рекомендуется
|
||||
ruby --version
|
||||
# ruby 3.3.x or later
|
||||
|
||||
# Класс использует стандартные библиотеки Ruby:
|
||||
# - json (для JSON парсинга)
|
||||
# - net/http (для HTTP запросов)
|
||||
# - uri (для URL парсинга)
|
||||
```
|
||||
|
||||
## Использование класса
|
||||
|
||||
### Базовое использование
|
||||
|
||||
```ruby
|
||||
require_relative "HestiaBunkerWebApi.rb"
|
||||
|
||||
# Создаём экземпляр API с аутентификацией
|
||||
api = HestiaBunkerWebApi.new(
|
||||
"http://127.0.0.1:8888", # URL API (можно https://)
|
||||
"admin", # username
|
||||
"password" # password
|
||||
)
|
||||
# или
|
||||
api = HestiaBunkerWebApi.new(
|
||||
"http://127.0.0.1:8888", # URL API (можно https://)
|
||||
)
|
||||
# в этом случае пароль и логин читаются автоматически из файла /etc/bunkerweb/api.env
|
||||
|
||||
|
||||
# При создании экземпляра автоматически происходит аутентификация
|
||||
# Если ошибка - выбрасывается BunkerWebApiError с описанием проблемы
|
||||
```
|
||||
|
||||
### Обработка ошибок
|
||||
|
||||
Все ошибки наследуются от `StandardError` через класс `BunkerWebApiError`:
|
||||
|
||||
```ruby
|
||||
begin
|
||||
api.create_service("example.domain", options)
|
||||
rescue BunkerWebApiError => e
|
||||
puts "[ERROR] Ошибка API: #{e.message}"
|
||||
|
||||
# Примеры возможных ошибок:
|
||||
# - "Authentication failed: 401 - Unauthorized"
|
||||
# - "Service 'x' already exists"
|
||||
# - "Certificate and Key paths are required when USE_SSL is enabled"
|
||||
# - "Failed to create service: status=500, body={...}"
|
||||
|
||||
exit 1
|
||||
end
|
||||
```
|
||||
|
||||
## Методы класса
|
||||
|
||||
### Конструктор
|
||||
|
||||
```ruby
|
||||
HestiaBunkerWebApi.new(api_url, username, password)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `api_url` - URL BunkerWeb API в формате `http://ip:port` или `https://ip:port`
|
||||
- `username` - имя администратора для аутентификации
|
||||
- `password` - пароль для аутентификации
|
||||
|
||||
**Действие:** При создании автоматически пытается аутентифицироваться через POST /auth и сохраняет токен.
|
||||
|
||||
### Создание сервиса
|
||||
|
||||
```ruby
|
||||
api.create_service(service_name, options = {})
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `service_name` - имя домена/сервиса (например, "example.my.domain")
|
||||
- `options` - хэш с конфигурацией:
|
||||
|
||||
| Параметр | Тип | Описание | Пример |
|
||||
|----------|-----|----------|--------|
|
||||
| `ssl` | String | "yes" для SSL, "no" для HTTP | `"no"` |
|
||||
| `certificate_path` | String | Путь к SSL сертификату (если ssl="yes") | `"/etc/ssl/certs/example.crt"` |
|
||||
| `key_path` | String | Путь к приватному ключу (если ssl="yes") | `"/etc/ssl/private/example.key"` |
|
||||
| `use_template` | String | Безопасность шаблона | `"high"` (default) |
|
||||
| `reverse_proxy_host` | String | Target reverse proxy | `"http://192.168.3.51:8078"` |
|
||||
| `reverse_proxy_url` | String | URL трансформация | `"~ ^/(.*)$"` |
|
||||
| `real_ip_from` | String | CIDR trusted network для RealIP | `"192.168.3.0/24"` |
|
||||
| `use_modsecurity` | String | WAF включение | `"yes"` (default) |
|
||||
| `anti_bot` | String | Bot protection | `"captcha"` (default) |
|
||||
| `http_port` | Integer/nil | HTTP порт | `"80"` или `null` |
|
||||
| `https_port` | Integer | HTTPS порт | `443` или `null` |
|
||||
|
||||
**Пример - создание reverse proxy сервиса без SSL:**
|
||||
```ruby
|
||||
result = api.create_service("example.my.domain", {
|
||||
ssl: "no",
|
||||
reverse_proxy_host: "http://192.168.3.51:8078"
|
||||
})
|
||||
|
||||
# Генерирует variables:
|
||||
# - USE_TEMPLATE: "high"
|
||||
# - USE_SSL: "no"
|
||||
# - LISTEN_HTTPS_PORT: "null"
|
||||
# - LISTEN_HTTP_PORT: "80"
|
||||
# - USE_REVERSE_PROXY: "yes"
|
||||
# - REVERSE_PROXY_HOST: "http://192.168.3.51:8078"
|
||||
```
|
||||
|
||||
**Пример - создание сервиса с SSL + reverse proxy:**
|
||||
```ruby
|
||||
result = api.create_service("example.my.domain", {
|
||||
ssl: "yes", # Включаем SSL
|
||||
|
||||
certificate_path: "/etc/ssl/certs/example.crt", # Путь к сертификату
|
||||
key_path: "/etc/ssl/private/example.key", # Путь к ключу
|
||||
|
||||
reverse_proxy_host: "http://192.168.3.51:8078", # Reverse proxy target
|
||||
|
||||
use_template: "high",
|
||||
anti_bot: "captcha"
|
||||
})
|
||||
|
||||
# Генерирует variables:
|
||||
# - USE_TEMPLATE: "high"
|
||||
# - USE_SSL: "yes"
|
||||
# - SSL_CERTIFICATE_FILE_PATH: "/etc/ssl/certs/example.crt"
|
||||
# - SSL_KEY_FILE_PATH: "/etc/ssl/private/example.key"
|
||||
# - LISTEN_HTTPS_PORT: "443"
|
||||
# - LISTEN_HTTP_PORT: "80"
|
||||
```
|
||||
|
||||
### Обновление SSL сертификата для существующего сервиса
|
||||
|
||||
```ruby
|
||||
api.update_service_ssl(service_name, certificate_path, key_path, https_port = nil)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `service_name` - имя уже созданного сервиса
|
||||
- `certificate_path` - новый путь к SSL сертификату
|
||||
- `key_path` - новый путь к приватному ключу
|
||||
- `https_port` (optional) - HTTPS порт (default: 443)
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
api.update_service_ssl(
|
||||
"example.my.domain",
|
||||
"/etc/ssl/certs/example.crt",
|
||||
"/etc/ssl/private/example.key"
|
||||
)
|
||||
|
||||
# Обновляет существующий сервис, сохраняя reverse proxy настройки
|
||||
```
|
||||
|
||||
### Удаление сервиса
|
||||
|
||||
```ruby
|
||||
api.delete_service(service_name)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `service_name` - имя сервиса для удаления
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
api.delete_service("example.my.domain")
|
||||
# Удаляет сервис и конфигурацию
|
||||
```
|
||||
|
||||
### Получение списка всех сервисов
|
||||
|
||||
```ruby
|
||||
api.list_services(drafts = false)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `drafts` (optional) - включать draft сервисы (default: false)
|
||||
|
||||
**Возвращает:** Array of service objects
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
services = api.list_services()
|
||||
services.each { |s| puts "- #{s['server_name']}" }
|
||||
```
|
||||
|
||||
### Получение деталей конкретного сервиса
|
||||
|
||||
```ruby
|
||||
api.get_service(service_name)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `service_name` - имя сервиса для получения деталей
|
||||
|
||||
**Возвращает:** Hash with service configuration (variables, settings, etc.)
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
config = api.get_service("example.my.domain")
|
||||
puts config.inspect
|
||||
```
|
||||
|
||||
### Перезагрузка конфигурации на instance
|
||||
|
||||
```ruby
|
||||
api.reload_instance(instance_hostname = nil)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `instance_hostname` (optional) - hostname instance для перезагрузки (если nil, reloads all instances)
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
# Reload все instances
|
||||
api.reload_instance()
|
||||
|
||||
# Reload конкретный instance
|
||||
api.reload_instance("192.168.3.50")
|
||||
```
|
||||
|
||||
### Получение списка всех instances
|
||||
|
||||
```ruby
|
||||
api.list_instances()
|
||||
```
|
||||
|
||||
**Возвращает:** Array of instance objects (hostname, name, port, etc.)
|
||||
|
||||
### Создание/регистрация BunkerWeb instance (worker node)
|
||||
|
||||
```ruby
|
||||
api.create_instance(hostname, name = nil, port = 8888, https_port = nil)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `hostname` - IP address или hostname worker node
|
||||
- `name` (optional) - Human-readable имя instance
|
||||
- `port` - API port на worker node (default: 8888)
|
||||
- `https_port` (optional) - HTTPS port если есть
|
||||
|
||||
**Пример:**
|
||||
```ruby
|
||||
api.create_instance(
|
||||
"192.168.3.50", # IP worker node
|
||||
"BunkerWeb Worker Node", # Optional name
|
||||
8888 # API port
|
||||
)
|
||||
|
||||
# Возвращает: { status: 201/409, body: {...} }
|
||||
# Если статус 201 - instance создан
|
||||
# Если статус 409 - instance уже существует (это OK)
|
||||
```
|
||||
|
||||
### Удаление BunkerWeb instance
|
||||
|
||||
```ruby
|
||||
api.delete_instance(hostname)
|
||||
```
|
||||
|
||||
**Параметры:**
|
||||
- `hostname` - hostname instance для удаления
|
||||
|
||||
## Примеры полного использования
|
||||
|
||||
### Пример 1: Создание и управление сервисом
|
||||
|
||||
```ruby
|
||||
require_relative "HestiaBunkerWebApi.rb"
|
||||
|
||||
begin
|
||||
# 1. Подключаемся к API
|
||||
api = HestiaBunkerWebApi.new(
|
||||
"http://127.0.0.1:8888",
|
||||
"admin",
|
||||
"your_password"
|
||||
)
|
||||
|
||||
# 2. Создаём reverse proxy сервис без SSL
|
||||
result = api.create_service("u4.my.brp", {
|
||||
ssl: "no",
|
||||
reverse_proxy_host: "http://192.168.3.51:8078"
|
||||
})
|
||||
|
||||
puts "[INFO] Service created: #{result.inspect}"
|
||||
|
||||
# 3. Добавляем SSL сертификат позже (если нужно)
|
||||
api.update_service_ssl(
|
||||
"u4.my.brp",
|
||||
"/etc/ssl/certs/u4.crt",
|
||||
"/etc/ssl/private/u4.key"
|
||||
)
|
||||
|
||||
# 4. Проверяем список сервисов
|
||||
services = api.list_services()
|
||||
puts "[INFO] All services:"
|
||||
services.each { |s| puts "- #{s['server_name']}" }
|
||||
|
||||
# 5. Удаление сервиса (при необходимости)
|
||||
api.delete_service("u4.my.brp")
|
||||
|
||||
rescue BunkerWebApiError => e
|
||||
puts "[ERROR] Ошибка API: #{e.message}"
|
||||
exit 1
|
||||
end
|
||||
```
|
||||
|
||||
### Пример 2: Управление несколькими сервисами
|
||||
|
||||
```ruby
|
||||
require_relative "HestiaBunkerWebApi.rb"
|
||||
|
||||
api = HestiaBunkerWebApi.new("http://127.0.0.1:8888", "admin", "password")
|
||||
|
||||
# Создаём несколько сервисов с разными конфигурациями
|
||||
services_to_create = [
|
||||
{ name: "service1.domain", ssl: "no", reverse_proxy_host: "http://192.168.3.50:80" },
|
||||
{ name: "service2.domain", ssl: "yes", certificate_path: "/certs/service2.crt", key_path: "/keys/service2.key", reverse_proxy_host: "http://192.168.3.51:8078" }
|
||||
]
|
||||
|
||||
services_to_create.each do |opts|
|
||||
begin
|
||||
api.create_service(opts[:name], opts)
|
||||
rescue BunkerWebApiError => e
|
||||
puts "[ERROR] #{e.message}" if e.message.include?("already exists")
|
||||
end
|
||||
end
|
||||
|
||||
# Reload конфигурации на instance
|
||||
api.reload_instance("192.168.3.50")
|
||||
```
|
||||
|
||||
### Пример 3: Обработка ошибок и логирование
|
||||
|
||||
```ruby
|
||||
require_relative "HestiaBunkerWebApi.rb"
|
||||
|
||||
def safe_create_service(api_url, username, password, service_name, options)
|
||||
begin
|
||||
api = HestiaBunkerWebApi.new(api_url, username, password)
|
||||
|
||||
result = api.create_service(service_name, options)
|
||||
return { success: true, data: result }
|
||||
|
||||
rescue BunkerWebApiError => e
|
||||
if e.message.include?("Authentication")
|
||||
puts "[FATAL] Authentication failed: #{e.message}"
|
||||
elsif e.message.include?("already exists")
|
||||
begin
|
||||
existing = api.get_service(service_name)
|
||||
return { success: false, already_exists: true, service: existing }
|
||||
rescue => get_error
|
||||
return { success: false, error: "Can't retrieve service: #{get_error.message}" }
|
||||
else
|
||||
return { success: false, error: e.message }
|
||||
end
|
||||
end
|
||||
|
||||
{ success: false, error: "Unknown error" }
|
||||
end
|
||||
|
||||
# Использование
|
||||
result = safe_create_service("http://127.0.0.1:8888", "admin", "password", "example.domain", { ssl: "yes" })
|
||||
|
||||
if result[:success]
|
||||
puts "[SUCCESS] Service created"
|
||||
elsif result[:already_exists]
|
||||
puts "[INFO] Service exists:"
|
||||
puts JSON.generate(result[:service])
|
||||
else
|
||||
puts "[FAILED] #{result[:error]}"
|
||||
end
|
||||
```
|
||||
|
||||
## Ошибки и их обработка
|
||||
|
||||
### Типичные ошибки:
|
||||
|
||||
| Код ответа | Описание | Пример сообщения |
|
||||
|------------|----------|------------------|
|
||||
| **401** | Authentication failed | "Authentication failed: 401 - Unauthorized" |
|
||||
| **200 (no token)** | Auth passed but no token | "Authentication succeeded but no token received" |
|
||||
| **Connection error** | API недоступен | "Authentication error: Connection refused" |
|
||||
| **409 Conflict** | Service already exists | "Service 'x' already exists" |
|
||||
| **422 Unprocessable Entity** | Invalid data (например, LISTEN_HTTPS_PORT = nil) | "Failed to create service: status=422..." |
|
||||
| **429 Too Many Requests** | Rate limit exceeded | "Rate limit exceeded: 10 per 1 minute" |
|
||||
|
||||
### Решение проблем с rate limiting
|
||||
|
||||
Если получаете ошибку `429` (rate limit), нужно отключить или увеличить лимит в `/etc/bunkerweb/api.env`:
|
||||
|
||||
```bash
|
||||
# Откройте конфиг и найдите секцию Rate limiting
|
||||
nano /etc/bunkerweb/api.env
|
||||
|
||||
# Добавьте/измените:
|
||||
API_RATE_LIMIT_ENABLED=no # Отключение rate limiting
|
||||
# или
|
||||
API_RATE_LIMIT=1000/minute # Увеличение лимита до 1000/m
|
||||
```
|
||||
|
||||
Затем перезагрузите API service:
|
||||
|
||||
```bash
|
||||
systemctl reload bunkerweb-api.service
|
||||
```
|
||||
|
||||
## Особенности реализации
|
||||
|
||||
### 1. SSL сертификатные пути
|
||||
|
||||
Когда `ssl: "no"` - API ожидает `"LISTEN_HTTPS_PORT" => "null"` (строка), а не JSON null (`nil`):
|
||||
|
||||
```ruby
|
||||
# ❌ Ошибка:
|
||||
variables["LISTEN_HTTPS_PORT"] = nil # → 422 error
|
||||
|
||||
# ✅ Правильно:
|
||||
variables["LISTEN_HTTPS_PORT"] = "null" # → 200 OK
|
||||
```
|
||||
|
||||
### 2. Статусы ответа для создания сервиса
|
||||
|
||||
BunkerWeb API возвращает **200 OK** вместо стандартного **201 Created**:
|
||||
|
||||
```ruby
|
||||
# Класс принимает оба статуса как успех:
|
||||
if [201, 200].include?(response[:status])
|
||||
puts "[INFO] Service created successfully"
|
||||
end
|
||||
```
|
||||
|
||||
### 3. Поддержка HTTP методов
|
||||
|
||||
Класс поддерживает все основные HTTP методы для API операций:
|
||||
- **GET** - получение данных (services, instances)
|
||||
- **POST** - создание (services, instances, auth)
|
||||
- **PATCH** - обновление (services)
|
||||
- **DELETE** - удаление (services, instances)
|
||||
|
||||
## Совместимость
|
||||
|
||||
- **Ruby**: 3.0+
|
||||
- **BunkerWeb API**: 1.6.x и выше
|
||||
- **ZooKeeper/Redis**: не требуются для этого класса (работает через HTTP API напрямую)
|
||||
|
||||
## Дополнительные ресурсы
|
||||
|
||||
- [Документация BunkerWeb API](https://docs.bunkerweb.io/api.md)
|
||||
- [API Swagger docs at /docs](http://127.0.0.1:8888/docs)
|
||||
- [OpenAPI schema](http://127.0.0.1:8888/openapi.json)
|
||||
240
func_ruby/ext-modules/bunkerweb_module.mod
Normal file
@@ -0,0 +1,240 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
require 'shellwords'
|
||||
|
||||
class BunkerwebWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "bunkerweb_module"
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 5,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Bunkerweb enabling",
|
||||
REQ: "",
|
||||
CONF: "yes",
|
||||
}
|
||||
end
|
||||
|
||||
def enable
|
||||
log_file = get_log
|
||||
f_inst_pp = get_module_paydata("bunkerweb_installer.yml")
|
||||
if !check
|
||||
inf = info
|
||||
log("Req error, needed #{inf[:REQ]}")
|
||||
"Req error, needed #{inf[:REQ]}"
|
||||
else
|
||||
begin
|
||||
log("install packages for bunkerweb support: /usr/bin/ansible-playbook -vv #{f_inst_pp}")
|
||||
result_action = `LC_ALL=C.UTF-8 /usr/bin/ansible-playbook -vv "#{f_inst_pp}" 2>&1`
|
||||
ex_status = $?.exitstatus
|
||||
if ex_status.to_i == 0 || ex_status.to_i == 2
|
||||
log(result_action)
|
||||
super
|
||||
end
|
||||
rescue => e
|
||||
log("module installation error #{e.message} #{e.backtrace.first}")
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def command(args)
|
||||
return log_return("Not enough arguments. Needed command") if args.length < 1
|
||||
log_file = get_log
|
||||
|
||||
m_command = args[0].strip
|
||||
case m_command
|
||||
when "add"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
m_ip = args[2].strip unless args[2].nil?
|
||||
if m_domain.nil? || m_ip.nil?
|
||||
log_return("Domain and IP should be specified. #{args}")
|
||||
else
|
||||
|
||||
log("add domain to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module add #{m_domain} #{m_ip} shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "delete"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
if m_domain.nil?
|
||||
log_return("Domain should be specified. #{args}")
|
||||
else
|
||||
|
||||
log("add domain to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module delete #{m_domain} shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "addssl"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
m_ssl_cert = args[2].strip unless args[2].nil?
|
||||
m_ssl_key = args[3].strip unless args[3].nil?
|
||||
if m_domain.nil? || m_ssl_cert.nil? || m_ssl_key.nil? || m_ssl_cert.empty? || m_ssl_key.empty?
|
||||
log_return("Domain, SSL cert and SSL key must be specified. #{args}")
|
||||
else
|
||||
log("add ssl cert to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module addssl #{m_domain} #{m_ssl_cert} #{m_ssl_key} shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "updssl"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
m_ssl_cert = args[2].strip unless args[2].nil?
|
||||
m_ssl_key = args[3].strip unless args[3].nil?
|
||||
if m_domain.nil? || m_ssl_cert.nil? || m_ssl_key.nil? || m_ssl_cert.empty? || m_ssl_key.empty?
|
||||
log_return("Domain, SSL cert and SSL key must be specified. #{args}")
|
||||
else
|
||||
log("update ssl cert to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module updssl #{m_domain} #{m_ssl_cert} #{m_ssl_key} shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "deletessl"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
if m_domain.nil?
|
||||
log_return("Domain should be specified. #{args}")
|
||||
else
|
||||
|
||||
log("delete ssl cert to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module deletessl #{m_domain} shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "list"
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
log("list of services")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module list #{format}`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
puts output
|
||||
ACTION_OK
|
||||
end
|
||||
when "passwd"
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
cred = {}
|
||||
api_file = "/etc/bunkerweb/api.env"
|
||||
if File.exist?(api_file)
|
||||
File.readlines(api_file).each do |line|
|
||||
line.strip!
|
||||
next if line.empty? || line.start_with?('#')
|
||||
key, value = line.split('=', 2)
|
||||
if %w[API_USERNAME API_PASSWORD].include?(key)
|
||||
cred[key] = value
|
||||
end
|
||||
end
|
||||
else
|
||||
cred["API_USERNAME"] = nil
|
||||
cred["API_PASSWORD"] = nil
|
||||
end
|
||||
cred["API_USERNAME"] ||= nil
|
||||
cred["API_PASSWORD"] ||= nil
|
||||
|
||||
ui_file = "/etc/bunkerweb/ui.env"
|
||||
if File.exist?(ui_file)
|
||||
File.readlines(ui_file).each do |line|
|
||||
line.strip!
|
||||
next if line.empty? || line.start_with?('#')
|
||||
key, value = line.split('=', 2)
|
||||
if %w[ADMIN_USERNAME ADMIN_PASSWORD].include?(key)
|
||||
cred[key] = value
|
||||
end
|
||||
end
|
||||
else
|
||||
cred["ADMIN_USERNAME"] = nil
|
||||
cred["ADMIN_PASSWORD"] = nil
|
||||
end
|
||||
cred["ADMIN_USERNAME"] ||= nil
|
||||
cred["ADMIN_PASSWORD"] ||= nil
|
||||
|
||||
result = []
|
||||
result << cred
|
||||
hestia_print_array_of_hashes(result, format, "API_USERNAME,API_PASSWORD,ADMIN_USERNAME,ADMIN_PASSWORD")
|
||||
ACTION_OK
|
||||
when "configure"
|
||||
param1 = args[1]
|
||||
param2 = args[2]
|
||||
if param1 && param2 && !param1.strip.empty? && !param2.strip.empty?
|
||||
cmd = "/usr/local/hestia/bin/v-bunkerweb-module-install #{Shellwords.escape(param1)} #{Shellwords.escape(param2)}"
|
||||
else
|
||||
cmd = "/usr/local/hestia/bin/v-bunkerweb-module-install"
|
||||
end
|
||||
output = `#{cmd} 2>&1`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("#{output}\nCommand failed with status #{exit_status}")
|
||||
else
|
||||
puts output
|
||||
ACTION_OK
|
||||
end
|
||||
when "alias"
|
||||
m_domain = args[1].strip unless args[1].nil?
|
||||
m_alias = args[2].strip unless args[2].nil?
|
||||
if m_domain.nil?
|
||||
log_return("Domain should be specified. #{args}")
|
||||
else
|
||||
|
||||
log("add alias #{m_alias} to domain #{m_domain} to bunkerweb protection")
|
||||
output = `/usr/local/hestia/bin/v-bunkerweb-module alias #{m_domain} "#{m_alias}" shell`
|
||||
exit_status = $?.exitstatus
|
||||
if exit_status != 0
|
||||
log_return("Command failed with status #{exit_status}")
|
||||
else
|
||||
ACTION_OK
|
||||
end
|
||||
end
|
||||
when "help"
|
||||
puts "#{$0} bunkerweb_module COMMAND [OPTIONS] [json|csv|plain]"
|
||||
puts "COMMANDS:"
|
||||
puts " add domain - add domain to bunkerweb"
|
||||
puts " delete domain - delete domain from bunkerweb"
|
||||
puts " addssl domain [path_to_cert] [path_to_key] - add existsing certificate to bunkerweb domain"
|
||||
puts " updssl domain [path_to_cert] [path_to_key] - update existsing certificate to bunkerweb domain"
|
||||
puts " passwd - get ui and api passwd"
|
||||
puts " configure [path_to_cert] [path_to_key] - start initial setup of bunkerweb should do only once"
|
||||
puts " help - help"
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("Unknown command. #{args}")
|
||||
end
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module BunkerwebModule
|
||||
def get_object
|
||||
Proc.new { BunkerwebWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include BunkerwebModule
|
||||
|
||||
@@loaded_plugins[BunkerwebWorker::MODULE_ID] = BunkerwebModule.get_object
|
||||
end
|
||||
1
func_ruby/ext-modules/configs/passenger_manager/version
Normal file
@@ -0,0 +1 @@
|
||||
0.0.1
|
||||
31
func_ruby/ext-modules/empty_module.mod
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
class EmptyWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "empty_module"
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 3,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Just empty module for storing max module id",
|
||||
REQ: "",
|
||||
CONF: "",
|
||||
}
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module EmptyModule
|
||||
def get_object
|
||||
Proc.new { EmptyWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include EmptyModule
|
||||
|
||||
@@loaded_plugins[EmptyWorker::MODULE_ID] = EmptyModule.get_object
|
||||
end
|
||||
1
func_ruby/ext-modules/last_free_id
Normal file
@@ -0,0 +1 @@
|
||||
7
|
||||
233
func_ruby/ext-modules/passenger_manager.mod
Normal file
@@ -0,0 +1,233 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
require "shell"
|
||||
|
||||
class PassengerWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "passenger_manager"
|
||||
|
||||
def check_domains_with_passenger
|
||||
dom_file = get_module_conf("domains.conf")
|
||||
val = hestia_get_file_keys_value(dom_file)
|
||||
if val.empty?
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 2,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Added passenger support for nginx",
|
||||
REQ: "",
|
||||
CONF: "yes",
|
||||
}
|
||||
end
|
||||
|
||||
def enable
|
||||
log_file = get_log
|
||||
f_inst_pp = get_module_paydata("passenger_installer.yml")
|
||||
f_uninst_pp = get_module_paydata("passenger_uninstaller.yml")
|
||||
if !check
|
||||
inf = info
|
||||
log("Req error, needed #{inf[:REQ]}")
|
||||
"Req error, needed #{inf[:REQ]}"
|
||||
else
|
||||
begin
|
||||
prepare_default_ruby_conf
|
||||
log("install packages for passenger + nginx support: /usr/bin/ansible-playbook -vv #{f_inst_pp}")
|
||||
result_action = `LC_ALL=C.UTF-8 /usr/bin/ansible-playbook -vv "#{f_inst_pp}" 2>&1`
|
||||
ex_status = $?.exitstatus
|
||||
if ex_status.to_i == 0 || ex_status.to_i == 2
|
||||
log(result_action)
|
||||
super
|
||||
else
|
||||
log(result_action)
|
||||
log("Try to disable action: /usr/bin/ansible-playbook -vv #{f_uninst_pp}")
|
||||
result_action = `LC_ALL=C.UTF-8 /usr/bin/ansible-playbook -vv "#{f_uninst_pp}" 2>&1`
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
rescue => e
|
||||
log("module installation error #{e.message} #{e.backtrace.first}")
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def disable
|
||||
log_file = get_log
|
||||
f_uninst_pp = get_module_paydata("passenger_uninstaller.yml")
|
||||
if !check_domains_with_passenger
|
||||
return log_return("Presents domains with passenger support disable it first")
|
||||
end
|
||||
begin
|
||||
log("uninstall packages for passenger + nginx support")
|
||||
log("Try to disable action: /usr/bin/ansible-playbook -vv #{f_uninst_pp}")
|
||||
result_action = `LC_ALL=C.UTF-8 /usr/bin/ansible-playbook -vv "#{f_uninst_pp}" 2>&1`
|
||||
ex_status = $?.exitstatus
|
||||
if ex_status.to_i == 0 || ex_status.to_i == 2
|
||||
log(result_action)
|
||||
super
|
||||
else
|
||||
log(result_action)
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
rescue => e
|
||||
log("module installation error #{e.message} #{e.backtrace.first}")
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
end
|
||||
|
||||
def prepare_default_ruby_conf
|
||||
ruby_conf_rubys = get_module_conf("rubys.conf")
|
||||
return if File.exist?(ruby_conf_rubys)
|
||||
|
||||
arr = ["/usr/bin/ruby", "/opt/brepo/ruby33/bin/ruby"]
|
||||
hestia_write_to_config_with_lock(ruby_conf_rubys, arr)
|
||||
end
|
||||
|
||||
def return_rubys_from_conf
|
||||
arr = []
|
||||
ruby_conf_rubys = get_module_conf("rubys.conf")
|
||||
return arr unless File.exist?(ruby_conf_rubys)
|
||||
|
||||
hestia_read_config_with_lock(ruby_conf_rubys)
|
||||
end
|
||||
|
||||
def command(args)
|
||||
return log_return("Not enough arguments. Needed command") if args.length < 1
|
||||
|
||||
m_command = args[0].strip
|
||||
case m_command
|
||||
when "get_rubys"
|
||||
result = return_rubys_from_conf.map { |item| { "RUBY" => item } }
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
hestia_print_array_of_hashes(result, format, "RUBY")
|
||||
ACTION_OK
|
||||
when "add_ruby"
|
||||
path = args[1]
|
||||
if path.nil?
|
||||
log_return("Path to ruby should be specified. #{args}")
|
||||
else
|
||||
path = path.strip
|
||||
if File.exist?(path)
|
||||
rubys = return_rubys_from_conf
|
||||
unless rubys.include? path
|
||||
rubys << path
|
||||
ruby_conf_rubys = get_module_conf("rubys.conf")
|
||||
hestia_write_to_config_with_lock(ruby_conf_rubys, rubys)
|
||||
end
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("File #{path} doesn't exists")
|
||||
end
|
||||
end
|
||||
when "del_ruby"
|
||||
path = args[1]
|
||||
if path.nil?
|
||||
log_return("Path to ruby should be specified. #{args}")
|
||||
else
|
||||
path = path.strip
|
||||
rubys = return_rubys_from_conf
|
||||
if rubys.include? path
|
||||
rubys.delete(path)
|
||||
ruby_conf_rubys = get_module_conf("rubys.conf")
|
||||
hestia_write_to_config_with_lock(ruby_conf_rubys, rubys)
|
||||
end
|
||||
ACTION_OK
|
||||
end
|
||||
when "set_user_ruby"
|
||||
domain = args[1]
|
||||
ruby_ver = args[2]
|
||||
log_mod = args[3]
|
||||
if domain.nil? || ruby_ver.nil?
|
||||
log_return("Domain or ruby version should be specified. #{args}")
|
||||
else
|
||||
if File.exist?(ruby_ver)
|
||||
dom_file = get_module_conf("domains.conf")
|
||||
if !log_mod.nil? && log_mod.to_s.strip == "on"
|
||||
ruby_ver = "#{ruby_ver}|on"
|
||||
end
|
||||
hestia_save_file_key_pair(dom_file, domain, ruby_ver)
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("Ruby path doesn't exists. #{ruby_ver}. Args #{args}")
|
||||
end
|
||||
end
|
||||
when "disable_user"
|
||||
domain = args[1]
|
||||
if domain.nil?
|
||||
log_return("Domain should be specified. #{args}")
|
||||
else
|
||||
dom_file = get_module_conf("domains.conf")
|
||||
hestia_save_file_key_pair(dom_file, domain, "")
|
||||
ACTION_OK
|
||||
end
|
||||
when "get_user_ruby"
|
||||
domain = args[1]
|
||||
if domain.nil?
|
||||
log_return("Domain should be specified. #{args}")
|
||||
else
|
||||
dom_file = get_module_conf("domains.conf")
|
||||
format = (args[2].nil? ? "shell" : args[2].strip)
|
||||
val = hestia_get_file_key_pair(dom_file, domain)
|
||||
val_spl = val.split("|", 2)
|
||||
result = Hash.new
|
||||
result["RUBY"] = val_spl[0]
|
||||
result["LOG"] = (val_spl.length > 1 ? val_spl[1] : "off")
|
||||
a_result = []
|
||||
a_result << result
|
||||
hestia_print_array_of_hashes(a_result, format, "RUBY,LOG")
|
||||
ACTION_OK
|
||||
end
|
||||
when "list_users_ruby"
|
||||
dom_file = get_module_conf("domains.conf")
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
val = hestia_get_file_keys_value(dom_file)
|
||||
result = Array.new
|
||||
val.each do |key, value|
|
||||
vv = value.split("|", 2)
|
||||
result << { "DOMAIN" => key, "RUBY" => vv[0], "LOG" => (vv.length > 1 ? vv[1] : "off") }
|
||||
end
|
||||
hestia_print_array_of_hashes(result, format, "DOMAIN,RUBY,LOG")
|
||||
ACTION_OK
|
||||
when "get_tpl_path"
|
||||
result = [{ "RUBY_TPL" => get_module_paydata_dir }]
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
hestia_print_array_of_hashes(result, format, "RUBY_TPL")
|
||||
ACTION_OK
|
||||
when "help"
|
||||
puts "#{$0} passenger_manager COMMAND [OPTIONS] [json|csv|plain]"
|
||||
puts "COMMANDS:"
|
||||
puts " get_rubys - list all available rubys pathes"
|
||||
puts " add_ruby [full_path_to_ruby_binary] - add ruby to list"
|
||||
puts " del_ruby [full_path_to_ruby] - delete ruby from list"
|
||||
puts " set_user_ruby [domain] [full_path_to_ruby_binary] [logging on or mpty] - set ruby for domain"
|
||||
puts " disable_user [domain] - delete ruby for domain"
|
||||
puts " get_user_ruby [domain] - show ruby path for domain or empty if not set"
|
||||
puts " list_users_ruby - show rubys for all domains"
|
||||
puts " get_tpl_path - show path for module's templates"
|
||||
puts " help - help"
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("Unknown command. #{args}")
|
||||
end
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module PassengerModule
|
||||
def get_object
|
||||
Proc.new { PassengerWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include PassengerModule
|
||||
|
||||
@@loaded_plugins[PassengerWorker::MODULE_ID] = PassengerModule.get_object
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
- name: Install Bunkerweb on localhost
|
||||
hosts: localhost
|
||||
connection: local
|
||||
become: true
|
||||
gather_facts: false
|
||||
environment:
|
||||
LANG: en_US.UTF-8
|
||||
LC_ALL: en_US.UTF-8
|
||||
tasks:
|
||||
- name: Install bunkerweb
|
||||
ansible.builtin.dnf:
|
||||
name: bunkerweb
|
||||
state: present
|
||||
@@ -0,0 +1,50 @@
|
||||
# Default Web Domain Template #
|
||||
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS #
|
||||
#=========================================================================#
|
||||
|
||||
server {
|
||||
listen %ip%:%proxy_ssl_port% ssl;
|
||||
server_name %domain_idn% %alias_idn%;
|
||||
root %docroot%
|
||||
error_log /var/log/%web_system%/domains/%domain%.error.log error;
|
||||
|
||||
ssl_certificate %ssl_pem%;
|
||||
ssl_certificate_key %ssl_key%;
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# TLS 1.3 0-RTT anti-replay
|
||||
if ($anti_replay = 307) { return 307 https://$host$request_uri; }
|
||||
if ($anti_replay = 425) { return 425; }
|
||||
|
||||
include %home%/%user%/conf/web/%domain%/nginx.hsts.conf*;
|
||||
|
||||
location ~ /\.(?!well-known\/|file) {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
passenger_enabled on;
|
||||
passenger_user %user%;
|
||||
passenger_group %user%;
|
||||
passenger_ruby %rubypath%;
|
||||
passenger_friendly_error_pages %rubylog%;
|
||||
|
||||
location / {
|
||||
passenger_base_uri /;
|
||||
passenger_app_root %docrtpriv%;
|
||||
passenger_document_root %docroot%;
|
||||
passenger_startup_file config.rb;
|
||||
passenger_app_type rack;
|
||||
}
|
||||
|
||||
location /error/ {
|
||||
alias %home%/%user%/web/%domain%/document_errors/;
|
||||
}
|
||||
|
||||
disable_symlinks if_not_owner from=%sdocroot%;
|
||||
|
||||
proxy_hide_header Upgrade;
|
||||
|
||||
include %home%/%user%/conf/web/%domain%/nginx.ssl.conf_*;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
# Default Web Domain Template #
|
||||
# DO NOT MODIFY THIS FILE! CHANGES WILL BE LOST WHEN REBUILDING DOMAINS #
|
||||
#=========================================================================#
|
||||
|
||||
server {
|
||||
listen %ip%:%proxy_port%;
|
||||
server_name %domain_idn% %alias_idn%;
|
||||
root %docroot%;
|
||||
error_log /var/log/%web_system%/domains/%domain%.error.log error;
|
||||
|
||||
include %home%/%user%/conf/web/%domain%/nginx.forcessl.conf*;
|
||||
|
||||
location ~ /\.(?!well-known\/|file) {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
passenger_enabled on;
|
||||
passenger_user %user%;
|
||||
passenger_group %user%;
|
||||
passenger_ruby %rubypath%;
|
||||
passenger_friendly_error_pages %rubylog%;
|
||||
|
||||
location / {
|
||||
passenger_base_uri /;
|
||||
passenger_app_root %docrtpriv%;
|
||||
passenger_document_root %docroot%;
|
||||
passenger_startup_file config.rb;
|
||||
passenger_app_type rack;
|
||||
}
|
||||
|
||||
disable_symlinks if_not_owner from=%docroot%;
|
||||
|
||||
include %home%/%user%/conf/web/%domain%/nginx.conf_*;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package { 'rubygems-devel':
|
||||
ensure => installed,
|
||||
name => 'rubygems-devel',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'rubygem-rake':
|
||||
ensure => installed,
|
||||
name => 'rubygem-rake',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'ruby-devel':
|
||||
ensure => installed,
|
||||
name => 'ruby-devel',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'rubygem-rack':
|
||||
ensure => installed,
|
||||
name => 'rubygem-rack',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'alt-brepo-ruby33-devel':
|
||||
ensure => installed,
|
||||
name => 'alt-brepo-ruby33-devel',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'alt-brepo-ruby33-rubygem-rake':
|
||||
ensure => installed,
|
||||
name => 'alt-brepo-ruby33-rubygem-rake',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'passenger-devel':
|
||||
ensure => installed,
|
||||
name => 'passenger-devel',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'passenger':
|
||||
ensure => installed,
|
||||
name => 'passenger',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'nginx-passenger':
|
||||
ensure => installed,
|
||||
name => 'nginx-mod-http-passenger',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> file { 'passenger.conf':
|
||||
ensure => file,
|
||||
path => '/etc/nginx/conf.d/passenger.conf',
|
||||
content => 'passenger_root /usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini;
|
||||
passenger_ruby /usr/bin/ruby;
|
||||
passenger_instance_registry_dir /var/run/passenger-instreg;
|
||||
passenger_user_switching on;
|
||||
passenger_env_var PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY 0;
|
||||
passenger_env_var PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY 0;',
|
||||
}
|
||||
-> file { 'passenger_includer.conf':
|
||||
ensure => file,
|
||||
content => 'load_module modules/ngx_http_passenger_module.so;',
|
||||
path => '/etc/nginx/conf.d/main/passenger.conf',
|
||||
}
|
||||
~> service { 'nginx_service':
|
||||
ensure => running,
|
||||
name => 'nginx',
|
||||
provider => 'systemd',
|
||||
hasrestart => true,
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
---
|
||||
- name: Install Passenger and configure Nginx on localhost
|
||||
hosts: localhost
|
||||
connection: local
|
||||
become: true
|
||||
gather_facts: false
|
||||
environment:
|
||||
LANG: en_US.UTF-8
|
||||
LC_ALL: en_US.UTF-8
|
||||
tasks:
|
||||
# Устанавливаем Ruby и зависимости
|
||||
- name: Install rubygems-devel
|
||||
ansible.builtin.dnf:
|
||||
name: rubygems-devel
|
||||
state: present
|
||||
- name: Install rubygem-rake
|
||||
ansible.builtin.dnf:
|
||||
name: rubygem-rake
|
||||
state: present
|
||||
- name: Install ruby-devel
|
||||
ansible.builtin.dnf:
|
||||
name: ruby-devel
|
||||
state: present
|
||||
- name: Install rubygem-rack
|
||||
ansible.builtin.dnf:
|
||||
name: rubygem-rack
|
||||
state: present
|
||||
- name: Install alt-brepo-ruby33-devel
|
||||
ansible.builtin.dnf:
|
||||
name: alt-brepo-ruby33-devel
|
||||
state: present
|
||||
- name: Install alt-brepo-ruby33-rubygem-rake
|
||||
ansible.builtin.dnf:
|
||||
name: alt-brepo-ruby33-rubygem-rake
|
||||
state: present
|
||||
# Устанавливаем Passenger и модуль Nginx
|
||||
- name: Install passenger-devel
|
||||
ansible.builtin.dnf:
|
||||
name: passenger-devel
|
||||
state: present
|
||||
- name: Install passenger
|
||||
ansible.builtin.dnf:
|
||||
name: passenger
|
||||
state: present
|
||||
- name: Install nginx-mod-http-passenger
|
||||
ansible.builtin.dnf:
|
||||
name: nginx-mod-http-passenger
|
||||
state: present
|
||||
# Конфигурируем Nginx для Passenger
|
||||
- name: Create passenger.conf
|
||||
ansible.builtin.copy:
|
||||
dest: /usr/local/hestia/nginx-system/etc/nginx/conf.d/passenger.conf
|
||||
content: |
|
||||
passenger_root /usr/share/ruby/vendor_ruby/phusion_passenger/locations.ini;
|
||||
passenger_ruby /usr/bin/ruby;
|
||||
passenger_instance_registry_dir /var/run/passenger-instreg;
|
||||
passenger_user_switching on;
|
||||
passenger_env_var PASSENGER_COMPILE_NATIVE_SUPPORT_BINARY 0;
|
||||
passenger_env_var PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY 0;
|
||||
- name: Create passenger_includer.conf
|
||||
ansible.builtin.copy:
|
||||
dest: /usr/local/hestia/nginx-system/etc/nginx/conf.d/main/passenger.conf
|
||||
content: |
|
||||
load_module modules/ngx_http_passenger_module.so;
|
||||
# Перезапускаем Nginx
|
||||
- name: Restart nginx service
|
||||
ansible.builtin.service:
|
||||
name: nginx-system
|
||||
state: restarted
|
||||
@@ -0,0 +1,29 @@
|
||||
package { 'nginx-mod-http-passenger':
|
||||
ensure => absent,
|
||||
name => 'nginx-mod-http-passenger',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'passenger-devel':
|
||||
ensure => absent,
|
||||
name => 'passenger-devel',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> package { 'passenger':
|
||||
ensure => absent,
|
||||
name => 'passenger',
|
||||
provider => 'dnf',
|
||||
}
|
||||
-> file { 'passenger.conf':
|
||||
ensure => absent,
|
||||
path => '/etc/nginx/conf.d/passenger.conf',
|
||||
}
|
||||
-> file { 'passenger_includer.conf':
|
||||
ensure => absent,
|
||||
path => '/etc/nginx/conf.d/main/passenger.conf',
|
||||
}
|
||||
~> service { 'nginx_service':
|
||||
ensure => running,
|
||||
name => 'nginx',
|
||||
provider => 'systemd',
|
||||
hasrestart => true,
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
- name: Uninstall Passenger and configure Nginx on localhost
|
||||
hosts: localhost
|
||||
connection: local
|
||||
become: true
|
||||
gather_facts: false
|
||||
environment:
|
||||
LANG: en_US.UTF-8
|
||||
LC_ALL: en_US.UTF-8
|
||||
tasks:
|
||||
# Удалаем модуль nginx-passenger
|
||||
- name: Remove nginx-mod-http-passenger package
|
||||
ansible.builtin.dnf:
|
||||
name: nginx-mod-http-passenger
|
||||
state: absent
|
||||
# Удалаем passenger и зависимости
|
||||
- name: Remove passenger-devel package
|
||||
ansible.builtin.dnf:
|
||||
name: passenger-devel
|
||||
state: absent
|
||||
- name: Remove passenger package
|
||||
ansible.builtin.dnf:
|
||||
name: passenger
|
||||
state: absent
|
||||
# Удаляем конфигурационные файлы Nginx
|
||||
- name: Remove passenger.conf
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/hestia/nginx-system/etc/nginx/conf.d/passenger.conf
|
||||
state: absent
|
||||
- name: Remove passenger_includer.conf
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/hestia/nginx-system/etc/nginx/conf.d/main/passenger.conf
|
||||
state: absent
|
||||
# Перезапускаем Nginx (необязательно, но полезно)
|
||||
- name: Restart nginx service
|
||||
ansible.builtin.service:
|
||||
name: nginx-system
|
||||
state: restarted
|
||||
256
func_ruby/ext-modules/php_brepo_modules.mod
Normal file
@@ -0,0 +1,256 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
class PHPWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "php_brepo_modules"
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 4,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Module for managing of php modules for php's from brepo repository",
|
||||
REQ: "",
|
||||
CONF: "yes",
|
||||
}
|
||||
end
|
||||
|
||||
def enable
|
||||
if $LOCAL_PHP == "yes"
|
||||
super
|
||||
else
|
||||
log_return("PHP from brepo repository not enabled")
|
||||
end
|
||||
end
|
||||
|
||||
def get_list_of_installed_php
|
||||
php_list = []
|
||||
lst = Dir["/opt/brepo/php*/etc/php.ini"]
|
||||
if lst.length.positive?
|
||||
php_list = lst.select do |item|
|
||||
%r{/opt/brepo/php\d+/etc/php\.ini} =~ item
|
||||
end.map do |item|
|
||||
res = item.match %r{/opt/brepo/php(?<ver>\d+)/etc/php\.ini}
|
||||
res[:ver]
|
||||
end
|
||||
end
|
||||
php_list
|
||||
end
|
||||
|
||||
def get_list_of_installed_php_modules(php_ver)
|
||||
php_modules = {}
|
||||
php_list = get_list_of_installed_php
|
||||
if php_list.include? php_ver
|
||||
lst = Dir["/opt/brepo/php#{php_ver}/etc/mod-installed/*.ini"]
|
||||
php_list_m = lst.map { |item| File.basename(item, ".ini") }.select { |item| item.strip != "" && !(item =~ %r{ioncube_loader_lin_}) }
|
||||
lst_enabled = Dir["/opt/brepo/php#{php_ver}/etc/php.d/*.ini"]
|
||||
php_list_i = {}
|
||||
lst_enabled.each do |item|
|
||||
fname = File.basename(item, ".ini")
|
||||
if fname.strip != ""
|
||||
if File.symlink? item
|
||||
fname_n = File.readlink(item)
|
||||
fname_n = File.basename(fname_n, ".ini")
|
||||
php_list_i[fname_n] = fname unless fname_n.strip == ""
|
||||
end
|
||||
end
|
||||
end
|
||||
php_list_m.each do |item|
|
||||
php_modules[item] = "disabled"
|
||||
php_modules[item] = php_list_i[item] unless php_list_i[item].nil?
|
||||
end
|
||||
end
|
||||
php_modules
|
||||
end
|
||||
|
||||
def get_php_module_description(module_name)
|
||||
case module_name
|
||||
when "bcmath"
|
||||
"Модуль математических операций с числами произвольной точности"
|
||||
when "curl"
|
||||
"Поддержка curl функций из библиотеки libcurl"
|
||||
when "dba"
|
||||
"Эти функции — основа для доступа к базам данных наподобие Berkeley DB"
|
||||
when "dom"
|
||||
"Модуль DOM разрешает работать в PHP с XML- и HTML-документами через DOM API"
|
||||
when "gd"
|
||||
"Функции работы с изображениями"
|
||||
when "imap"
|
||||
"Эти функции позволяют работать с протоколом IMAP, а также NNTP, POP3 и локальными методами доступа к почтовому ящику."
|
||||
when "intl"
|
||||
"Модуль интернационализации"
|
||||
when "ioncube"
|
||||
"Модуль котрый производит деобфускацию кода, написанного на языке php и закодированного утилитами из набора ioncube"
|
||||
when "ioncube_loader_lin_7.4"
|
||||
"Модуль котрый производит деобфускацию кода, написанного на языке php и закодированного утилитами из набора ioncube"
|
||||
when "json"
|
||||
"Поддержка json в PHP"
|
||||
when "ldap"
|
||||
"Поддержка работы с LDAP в PHP"
|
||||
when "mbstring"
|
||||
"Поддержка работы с многобайтовыми строками"
|
||||
when "memcache"
|
||||
"Модуль Memcache предоставляет удобный процедурный и объектно-ориентированный интерфейс к memcached, высокоэффективному кеширующему демону, который был специально разработан для снижения нагрузки на базу данных в динамических веб приложениях"
|
||||
when "mysqli"
|
||||
"Модуль mysqli позволяет вам получить доступ к функциональности, которую предоставляет MySQL версии 4.1 и выше"
|
||||
when "mysqlnd"
|
||||
"Встроенный драйвер MySQL"
|
||||
when "odbc"
|
||||
"В дополнение к обычной поддержке ODBC, функции Unified ODBC в PHP позволяют получить доступ к нескольким базам данных, которые позаимствовали семантику ODBC API для реализации своего собственного API."
|
||||
when "opcache"
|
||||
"Модуль OPcache сохраняет предкомпилированный байт-код скриптов в разделяемой памяти. Кеширование операционного PHP-кода повышает производительность и помогает избегать загрузки и анализа скриптов при каждом запросе."
|
||||
when "pdo"
|
||||
"Модуль PDO определяет легковесный и непротиворечивый интерфейс доступа к базам данных в PHP."
|
||||
when "pdo_dblib"
|
||||
"PDO_DBLIB: драйвер модуля PDO для СУБД Microsoft SQL Server и Sybase"
|
||||
when "pdo_mysql"
|
||||
"PDO_MYSQL: драйвер модуля PDO для СУБД MySQL"
|
||||
when "pdo_odbc"
|
||||
"PDO_ODBC: драйвер модуля PDO для СУБД ODBC и DB2"
|
||||
when "pdo_pgsql"
|
||||
"PDO_PGSQL: драйвер модуля PDO для СУБД PostgreSQL"
|
||||
when "pdo_sqlite"
|
||||
"PDO_SQLITE: драйвер модуля PDO для СУБД SQLite"
|
||||
when "pgsql"
|
||||
"Модуль поддержки взаимодействия PHP с PostgreSQL"
|
||||
when "phar"
|
||||
"Модуль phar предоставляет возможность поместить целое PHP-приложение в один-единственный файл c именем phar (PHP Archive) для простого распространения и установки"
|
||||
when "posix"
|
||||
"Этот модуль содержит интерфейс к функциям, определённым в стандарте IEEE 1003.1 (POSIX.1), которые не доступны с помощью других средств."
|
||||
when "pspell"
|
||||
"Функции позволяют проверять правописание слова и предлагают варианты исправления."
|
||||
when "snmp"
|
||||
"Модуль SNMP предоставляет простой и удобный набор инструментов для управления удалёнными устройствами через Simple Network Management Protocol (простой протокол управления сетями)"
|
||||
when "soap"
|
||||
"Модуль SOAP может использоваться для написания как серверной, так и клиентской части. Он реализует спецификации » SOAP 1.1, » SOAP 1.2 и » WSDL 1.1."
|
||||
when "sodium"
|
||||
"Sodium — современная, простая в работе программная библиотека для шифрования и дешифрования данных, выполнения операций с подписями, хеширования паролей и других криптографических целей"
|
||||
when "sysvmsg"
|
||||
"Модуль поддержки сообщений System V"
|
||||
when "sysvsem"
|
||||
"Поддержка семафоров"
|
||||
when "sysvshm"
|
||||
"Поддержка разделяемой памяти"
|
||||
when "tidy"
|
||||
"Модуль коррекции разметки tidy"
|
||||
when "xmlreader"
|
||||
"Модуль XMLReader — синтаксический анализатор XML-документов"
|
||||
when "xmlrpc"
|
||||
"Функции модуля помогают писать клиентский или серверный код по правилам стандарта XML-RPC"
|
||||
when "xmlwriter"
|
||||
"Модуль XMLWriter оборачивает API-интерфейс парсера xmlWriter, который входит в состав модуля libxml."
|
||||
when "xsl"
|
||||
"Модуль XSL реализует XSL-стандарт путём XSLT-преобразований, которые выполняет через библиотеку libxslt"
|
||||
when "zip"
|
||||
"Модуль позволяет легко читать и записывать как в сами сжатые ZIP-архивы, так и в файлы внутри них"
|
||||
else
|
||||
"нет описания"
|
||||
end
|
||||
end
|
||||
|
||||
def disable_module(php_ver, module_name)
|
||||
php_mods = get_list_of_installed_php_modules(php_ver)
|
||||
return if php_mods[module_name].nil?
|
||||
|
||||
if File.exist? ("/opt/brepo/php#{php_ver}/etc/php.d/#{php_mods[module_name]}.ini")
|
||||
File.unlink("/opt/brepo/php#{php_ver}/etc/php.d/#{php_mods[module_name]}.ini")
|
||||
end
|
||||
end
|
||||
|
||||
def enable_module(php_ver, module_name)
|
||||
php_mods = get_list_of_installed_php_modules(php_ver)
|
||||
return if php_mods[module_name].nil?
|
||||
|
||||
if php_mods[module_name] == "disabled"
|
||||
case module_name
|
||||
when "opcache"
|
||||
File.symlink("/opt/brepo/php#{php_ver}/etc/mod-installed/#{module_name}.ini", "/opt/brepo/php#{php_ver}/etc/php.d/10-#{module_name}.ini")
|
||||
when "mysqli", "pdo_mysql", "xmlreader", "zip"
|
||||
File.symlink("/opt/brepo/php#{php_ver}/etc/mod-installed/#{module_name}.ini", "/opt/brepo/php#{php_ver}/etc/php.d/30-#{module_name}.ini")
|
||||
else
|
||||
File.symlink("/opt/brepo/php#{php_ver}/etc/mod-installed/#{module_name}.ini", "/opt/brepo/php#{php_ver}/etc/php.d/20-#{module_name}.ini")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def command(args)
|
||||
return log_return("Not enough arguments. Needed command") if args.length < 1
|
||||
|
||||
m_command = args[0].strip
|
||||
case m_command
|
||||
when "php_list"
|
||||
result = get_list_of_installed_php.map { |item| { "PHPVER" => item } }
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
hestia_print_array_of_hashes(result, format, "PHPVER")
|
||||
ACTION_OK
|
||||
when "php_modules"
|
||||
vers = args[1]
|
||||
if vers.nil?
|
||||
log_return("Verssion should be specified. #{args}")
|
||||
else
|
||||
vers = vers.strip
|
||||
modules_list = get_list_of_installed_php_modules(vers)
|
||||
m_keys = modules_list.keys.sort
|
||||
result = []
|
||||
m_keys.each do |kk|
|
||||
tmp_hash = {}
|
||||
tmp_hash["PHPVER"] = vers
|
||||
tmp_hash["MODNAME"] = kk
|
||||
tmp_hash["STATE"] = modules_list[kk]
|
||||
tmp_hash["DESCR"] = get_php_module_description(kk)
|
||||
result << tmp_hash
|
||||
end
|
||||
format = (args[2].nil? ? "shell" : args[2].strip)
|
||||
hestia_print_array_of_hashes(result, format, "PHPVER,MODNAME,STATE,DESCR")
|
||||
ACTION_OK
|
||||
end
|
||||
when "php_enable"
|
||||
vers = args[1]
|
||||
mod_n = args[2]
|
||||
if vers.nil? || mod_n.nil?
|
||||
log_return("Verssion and module name should be specified. #{args}")
|
||||
else
|
||||
vers = vers.strip
|
||||
mod_n = mod_n.strip
|
||||
enable_module(vers, mod_n)
|
||||
ACTION_OK
|
||||
end
|
||||
when "php_disable"
|
||||
vers = args[1]
|
||||
mod_n = args[2]
|
||||
if vers.nil? || mod_n.nil?
|
||||
log_return("Verssion and module name should be specified. #{args}")
|
||||
else
|
||||
vers = vers.strip
|
||||
mod_n = mod_n.strip
|
||||
disable_module(vers, mod_n)
|
||||
ACTION_OK
|
||||
end
|
||||
when "help"
|
||||
puts "#{$0} php_brepo_modules COMMAND [OPTIONS] [json|csv|plain]"
|
||||
puts "COMMANDS:"
|
||||
puts " php_list - list all local php installed"
|
||||
puts " php_modules [php_ver] - list available php module"
|
||||
puts " php_enable [php_ver] [module_name] - enable php module"
|
||||
puts " php_disable [php_ver] [module_name] - disable php module"
|
||||
puts " help - help"
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("Unknown command. #{args}")
|
||||
end
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module PHPModule
|
||||
def get_object
|
||||
Proc.new { PHPWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include PHPModule
|
||||
|
||||
@@loaded_plugins[PHPWorker::MODULE_ID] = PHPModule.get_object
|
||||
end
|
||||
117
func_ruby/ext-modules/puppet_installer.mod
Normal file
@@ -0,0 +1,117 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
require "shell"
|
||||
require "date"
|
||||
|
||||
class PuppetWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "puppet_installer"
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 1,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Added puppet support, needed for another modules",
|
||||
REQ: "",
|
||||
CONF: "",
|
||||
}
|
||||
end
|
||||
|
||||
def enable
|
||||
log_file = get_log
|
||||
date = DateTime.now
|
||||
bkp_name = date.strftime("%Y_%m_%d_%H_%M_%S")
|
||||
if !check
|
||||
inf = info
|
||||
log("Req error, needed #{inf[:REQ]}")
|
||||
"Req error, needed #{inf[:REQ]}"
|
||||
else
|
||||
Shell.def_system_command("dnf", "/usr/bin/dnf")
|
||||
Shell.def_system_command("gem", "/usr/bin/gem")
|
||||
Shell.verbose = true
|
||||
Shell.debug = false
|
||||
sh = Shell.new
|
||||
begin
|
||||
%x( /usr/bin/rpm -q puppet )
|
||||
unless $?.success?
|
||||
log("install puppet packages")
|
||||
sh.transact do
|
||||
dnf("install", "-y", "puppet", "ruby", "rubygems", "puppet-stdlib") > log_file
|
||||
gem("cleanup", "thor") > log_file
|
||||
end
|
||||
else
|
||||
log("puppet installed")
|
||||
end
|
||||
log("prepare puppet configuration")
|
||||
if File.exist?("/etc/puppet/puppet.conf")
|
||||
File.rename("/etc/puppet/puppet.conf", "/etc/puppet/puppet.conf.#{bkp_name}")
|
||||
end
|
||||
puppet_conf = <<~CONF
|
||||
[main]
|
||||
confdir=/etc/puppet
|
||||
logdir=/var/log/puppet
|
||||
vardir=/var/lib/puppet
|
||||
ssldir=/var/lib/puppet/ssl
|
||||
rundir=/var/run/puppet
|
||||
factpath=$confdir/facter
|
||||
environmentpath=$confdir/environments
|
||||
basemodulepath=/usr/share/puppet/modules
|
||||
default_manifest=$confdir/manifests
|
||||
environment_timeout = unlimited
|
||||
manifests_path =$confdir/manifests
|
||||
CONF
|
||||
File.open("/etc/puppet/puppet.conf", "w") do |f|
|
||||
f.puts(puppet_conf)
|
||||
end
|
||||
log("prepare hiera configuration")
|
||||
if File.exist?("/etc/puppet/hiera.yaml")
|
||||
File.rename("/etc/puppet/hiera.yaml", "/etc/puppet/hiera.yaml.#{bkp_name}")
|
||||
end
|
||||
hiera_conf = <<~CONF
|
||||
---
|
||||
version: 5
|
||||
hierarchy:
|
||||
- name: "yaml"
|
||||
datadir: /tmp/puppet/hieradata
|
||||
# data is staged to a local directory by the puppet-manifest-apply.sh script
|
||||
data_hash: yaml_data
|
||||
paths:
|
||||
- runtime.yaml
|
||||
- host.yaml
|
||||
- secure_system.yaml
|
||||
- system.yaml
|
||||
- secure_static.yaml
|
||||
- static.yaml
|
||||
- personality.yaml
|
||||
- global.yaml
|
||||
CONF
|
||||
File.open("/etc/puppet/hiera.yaml", "w") do |f|
|
||||
f.puts(hiera_conf)
|
||||
end
|
||||
log("create manifests directory")
|
||||
sh.transact do
|
||||
((mkdir("/etc/puppet/manifests")) > log_file) unless File.exist?("/etc/puppet/manifests")
|
||||
end
|
||||
super
|
||||
rescue => e
|
||||
log("module installation error #{e.message} #{e.backtrace.first}")
|
||||
"module installation error. See log #{log_file}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module PuppetModule
|
||||
def get_object
|
||||
Proc.new { PuppetWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include PuppetModule
|
||||
|
||||
@@loaded_plugins[PuppetWorker::MODULE_ID] = PuppetModule.get_object
|
||||
end
|
||||
122
func_ruby/ext-modules/update_module.mod
Normal file
@@ -0,0 +1,122 @@
|
||||
#!/opt/brepo/ruby33/bin/ruby
|
||||
|
||||
require 'pathname'
|
||||
require 'fileutils'
|
||||
require 'digest'
|
||||
|
||||
class UpdateWorker < Kernel::ModuleCoreWorker
|
||||
MODULE_ID = "update_module"
|
||||
|
||||
def info
|
||||
{
|
||||
ID: 6,
|
||||
NAME: MODULE_ID,
|
||||
DESCR: "Module for updating HestiaCP data and templates",
|
||||
REQ: "",
|
||||
CONF: "yes",
|
||||
}
|
||||
end
|
||||
|
||||
def file_changed?(new_file, old_file)
|
||||
return true unless File.exist?(old_file)
|
||||
new_hash = Digest::SHA256.file(new_file).hexdigest
|
||||
old_hash = Digest::SHA256.file(old_file).hexdigest
|
||||
new_hash != old_hash
|
||||
end
|
||||
|
||||
def get_templates_map()
|
||||
{ :templates=>
|
||||
[
|
||||
{:new=>"/usr/local/hestia/install/rpm/templates/web/awstats", :old=>"/usr/local/hestia/data/templates/web/awstats"},
|
||||
{:new=>"/usr/local/hestia/install/rpm/templates/web/httpd", :old=>"/usr/local/hestia/data/templates/web/httpd"},
|
||||
{:new=>"/usr/local/hestia/install/rpm/templates/web/nginx", :old=>"/usr/local/hestia/data/templates/web/nginx"},
|
||||
{:new=>"/usr/local/hestia/install/rpm/templates/web/php-fpm", :old=>"/usr/local/hestia/data/templates/web/php-fpm"}
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
# New helper method to get list of changed template files
|
||||
def get_changed_template_files
|
||||
templates_map = get_templates_map()[:templates]
|
||||
result = []
|
||||
templates_map.each do |tpl|
|
||||
new_dir = tpl[:new]
|
||||
old_dir = tpl[:old]
|
||||
Dir.glob(File.join(new_dir, '**', '*')).each do |new_file|
|
||||
next if File.directory?(new_file)
|
||||
rel_path = Pathname.new(new_file).relative_path_from(Pathname.new(new_dir)).to_s
|
||||
old_file = File.join(old_dir, rel_path)
|
||||
result << [new_dir, new_file, old_file] if file_changed?(new_file, old_file)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def command(args)
|
||||
return log_return("Not enough arguments. Needed command") if args.length < 1
|
||||
log_file = get_log
|
||||
|
||||
m_command = args[0].strip
|
||||
case m_command
|
||||
when "synctemplates"
|
||||
result = get_changed_template_files
|
||||
result.each do |new_dir, new_file, old_file|
|
||||
if !File.exist?(old_file)
|
||||
FileUtils.cp(new_file, old_file)
|
||||
else
|
||||
stat = File.stat(old_file)
|
||||
uid = stat.uid
|
||||
gid = stat.gid
|
||||
mode = stat.mode & 0o7777
|
||||
FileUtils.cp(new_file, old_file)
|
||||
File.chown(uid, gid, old_file)
|
||||
File.chmod(mode, old_file)
|
||||
end
|
||||
end
|
||||
ACTION_OK
|
||||
when "listsynctemplates"
|
||||
format = (args[1].nil? ? "shell" : args[1].strip)
|
||||
list = get_changed_template_files
|
||||
result = []
|
||||
result = list.map do |new_dir, new_file, old_file|
|
||||
file_name = Pathname.new(new_file).relative_path_from(Pathname.new(new_dir)).to_s
|
||||
dir_name = File.basename(new_dir)
|
||||
relative_path = Pathname.new(new_file).relative_path_from(Pathname.new(new_dir)).to_s
|
||||
file_name = File.join(dir_name, relative_path)
|
||||
{
|
||||
"FILE_NAME" => file_name,
|
||||
"NEW_SIZE" => File.size(new_file),
|
||||
"OLD_SIZE" => File.exist?(old_file) ? File.size(old_file) : "-"
|
||||
}
|
||||
end
|
||||
|
||||
hestia_print_array_of_hashes(result, format, "FILE_NAME,NEW_SIZE,OLD_SIZE")
|
||||
ACTION_OK
|
||||
when "help"
|
||||
puts "#{$0} update_module COMMAND [json|csv|plain]"
|
||||
puts "COMMANDS:"
|
||||
puts " synctemplates - sync web templates"
|
||||
puts " listsynctemplates - show changed web templates"
|
||||
puts " help - help"
|
||||
ACTION_OK
|
||||
else
|
||||
log_return("Unknown command. #{args}")
|
||||
end
|
||||
end
|
||||
|
||||
implements IPluginInterface
|
||||
end
|
||||
|
||||
module UpdateModule
|
||||
def get_object
|
||||
Proc.new { UpdateWorker.new }
|
||||
end
|
||||
|
||||
module_function :get_object
|
||||
end
|
||||
|
||||
class Kernel::PluginConfiguration
|
||||
include UpdateModule
|
||||
|
||||
@@loaded_plugins[UpdateWorker::MODULE_ID] = UpdateModule.get_object
|
||||
end
|
||||