77f8b59290
OpenVPN Web management console with multi-instance support, client cert issuance, traffic/connection auditing, certificate expiry reminders, auto backup/restore. Stack: - Backend: Go 1.21+ (Gin + JWT) - Frontend: Vue 3 + Element Plus + ECharts + Vite - Storage: JSON file (db.json) + filesystem (pki/, instances/, clients/, backups/) Features: - Multi-instance OpenVPN management (independent port/proto/subnet/PKI) - One-click client certificate issuance with .ovpn (embedded certs) - Certificate expiry reminders (30-day threshold) - Connection log parsing (status-version 3) - Auto backup/restore (tar.gz) - Audit log for all write operations - JWT auth (12h TTL) - One-line install.sh for Ubuntu/Debian/RHEL/Fedora
88 lines
1.9 KiB
Go
88 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"openvpn-manager/internal/api"
|
|
"openvpn-manager/internal/config"
|
|
"openvpn-manager/internal/service"
|
|
"openvpn-manager/internal/store"
|
|
"openvpn-manager/pkg/openvpn"
|
|
)
|
|
|
|
func main() {
|
|
dataDir := flag.String("data", "", "data directory (default $OVPNMGR_DATA or ./data)")
|
|
distDir := flag.String("dist", "", "frontend dist directory (default $OVPNMGR_DIST or ./dist)")
|
|
flag.Parse()
|
|
|
|
if *dataDir == "" {
|
|
*dataDir = os.Getenv("OVPNMGR_DATA")
|
|
}
|
|
if *dataDir == "" {
|
|
*dataDir = "./data"
|
|
}
|
|
if *distDir == "" {
|
|
*distDir = os.Getenv("OVPNMGR_DIST")
|
|
}
|
|
if *distDir == "" {
|
|
*distDir = "./dist"
|
|
}
|
|
abs, _ := filepath.Abs(*dataDir)
|
|
cfg := config.Load(abs)
|
|
|
|
if err := os.MkdirAll(cfg.PKIDir(), 0o700); err != nil {
|
|
log.Fatalf("mkdir pki: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.InstancesDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir instances: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.ClientsDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir clients: %v", err)
|
|
}
|
|
if err := os.MkdirAll(cfg.BackupsDir(), 0o755); err != nil {
|
|
log.Fatalf("mkdir backups: %v", err)
|
|
}
|
|
|
|
st, err := store.Open(cfg.DBFile())
|
|
if err != nil {
|
|
log.Fatalf("open store: %v", err)
|
|
}
|
|
ovm := openvpn.NewManager(cfg.OpenVPNBin, cfg.DataDir)
|
|
if err := ovm.EnsureCA(); err != nil {
|
|
log.Printf("warn: ensure CA: %v", err)
|
|
}
|
|
svc := service.New(cfg, st, ovm)
|
|
|
|
addr := cfg.Host + ":" + itoa(cfg.Port)
|
|
log.Printf("openvpn-manager listening on %s, data=%s, dist=%s", addr, cfg.DataDir, *distDir)
|
|
srv := api.NewServer(cfg, svc)
|
|
if err := srv.Router(*distDir).Run(addr); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func itoa(n int) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
neg := false
|
|
if n < 0 {
|
|
neg = true
|
|
n = -n
|
|
}
|
|
var buf [20]byte
|
|
i := len(buf)
|
|
for n > 0 {
|
|
i--
|
|
buf[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
buf[i] = '-'
|
|
}
|
|
return string(buf[i:])
|
|
} |