129 lines
2.6 KiB
Go
129 lines
2.6 KiB
Go
package nginx
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/panelhosting/panel/internal/ssl"
|
|
)
|
|
|
|
type Manager struct {
|
|
sitesDir string
|
|
reloadCmd string
|
|
sslStorage string
|
|
}
|
|
|
|
func NewManager(sitesDir, reloadCmd, sslStorage string) *Manager {
|
|
return &Manager{sitesDir: sitesDir, reloadCmd: reloadCmd, sslStorage: sslStorage}
|
|
}
|
|
|
|
func (m *Manager) Enabled() bool {
|
|
return m.sitesDir != ""
|
|
}
|
|
|
|
func (m *Manager) PrepareHTTPChallenge(domain, documentRoot string) error {
|
|
if !m.Enabled() {
|
|
return nil
|
|
}
|
|
if err := os.MkdirAll(m.sitesDir, 0o755); err != nil {
|
|
return err
|
|
}
|
|
if err := os.MkdirAll(filepath.Join(documentRoot, ".well-known", "acme-challenge"), 0o755); err != nil {
|
|
return err
|
|
}
|
|
|
|
cfg := fmt.Sprintf(`# PanelHosting — HTTP challenge for %s
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name %s;
|
|
|
|
location ^~ /.well-known/acme-challenge/ {
|
|
root %s;
|
|
default_type "text/plain";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
location / {
|
|
return 404;
|
|
}
|
|
}
|
|
`, domain, domain, documentRoot)
|
|
|
|
path := filepath.Join(m.sitesDir, sanitize(domain)+".conf")
|
|
if err := os.WriteFile(path, []byte(cfg), 0o644); err != nil {
|
|
return err
|
|
}
|
|
return m.reload()
|
|
}
|
|
|
|
func (m *Manager) ApplyHTTPS(domain, documentRoot string) error {
|
|
if !m.Enabled() {
|
|
return nil
|
|
}
|
|
certPath, keyPath := ssl.CertPaths(m.sslStorage, domain)
|
|
cfg := fmt.Sprintf(`# PanelHosting — %s
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name %s;
|
|
|
|
location ^~ /.well-known/acme-challenge/ {
|
|
root %s;
|
|
default_type "text/plain";
|
|
try_files $uri =404;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
server_name %s;
|
|
|
|
ssl_certificate %s;
|
|
ssl_certificate_key %s;
|
|
|
|
root %s;
|
|
index index.php index.html;
|
|
|
|
location / {
|
|
try_files $uri $uri/ =404;
|
|
}
|
|
}
|
|
`, domain, domain, documentRoot, domain, domain, certPath, keyPath, documentRoot)
|
|
|
|
path := filepath.Join(m.sitesDir, sanitize(domain)+".conf")
|
|
if err := os.WriteFile(path, []byte(cfg), 0o644); err != nil {
|
|
return err
|
|
}
|
|
return m.reload()
|
|
}
|
|
|
|
func (m *Manager) reload() error {
|
|
cmd := strings.TrimSpace(m.reloadCmd)
|
|
if cmd == "" {
|
|
return nil
|
|
}
|
|
parts := strings.Fields(cmd)
|
|
if len(parts) == 0 {
|
|
return nil
|
|
}
|
|
c := exec.Command(parts[0], parts[1:]...)
|
|
if out, err := c.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("nginx reload: %w: %s", err, strings.TrimSpace(string(out)))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sanitize(domain string) string {
|
|
return strings.NewReplacer(".", "_", ":", "_").Replace(domain)
|
|
}
|