repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

pico / pkg / apps / pgs
Eric Bower  ·  2026-03-05

ssh.go

  1package pgs
  2
  3import (
  4	"context"
  5	"os"
  6	"os/signal"
  7	"syscall"
  8
  9	"github.com/picosh/pico/pkg/pssh"
 10	"github.com/picosh/pico/pkg/send/auth"
 11	"github.com/picosh/pico/pkg/send/list"
 12	"github.com/picosh/pico/pkg/send/pipe"
 13	"github.com/picosh/pico/pkg/send/protocols/rsync"
 14	"github.com/picosh/pico/pkg/send/protocols/scp"
 15	"github.com/picosh/pico/pkg/send/protocols/sftp"
 16	"github.com/picosh/pico/pkg/shared"
 17	"github.com/picosh/pico/pkg/tunkit"
 18)
 19
 20func createSshServer(cfg *PgsConfig, ctx context.Context, cacheClearingQueue chan string) (*pssh.SSHServer, error) {
 21	host := shared.GetEnv("PGS_HOST", "0.0.0.0")
 22	port := shared.GetEnv("PGS_SSH_PORT", "2222")
 23	promPort := shared.GetEnv("PGS_PROM_PORT", "9222")
 24	logger := cfg.Logger
 25
 26	handler := NewUploadAssetHandler(
 27		cfg,
 28		cacheClearingQueue,
 29		ctx,
 30	)
 31
 32	sshAuth := shared.NewSshAuthHandler(cfg.DB, logger, "pgs")
 33
 34	webTunnel := &tunkit.WebTunnelHandler{
 35		Logger:      logger,
 36		HttpHandler: CreateHttpHandler(cfg),
 37	}
 38
 39	// Create a new SSH server
 40	server, err := pssh.NewSSHServerWithConfig(
 41		ctx,
 42		logger,
 43		"pgs-ssh",
 44		host,
 45		port,
 46		promPort,
 47		"ssh_data/term_info_ed25519",
 48		sshAuth.PubkeyAuthHandler,
 49		[]pssh.SSHServerMiddleware{
 50			pipe.Middleware(handler, ""),
 51			list.Middleware(handler),
 52			scp.Middleware(handler),
 53			rsync.Middleware(handler),
 54			auth.Middleware(handler),
 55			Middleware(handler),
 56			pssh.LogMiddleware(handler, handler.Cfg.DB),
 57		},
 58		[]pssh.SSHServerMiddleware{
 59			sftp.Middleware(handler),
 60			pssh.LogMiddleware(handler, handler.Cfg.DB),
 61		},
 62		map[string]pssh.SSHServerChannelMiddleware{
 63			"direct-tcpip": tunkit.LocalForwardHandler(webTunnel),
 64		},
 65	)
 66
 67	return server, err
 68}
 69
 70func StartSshServer(cfg *PgsConfig, killCh chan error) {
 71	ctx, cancel := context.WithCancel(context.Background())
 72	defer cancel()
 73
 74	cacheClearingQueue := make(chan string, 100)
 75	logger := cfg.Logger
 76
 77	server, err := createSshServer(cfg, ctx, cacheClearingQueue)
 78	if err != nil {
 79		logger.Error("failed to create ssh server", "err", err.Error())
 80		os.Exit(1)
 81	}
 82
 83	// start cron job for bin project ttl
 84	go BinCron(cfg)
 85
 86	done := make(chan os.Signal, 1)
 87	signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
 88	logger.Info("Starting SSH server", "addr", server.Config.ListenAddr)
 89	go func() {
 90		if err = server.ListenAndServe(); err != nil {
 91			logger.Error("serve", "err", err.Error())
 92			os.Exit(1)
 93		}
 94	}()
 95
 96	exit := func() {
 97		logger.Info("stopping ssh server")
 98		cancel()
 99	}
100
101	select {
102	case <-killCh:
103		exit()
104	case <-done:
105		exit()
106	}
107}