package main import ( "context" "fmt" "os" "strings" "github.com/spf13/cobra" "github.com/fatedier/frp/pkg/config" v1 "github.com/fatedier/frp/pkg/config/v1" "github.com/fatedier/frp/pkg/config/v1/validation" "github.com/fatedier/frp/pkg/db" "github.com/fatedier/frp/pkg/policy/security" "github.com/fatedier/frp/pkg/util/log" "github.com/fatedier/frp/pkg/util/version" "github.com/fatedier/frp/server" ) var ( cfgFile string showVersion bool strictConfigMode bool allowUnsafe []string serverCfg v1.ServerConfig ) func init() { rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file of frps") rootCmd.PersistentFlags().BoolVarP(&showVersion, "version", "v", false, "version of frps") rootCmd.PersistentFlags().BoolVarP(&strictConfigMode, "strict_config", "", true, "strict config parsing mode, unknown fields will cause errors") rootCmd.PersistentFlags().StringSliceVarP(&allowUnsafe, "allow-unsafe", "", []string{}, fmt.Sprintf("allowed unsafe features, one or more of: %s", strings.Join(security.ServerUnsafeFeatures, ", "))) config.RegisterServerConfigFlags(rootCmd, &serverCfg) } var rootCmd = &cobra.Command{ Use: "frps", Short: "frps is the server of frp (https://github.com/fatedier/frp)", RunE: func(cmd *cobra.Command, args []string) error { if showVersion { fmt.Println(version.Full()) return nil } if err := db.Init("sqlite", "admin.db"); err != nil { fmt.Printf("failed to initialize admin database: %v\n", err) os.Exit(1) } defer db.Close() var ( svrCfg *v1.ServerConfig isLegacyFormat bool err error ) if cfgFile != "" { svrCfg, isLegacyFormat, err = config.LoadServerConfig(cfgFile, strictConfigMode) if err != nil { fmt.Println(err) os.Exit(1) } if isLegacyFormat { fmt.Printf("WARNING: ini format is deprecated, please use yaml/json/toml instead!\n") } } else { svrCfg, err = loadConfigFromDB() if err != nil { fmt.Printf("failed to load server config: %v\n", err) os.Exit(1) } } unsafeFeatures := security.NewUnsafeFeatures(allowUnsafe) validator := validation.NewConfigValidator(unsafeFeatures) warning, err := validator.ValidateServerConfig(svrCfg) if warning != nil { fmt.Printf("WARNING: %v\n", warning) } if err != nil { fmt.Println(err) os.Exit(1) } if err := runServer(svrCfg); err != nil { fmt.Println(err) os.Exit(1) } return nil }, } func Execute() { rootCmd.SetGlobalNormalizationFunc(config.WordSepNormalizeFunc) if err := rootCmd.Execute(); err != nil { os.Exit(1) } } func loadConfigFromDB() (*v1.ServerConfig, error) { hasConfig, err := db.HasServerConfig() if err != nil { return nil, fmt.Errorf("failed to check server config in db: %w", err) } if hasConfig { cfg, err := db.LoadServerConfig() if err != nil { return nil, fmt.Errorf("failed to load server config from db: %w", err) } if err := cfg.Complete(); err != nil { return nil, fmt.Errorf("failed to complete server config: %w", err) } log.Infof("frps uses database configuration") return cfg, nil } cfg := db.DefaultServerConfig() if err := cfg.Complete(); err != nil { return nil, fmt.Errorf("failed to complete server config: %w", err) } if err := db.SaveServerConfig(cfg); err != nil { log.Warnf("failed to save default config to db: %v", err) } log.Infof("frps started with default configuration (first run)") return cfg, nil } func runServer(cfg *v1.ServerConfig) (err error) { log.InitLogger(cfg.Log.To, cfg.Log.Level, int(cfg.Log.MaxDays), cfg.Log.DisablePrintColor) if cfgFile != "" { log.Infof("frps uses config file: %s", cfgFile) } else { log.Infof("frps uses database configuration") } svr, err := server.NewService(cfg) if err != nil { return err } log.Infof("frps started successfully") svr.Run(context.Background()) return }