Files

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)
}