Add node mode with SSH auto-install and Remnawave-style manual deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
orohi
2026-07-29 04:03:33 +03:00
co-authored by Cursor
parent 93bbbf8ce8
commit 7b77d84f68
20 changed files with 1470 additions and 8 deletions
+35 -3
View File
@@ -12,23 +12,45 @@ import (
"github.com/orohi/vpn-panel/internal/auth"
"github.com/orohi/vpn-panel/internal/db"
"github.com/orohi/vpn-panel/internal/secretbox"
)
type Server struct {
DB *sql.DB
Auth *auth.Manager
Templates *template.Template
SecretKey []byte
}
type pageData map[string]any
func New(database *sql.DB, authMgr *auth.Manager, templatesDir string) (*Server, error) {
func New(database *sql.DB, authMgr *auth.Manager, appSecret, templatesDir string) (*Server, error) {
pattern := filepath.Join(templatesDir, "*.html")
tmpl, err := template.ParseGlob(pattern)
tmpl, err := template.New("").Funcs(template.FuncMap{
"statusClass": func(s string) string {
switch s {
case "online":
return "on"
case "installing":
return "warn"
case "error":
return "err"
case "offline":
return "off"
default:
return "off"
}
},
}).ParseGlob(pattern)
if err != nil {
return nil, err
}
return &Server{DB: database, Auth: authMgr, Templates: tmpl}, nil
return &Server{
DB: database,
Auth: authMgr,
Templates: tmpl,
SecretKey: secretbox.DeriveKey(appSecret),
}, nil
}
func (s *Server) Routes() http.Handler {
@@ -44,6 +66,14 @@ func (s *Server) Routes() http.Handler {
r.HandleFunc("/admin/protocols", s.Auth.RequireAuth(s.protocols)).Methods(http.MethodGet)
r.HandleFunc("/admin/protocols/{id}/toggle", s.Auth.RequireAuth(s.toggleProtocol)).Methods(http.MethodPost)
r.HandleFunc("/admin/nodes", s.Auth.RequireAuth(s.nodesList)).Methods(http.MethodGet)
r.HandleFunc("/admin/nodes/new", s.Auth.RequireAuth(s.nodesNewGet)).Methods(http.MethodGet)
r.HandleFunc("/admin/nodes/new", s.Auth.RequireAuth(s.nodesCreate)).Methods(http.MethodPost)
r.HandleFunc("/admin/nodes/{id}", s.Auth.RequireAuth(s.nodeView)).Methods(http.MethodGet)
r.HandleFunc("/admin/nodes/{id}/install", s.Auth.RequireAuth(s.nodeInstall)).Methods(http.MethodPost)
r.HandleFunc("/admin/nodes/{id}/check", s.Auth.RequireAuth(s.nodeCheck)).Methods(http.MethodPost)
r.HandleFunc("/admin/nodes/{id}/delete", s.Auth.RequireAuth(s.nodeDelete)).Methods(http.MethodPost)
r.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok"))
@@ -125,11 +155,13 @@ func (s *Server) dashboard(w http.ResponseWriter, r *http.Request) {
http.Error(w, "db error", http.StatusInternalServerError)
return
}
nodes, _ := db.ListNodes(s.DB)
s.render(w, "dashboard.html", pageData{
"Title": "Админка",
"UserName": s.Auth.CurrentName(r),
"Stats": stats,
"Protocols": protocols,
"Nodes": nodes,
"Active": "dashboard",
})
}