Interactive install, with flags kept for unattended installs
In a terminal, install now asks for the domain, Let's Encrypt email, endpoint, WireGuard port and admin password, shows a summary and changes nothing until confirmed. Re-runs offer the current settings and say how many devices need a new config when the endpoint or port changes. Flags still work and skip their question; -y or no terminal skips all questions. New -port flag sets the WireGuard UDP port. Every value is checked before the system is touched.
This commit is contained in:
@@ -36,8 +36,9 @@ func usage() {
|
||||
fmt.Fprintf(os.Stderr, `%s %s — WireGuard server manager
|
||||
|
||||
Usage (as root):
|
||||
%s install [-domain vpn.example.net] [-email you@example.net] [-endpoint host]
|
||||
set up user, folder, config, sysctls and systemd service; start it
|
||||
%s install [-domain vpn.example.net] [-email you@example.net] [-endpoint host] [-port 51820] [-y]
|
||||
set up user, folder, config, sysctls and systemd service; start it.
|
||||
In a terminal it asks for the settings no flag gave; -y never asks
|
||||
%s update [-force]
|
||||
replace the installed binary with this one and restart
|
||||
%s uninstall [-purge] [-y]
|
||||
@@ -330,7 +331,11 @@ func cmdInstall(args []string) error {
|
||||
domain := fs.String("domain", "", "domain for the web interface; enables Let's Encrypt")
|
||||
email := fs.String("email", "", "contact email for Let's Encrypt (optional)")
|
||||
endpoint := fs.String("endpoint", "", "host or IP clients connect to (default: the domain)")
|
||||
port := fs.Int("port", 0, "UDP port WireGuard listens on (default: 51820, or the current port when already installed)")
|
||||
yes := fs.Bool("y", false, "do not ask; use the flags and defaults")
|
||||
_ = fs.Parse(args)
|
||||
given := map[string]bool{}
|
||||
fs.Visit(func(f *flag.Flag) { given[f.Name] = true })
|
||||
if err := requireRoot(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -339,6 +344,33 @@ func cmdInstall(args []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read the current settings without changing anything, so questions
|
||||
// and checks happen before the system is touched.
|
||||
_, statErr := os.Stat(configFile)
|
||||
existing := statErr == nil
|
||||
cur, err := loadConfigFile(configFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plan := installPlan{domain: *domain, email: *email, endpoint: *endpoint, port: *port}
|
||||
if err := plan.check(); err != nil {
|
||||
return err
|
||||
}
|
||||
if !existing {
|
||||
n, err := randomSubnet(24)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
plan.ipv4 = n.String()
|
||||
}
|
||||
if !*yes && term.IsTerminal(int(os.Stdin.Fd())) {
|
||||
if plan, err = askInstall(os.Stdin, cur, existing, given, plan); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if n := plan.reissueCount(cur, existing); n > 0 {
|
||||
fmt.Printf("Note: %d existing device(s) need a new config: the endpoint or port changes.\n", n)
|
||||
}
|
||||
|
||||
// User and folder
|
||||
if _, err := user.Lookup(serviceName); err != nil {
|
||||
step("Creating system user %s", serviceName)
|
||||
@@ -375,11 +407,11 @@ func cmdInstall(args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Config: created with defaults (server key, free subnet) if missing.
|
||||
_, statErr := os.Stat(configFile)
|
||||
if errors.Is(statErr, os.ErrNotExist) {
|
||||
// Config: created with defaults (server key, the chosen subnet) if missing.
|
||||
if !existing {
|
||||
step("Creating %s", configFile)
|
||||
if err := os.WriteFile(configFile, []byte("{}\n"), 0o600); err != nil {
|
||||
initial := fmt.Sprintf("{\"server\": {\"ipv4\": %q}}\n", plan.ipv4)
|
||||
if err := os.WriteFile(configFile, []byte(initial), 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -390,23 +422,9 @@ func cmdInstall(args []string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *domain != "" || *email != "" || *endpoint != "" {
|
||||
step("Saving domain and endpoint settings")
|
||||
if err := store.Update(func(c *Config) error {
|
||||
if *domain != "" {
|
||||
c.Web.TLS.Mode, c.Web.TLS.Domain = "acme", *domain
|
||||
if c.Server.Endpoint == "" {
|
||||
c.Server.Endpoint = *domain
|
||||
}
|
||||
}
|
||||
if *email != "" {
|
||||
c.Web.TLS.Email = *email
|
||||
}
|
||||
if *endpoint != "" {
|
||||
c.Server.Endpoint = *endpoint
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
if plan.changes() {
|
||||
step("Saving the settings")
|
||||
if err := store.Update(func(c *Config) error { plan.apply(c); return nil }); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user