1//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
2// +build darwin dragonfly freebsd linux netbsd openbsd solaris
3
4// This is an example of binding soft-serve ssh port to a restricted port (<1024) and
5// then droping root privileges to a different user to run the server.
6// Make sure you run this as root.
7
8package main
9
10import (
11 "context"
12 "flag"
13 "fmt"
14 "net"
15 "os"
16 "os/signal"
17 "syscall"
18 "time"
19
20 "github.com/charmbracelet/log"
21
22 "github.com/charmbracelet/soft-serve/server"
23 "github.com/charmbracelet/soft-serve/server/config"
24)
25
26var (
27 port = flag.Int("port", 22, "port to listen on")
28 gid = flag.Int("gid", 1000, "group id to run as")
29 uid = flag.Int("uid", 1000, "user id to run as")
30)
31
32func main() {
33 flag.Parse()
34 addr := fmt.Sprintf(":%d", *port)
35 // To listen on port 22 we need root privileges
36 ls, err := net.Listen("tcp", addr)
37 if err != nil {
38 log.Fatal("Can't listen", "err", err)
39 }
40 // We don't need root privileges any more
41 if err := syscall.Setgid(*gid); err != nil {
42 log.Fatal("Setgid error", "err", err)
43 }
44 if err := syscall.Setuid(*uid); err != nil {
45 log.Fatal("Setuid error", "err", err)
46 }
47 ctx := context.Background()
48 // Set up config
49 cfg := config.DefaultConfig()
50 if !cfg.Exist() {
51 if err := cfg.WriteConfig(); err != nil {
52 log.Fatal("failed to write default config: %w", err)
53 }
54 }
55 ctx = config.WithContext(ctx, cfg)
56 cfg.SSH.ListenAddr = fmt.Sprintf(":%d", *port)
57 s, err := server.NewServer(ctx)
58 if err != nil {
59 log.Fatal(err)
60 }
61
62 done := make(chan os.Signal, 1)
63 signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
64
65 log.Print("Starting SSH server", "addr", cfg.SSH.ListenAddr)
66 go func() {
67 if err := s.SSHServer.Serve(ls); err != nil {
68 log.Fatal(err)
69 }
70 }()
71
72 <-done
73
74 log.Print("Stopping SSH server", "addr", cfg.SSH.ListenAddr)
75 ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
76 defer func() { cancel() }()
77 if err := s.Shutdown(ctx); err != nil {
78 log.Fatal(err)
79 }
80}