StartServer starts the SSH server with the provided options. It configures the server with secure defaults, sets up authentication, and begins listening for connections. Returns an error if the server is already running or if there's an issue starting the server.
(opts ServerOptions)
| 37 | // and begins listening for connections. Returns an error if the server |
| 38 | // is already running or if there's an issue starting the server. |
| 39 | func (a *Agent) StartServer(opts ServerOptions) error { |
| 40 | if disableSSH, _ := utils.GetEnv("DISABLE_SSH"); disableSSH == "true" { |
| 41 | return errors.New("SSH disabled") |
| 42 | } |
| 43 | if a.server != nil { |
| 44 | return errors.New("server already started") |
| 45 | } |
| 46 | |
| 47 | slog.Info("Starting SSH server", "addr", opts.Addr, "network", opts.Network) |
| 48 | |
| 49 | if opts.Network == "unix" { |
| 50 | // remove existing socket file if it exists |
| 51 | if err := os.Remove(opts.Addr); err != nil && !os.IsNotExist(err) { |
| 52 | return err |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | // start listening on the address |
| 57 | ln, err := net.Listen(opts.Network, opts.Addr) |
| 58 | if err != nil { |
| 59 | return err |
| 60 | } |
| 61 | defer ln.Close() |
| 62 | |
| 63 | // base config (limit to allowed algorithms) |
| 64 | config := &gossh.ServerConfig{ |
| 65 | ServerVersion: fmt.Sprintf("SSH-2.0-%s_%s", beszel.AppName, beszel.Version), |
| 66 | } |
| 67 | config.KeyExchanges = common.DefaultKeyExchanges |
| 68 | config.MACs = common.DefaultMACs |
| 69 | config.Ciphers = common.DefaultCiphers |
| 70 | |
| 71 | // set default handler |
| 72 | ssh.Handle(a.handleSession) |
| 73 | |
| 74 | a.server = &ssh.Server{ |
| 75 | ServerConfigCallback: func(ctx ssh.Context) *gossh.ServerConfig { |
| 76 | return config |
| 77 | }, |
| 78 | // check public key(s) |
| 79 | PublicKeyHandler: func(ctx ssh.Context, key ssh.PublicKey) bool { |
| 80 | remoteAddr := ctx.RemoteAddr() |
| 81 | for _, pubKey := range opts.Keys { |
| 82 | if ssh.KeysEqual(key, pubKey) { |
| 83 | slog.Info("SSH connected", "addr", remoteAddr) |
| 84 | return true |
| 85 | } |
| 86 | } |
| 87 | slog.Warn("Invalid SSH key", "addr", remoteAddr) |
| 88 | return false |
| 89 | }, |
| 90 | // disable pty |
| 91 | PtyCallback: func(ctx ssh.Context, pty ssh.Pty) bool { |
| 92 | return false |
| 93 | }, |
| 94 | // close idle connections after 70 seconds |
| 95 | IdleTimeout: 70 * time.Second, |
| 96 | } |