diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 4a956e2a6..cb261b1cc 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -65,18 +65,13 @@ nfpms: - wiretrustee formats: - deb - contents: - - src: release_files/wiretrustee.service - dst: /lib/systemd/system/wiretrustee.service - - - src: release_files/wiretrustee.json - dst: /etc/wiretrustee/wiretrustee.json - type: "config|noreplace" scripts: postinstall: "release_files/post_install.sh" + preremove: "release_files/pre_remove.sh" replacements: arm6: armf + - maintainer: Wiretrustee description: Wiretrustee client. homepage: https://wiretrustee.com/ @@ -85,16 +80,10 @@ nfpms: - wiretrustee formats: - rpm - contents: - - src: release_files/wiretrustee.service - dst: /lib/systemd/system/wiretrustee.service - - - src: release_files/wiretrustee.json - dst: /etc/wiretrustee/wiretrustee.json - type: "config|noreplace" scripts: postinstall: "release_files/post_install.sh" + preremove: "release_files/pre_remove.sh" dockers: - image_templates: - wiretrustee/signal:{{ .Version }}-amd64 diff --git a/README.md b/README.md index 3bbbb365d..68652b79c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,6 @@

-
@@ -146,40 +145,22 @@ After that you may need to add /usr/local/bin in your MAC's PATH environment var For **Unix** systems: ```shell - sudo wiretrustee login --setup-key + sudo wiretrustee up --setup-key ``` -For **Windows** systems: +For **Windows** systems, start powershell as administrator and: ```shell - .\wiretrustee.exe login --setup-key + wiretrustee up --setup-key ``` Alternatively, if you are hosting your own Management Service provide `--management-url` property pointing to your Management Service: ```shell - sudo wiretrustee login --setup-key --management-url https://localhost:33073 + sudo wiretrustee up --setup-key --management-url https://localhost:33073 ``` -You could also omit `--setup-key` property. In this case the tool will prompt it the key. +> You could also omit `--setup-key` property. In this case the tool will prompt it the key. -2. Start Wiretrustee: -For **MACOS** you will just start the service: - ````shell - sudo wiretrustee up - # or - sudo wiretrustee up & # to run it in background - ```` -For **Linux** systems: - ```shell - sudo systemctl restart wiretrustee.service - sudo systemctl status wiretrustee.service - ``` -For **Windows** systems: - ```shell - .\wiretrustee.exe service start - ``` -> You may need to run Powershell as Administrator - -3. Check your IP: +2. Check your IP: For **MACOS** you will just start the service: ````shell sudo ipconfig getifaddr utun100 @@ -193,7 +174,7 @@ For **Windows** systems: netsh interface ip show config name="wt0" ``` -4. Repeat on other machines. +3. Repeat on other machines. ### Running Dashboard, Management, Signal and Coturn Wiretrustee uses [Auth0](https://auth0.com) for user authentication and authorization, therefore you will need to create a free account diff --git a/client/cmd/login.go b/client/cmd/login.go index a436b4c7b..f3c27dce8 100644 --- a/client/cmd/login.go +++ b/client/cmd/login.go @@ -152,6 +152,5 @@ func promptPeerSetupKey() (string, error) { return "", s.Err() } -func init() { - loginCmd.PersistentFlags().StringVar(&setupKey, "setup-key", "", "Setup key obtained from the Management Service Dashboard (used to register peer)") -} +//func init() { +//} diff --git a/client/cmd/root.go b/client/cmd/root.go index 647014687..80dd56eda 100644 --- a/client/cmd/root.go +++ b/client/cmd/root.go @@ -2,11 +2,13 @@ package cmd import ( "fmt" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/wiretrustee/wiretrustee/client/internal" "os" "os/signal" "runtime" + "syscall" ) const ( @@ -22,8 +24,7 @@ var ( defaultLogFile string logFile string managementURL string - - rootCmd = &cobra.Command{ + rootCmd = &cobra.Command{ Use: "wiretrustee", Short: "", Long: "", @@ -52,9 +53,11 @@ func init() { rootCmd.PersistentFlags().StringVar(&configPath, "config", defaultConfigPath, "Wiretrustee config file location") rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "sets Wiretrustee log level") rootCmd.PersistentFlags().StringVar(&logFile, "log-file", defaultLogFile, "sets Wiretrustee log path. If console is specified the the log will be output to stdout") + rootCmd.PersistentFlags().StringVar(&setupKey, "setup-key", "", "Setup key obtained from the Management Service Dashboard (used to register peer)") rootCmd.AddCommand(serviceCmd) rootCmd.AddCommand(upCmd) rootCmd.AddCommand(loginCmd) + rootCmd.AddCommand(versionCmd) serviceCmd.AddCommand(runCmd, startCmd, stopCmd, restartCmd) // service control commands are subcommands of service serviceCmd.AddCommand(installCmd, uninstallCmd) // service installer commands are subcommands of service } @@ -62,10 +65,10 @@ func init() { // SetupCloseHandler handles SIGTERM signal and exits with success func SetupCloseHandler() { c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) + signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { for range c { - fmt.Println("\r- Ctrl+C pressed in Terminal") + log.Info("shutdown signal received") stopCh <- 0 } }() diff --git a/client/cmd/service_controller.go b/client/cmd/service_controller.go index 6b3945189..6d80f049b 100644 --- a/client/cmd/service_controller.go +++ b/client/cmd/service_controller.go @@ -4,13 +4,14 @@ import ( "github.com/kardianos/service" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/wiretrustee/wiretrustee/util" ) func (p *program) Start(s service.Service) error { // Start should not block. Do the actual work async. log.Info("starting service") //nolint go func() { - err := upCmd.RunE(p.cmd, p.args) + err := runClient() if err != nil { return } @@ -20,7 +21,6 @@ func (p *program) Start(s service.Service) error { } func (p *program) Stop(s service.Service) error { - stopCh <- 1 return nil } @@ -29,7 +29,11 @@ var ( Use: "run", Short: "runs wiretrustee as service", Run: func(cmd *cobra.Command, args []string) { - + err := util.InitLog(logLevel, logFile) + if err != nil { + log.Errorf("failed initializing log %v", err) + return + } prg := &program{ cmd: cmd, args: args, @@ -54,19 +58,24 @@ var ( startCmd = &cobra.Command{ Use: "start", Short: "starts wiretrustee service", - Run: func(cmd *cobra.Command, args []string) { - + RunE: func(cmd *cobra.Command, args []string) error { + err := util.InitLog(logLevel, logFile) + if err != nil { + log.Errorf("failed initializing log %v", err) + return err + } s, err := newSVC(&program{}, newSVCConfig()) if err != nil { cmd.PrintErrln(err) - return + return err } err = s.Start() if err != nil { cmd.PrintErrln(err) - return + return err } - cmd.Printf("Wiretrustee service has been started") + cmd.Println("Wiretrustee service has been started") + return nil }, } ) @@ -76,7 +85,10 @@ var ( Use: "stop", Short: "stops wiretrustee service", Run: func(cmd *cobra.Command, args []string) { - + err := util.InitLog(logLevel, logFile) + if err != nil { + log.Errorf("failed initializing log %v", err) + } s, err := newSVC(&program{}, newSVCConfig()) if err != nil { cmd.PrintErrln(err) @@ -87,7 +99,7 @@ var ( cmd.PrintErrln(err) return } - cmd.Printf("Wiretrustee service has been stopped") + cmd.Println("Wiretrustee service has been stopped") }, } ) @@ -97,7 +109,10 @@ var ( Use: "restart", Short: "restarts wiretrustee service", Run: func(cmd *cobra.Command, args []string) { - + err := util.InitLog(logLevel, logFile) + if err != nil { + log.Errorf("failed initializing log %v", err) + } s, err := newSVC(&program{}, newSVCConfig()) if err != nil { cmd.PrintErrln(err) @@ -108,7 +123,7 @@ var ( cmd.PrintErrln(err) return } - cmd.Printf("Wiretrustee service has been restarted") + cmd.Println("Wiretrustee service has been restarted") }, } ) diff --git a/client/cmd/service_installer.go b/client/cmd/service_installer.go index 1f289f81d..49331dd65 100644 --- a/client/cmd/service_installer.go +++ b/client/cmd/service_installer.go @@ -9,7 +9,7 @@ var ( installCmd = &cobra.Command{ Use: "install", Short: "installs wiretrustee service", - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { svcConfig := newSVCConfig() @@ -30,15 +30,16 @@ var ( s, err := newSVC(&program{}, svcConfig) if err != nil { cmd.PrintErrln(err) - return + return err } err = s.Install() if err != nil { cmd.PrintErrln(err) - return + return err } - cmd.Printf("Wiretrustee service has been installed") + cmd.Println("Wiretrustee service has been installed") + return nil }, } ) @@ -60,7 +61,7 @@ var ( cmd.PrintErrln(err) return } - cmd.Printf("Wiretrustee has been uninstalled") + cmd.Println("Wiretrustee has been uninstalled") }, } ) diff --git a/client/cmd/up.go b/client/cmd/up.go index 5d2469f82..f869ba841 100644 --- a/client/cmd/up.go +++ b/client/cmd/up.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "github.com/kardianos/service" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/wiretrustee/wiretrustee/client/internal" @@ -17,7 +18,7 @@ import ( var ( upCmd = &cobra.Command{ Use: "up", - Short: "start wiretrustee", + Short: "install, login and start wiretrustee client", RunE: func(cmd *cobra.Command, args []string) error { err := util.InitLog(logLevel, logFile) if err != nil { @@ -25,89 +26,42 @@ var ( return err } - config, err := internal.ReadConfig(managementURL, configPath) + err = loginCmd.RunE(cmd, args) if err != nil { - log.Errorf("failed reading config %s %v", configPath, err) + return err + } + if logFile == "console" { + return runClient() + } + + s, err := newSVC(&program{}, newSVCConfig()) + if err != nil { + cmd.PrintErrln(err) return err } - //validate our peer's Wireguard PRIVATE key - myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) + srvStatus, err := s.Status() if err != nil { - log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) - return err + if err == service.ErrNotInstalled { + log.Infof("%s. Installing it now", err.Error()) + e := installCmd.RunE(cmd, args) + if e != nil { + return e + } + } else { + log.Warnf("failed retrieving service status: %v", err) + } } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - mgmTlsEnabled := false - if config.ManagementURL.Scheme == "https" { - mgmTlsEnabled = true + if srvStatus == service.StatusRunning { + stopCmd.Run(cmd, args) } - - // connect (just a connection, no stream yet) and login to Management Service to get an initial global Wiretrustee config - mgmClient, loginResp, err := connectToManagement(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled) - if err != nil { - log.Warn(err) - return err - } - - // with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal - signalClient, err := connectToSignal(ctx, loginResp.GetWiretrusteeConfig(), myPrivateKey) - if err != nil { - log.Error(err) - return err - } - - engineConfig, err := createEngineConfig(myPrivateKey, config, loginResp.GetWiretrusteeConfig(), loginResp.GetPeerConfig()) - if err != nil { - log.Error(err) - return err - } - - // create start the Wiretrustee Engine that will connect to the Signal and Management streams and manage connections to remote peers. - engine := internal.NewEngine(signalClient, mgmClient, engineConfig, cancel) - err = engine.Start() - if err != nil { - log.Errorf("error while starting Wiretrustee Connection Engine: %s", err) - return err - } - - SetupCloseHandler() - - select { - case <-stopCh: - case <-ctx.Done(): - } - - log.Infof("receive signal to stop running") - err = mgmClient.Close() - if err != nil { - log.Errorf("failed closing Management Service client %v", err) - return err - } - err = signalClient.Close() - if err != nil { - log.Errorf("failed closing Signal Service client %v", err) - return err - } - - err = engine.Stop() - if err != nil { - log.Errorf("failed stopping engine %v", err) - return err - } - - return nil + return startCmd.RunE(cmd, args) }, } ) -func init() { -} - // createEngineConfig converts configuration received from Management Service to EngineConfig -func createEngineConfig(key wgtypes.Key, config *internal.Config, wtConfig *mgmProto.WiretrusteeConfig, peerConfig *mgmProto.PeerConfig) (*internal.EngineConfig, error) { +func createEngineConfig(key wgtypes.Key, config *internal.Config, peerConfig *mgmProto.PeerConfig) (*internal.EngineConfig, error) { iFaceBlackList := make(map[string]struct{}) for i := 0; i < len(config.IFaceBlackList); i += 2 { iFaceBlackList[config.IFaceBlackList[i]] = struct{}{} @@ -167,3 +121,84 @@ func connectToManagement(ctx context.Context, managementAddr string, ourPrivateK return client, loginResp, nil } + +func runClient() error { + config, err := internal.ReadConfig(managementURL, configPath) + if err != nil { + log.Errorf("failed reading config %s %v", configPath, err) + return err + } + + //validate our peer's Wireguard PRIVATE key + myPrivateKey, err := wgtypes.ParseKey(config.PrivateKey) + if err != nil { + log.Errorf("failed parsing Wireguard key %s: [%s]", config.PrivateKey, err.Error()) + return err + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + mgmTlsEnabled := false + if config.ManagementURL.Scheme == "https" { + mgmTlsEnabled = true + } + + // connect (just a connection, no stream yet) and login to Management Service to get an initial global Wiretrustee config + mgmClient, loginResp, err := connectToManagement(ctx, config.ManagementURL.Host, myPrivateKey, mgmTlsEnabled) + if err != nil { + log.Warn(err) + return err + } + + // with the global Wiretrustee config in hand connect (just a connection, no stream yet) Signal + signalClient, err := connectToSignal(ctx, loginResp.GetWiretrusteeConfig(), myPrivateKey) + if err != nil { + log.Error(err) + return err + } + + peerConfig := loginResp.GetPeerConfig() + + engineConfig, err := createEngineConfig(myPrivateKey, config, peerConfig) + if err != nil { + log.Error(err) + return err + } + + // create start the Wiretrustee Engine that will connect to the Signal and Management streams and manage connections to remote peers. + engine := internal.NewEngine(signalClient, mgmClient, engineConfig, cancel) + err = engine.Start() + if err != nil { + log.Errorf("error while starting Wiretrustee Connection Engine: %s", err) + return err + } + + log.Print("Wiretrustee engine started, my IP is: ", peerConfig.Address) + + SetupCloseHandler() + + select { + case <-stopCh: + case <-ctx.Done(): + } + + log.Info("shutting down Wiretrustee client") + err = mgmClient.Close() + if err != nil { + log.Errorf("failed closing Management Service client %v", err) + return err + } + err = signalClient.Close() + if err != nil { + log.Errorf("failed closing Signal Service client %v", err) + return err + } + + err = engine.Stop() + if err != nil { + log.Errorf("failed stopping engine %v", err) + return err + } + + return nil +} diff --git a/client/cmd/up_test.go b/client/cmd/up_test.go index 2b8769249..b5a7a8b6d 100644 --- a/client/cmd/up_test.go +++ b/client/cmd/up_test.go @@ -1,13 +1,10 @@ package cmd import ( - "errors" - "fmt" "github.com/wiretrustee/wiretrustee/iface" mgmt "github.com/wiretrustee/wiretrustee/management/server" "github.com/wiretrustee/wiretrustee/util" "net/url" - "os" "path/filepath" "testing" "time" @@ -37,24 +34,6 @@ func TestUp_Start(t *testing.T) { } -func TestUp_ShouldFail_On_NoConfig(t *testing.T) { - - tempDir := t.TempDir() - confPath := tempDir + "/config.json" - mgmtURL := fmt.Sprintf("http://%s", mgmAddr) - rootCmd.SetArgs([]string{ - "up", - "--config", - confPath, - "--management-url", - mgmtURL, - }) - err := rootCmd.Execute() - if err == nil || !errors.Is(err, os.ErrNotExist) { - t.Errorf("expecting login command to fail on absence of config") - } -} - func TestUp(t *testing.T) { defer iface.Close() @@ -65,24 +44,17 @@ func TestUp(t *testing.T) { if err != nil { t.Fatal(err) } + rootCmd.SetArgs([]string{ - "login", + "up", "--config", confPath, "--setup-key", "A2C8E62B-38F5-4553-B31E-DD66C696CEBB", "--management-url", mgmtURL.String(), - }) - err = rootCmd.Execute() - if err != nil { - t.Fatal(err) - } - - rootCmd.SetArgs([]string{ - "up", - "--config", - confPath, + "--log-file", + "console", }) go func() { err = rootCmd.Execute() diff --git a/client/cmd/version.go b/client/cmd/version.go new file mode 100644 index 000000000..dd02eb502 --- /dev/null +++ b/client/cmd/version.go @@ -0,0 +1,14 @@ +package cmd + +import "github.com/spf13/cobra" + +var ( + Version string + versionCmd = &cobra.Command{ + Use: "version", + Short: "prints wiretrustee version", + Run: func(cmd *cobra.Command, args []string) { + cmd.Println(Version) + }, + } +) diff --git a/client/main.go b/client/main.go index 0a85983f1..86b24e735 100644 --- a/client/main.go +++ b/client/main.go @@ -5,7 +5,11 @@ import ( "os" ) +var version = "development" + func main() { + + cmd.Version = version if err := cmd.Execute(); err != nil { os.Exit(1) } diff --git a/go.mod b/go.mod index 011877ec6..76fc3f767 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/golang/protobuf v1.5.2 github.com/google/uuid v1.2.0 github.com/gorilla/mux v1.8.0 - github.com/kardianos/service v1.2.0 + github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7 github.com/onsi/ginkgo v1.16.4 github.com/onsi/gomega v1.13.0 github.com/pion/ice/v2 v2.1.7 diff --git a/go.sum b/go.sum index 13a2b611b..a49ae6965 100644 --- a/go.sum +++ b/go.sum @@ -148,6 +148,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/service v1.2.0 h1:bGuZ/epo3vrt8IPC7mnKQolqFeYJb7Cs8Rk4PSOBB/g= github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= +github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7 h1:oohm9Rk9JAxxmp2NLZa7Kebgz9h4+AJDcc64txg3dQ0= +github.com/kardianos/service v1.2.1-0.20210728001519-a323c3813bc7/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= diff --git a/release_files/post_install.sh b/release_files/post_install.sh index 5471a7abc..6342c3b1d 100644 --- a/release_files/post_install.sh +++ b/release_files/post_install.sh @@ -12,30 +12,25 @@ fi cleanInstall() { printf "\033[32m Post Install of an clean install\033[0m\n" # Step 3 (clean install), enable the service in the proper way for this platform - if [ "${use_systemctl}" = "True" ]; then - printf "\033[32m Reload the service unit from disk\033[0m\n" - systemctl daemon-reload ||: - printf "\033[32m Unmask the service\033[0m\n" - systemctl unmask wiretrustee ||: - printf "\033[32m Set the preset flag for the service unit\033[0m\n" - systemctl preset wiretrustee ||: - printf "\033[32m Set the enabled flag for the service unit\033[0m\n" - systemctl enable wiretrustee ||: - systemctl restart wiretrustee ||: - fi + /usr/local/bin/wiretrustee service install } upgrade() { printf "\033[32m Post Install of an upgrade\033[0m\n" if [ "${use_systemctl}" = "True" ]; then - printf "\033[32m Reload the service unit from disk\033[0m\n" - systemctl daemon-reload ||: - printf "\033[32m Restarting the service\033[0m\n" - systemctl restart wiretrustee ||: + printf "\033[32m Stopping the service\033[0m\n" + systemctl stop wiretrustee fi + if [ -e /lib/systemd/system/wiretrustee.service ]; then + rm -f /lib/systemd/system/wiretrustee.service + systemctl daemon-reload + fi + # will trow an error until everyone upgrade + /usr/local/bin/wiretrustee service uninstall + /usr/local/bin/wiretrustee service install } -# Step 2, check if this is a clean install or an upgrade +# Check if this is a clean install or an upgrade action="$1" if [ "$1" = "configure" ] && [ -z "$2" ]; then # Alpine linux does not pass args, and deb passes $1=configure diff --git a/release_files/pre_remove.sh b/release_files/pre_remove.sh new file mode 100644 index 000000000..6ac324baa --- /dev/null +++ b/release_files/pre_remove.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# decide if we should use systemd or init/upstart +use_systemctl="True" +systemd_version=0 +if ! command -V systemctl >/dev/null 2>&1; then + use_systemctl="False" +else + systemd_version=$(systemctl --version | head -1 | sed 's/systemd //g') +fi + +printf "\033[32m Pre uninstall\033[0m\n" + +if [ "${use_systemctl}" = "True" ]; then + printf "\033[32m Stopping the service\033[0m\n" + systemctl stop wiretrustee + + if [ -e /lib/systemd/system/wiretrustee.service ]; then + rm -f /lib/systemd/system/wiretrustee.service + systemctl daemon-reload + fi + +fi +printf "\033[32m Uninstalling the service\033[0m\n" +/usr/local/bin/wiretrustee service uninstall + + +if [ "${use_systemctl}" = "True" ]; then + printf "\n\033[32m running daemon reload\033[0m\n" + systemctl daemon-reload +fi \ No newline at end of file diff --git a/release_files/wiretrustee.json b/release_files/wiretrustee.json deleted file mode 100644 index d64d7ee38..000000000 --- a/release_files/wiretrustee.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "PrivateKey": "", - "Peers": [ - { - "WgPubKey": "", - "WgAllowedIps": "" - } - ], - "StunTurnURLs": [ - { - "Scheme": 1, - "Host": "", - "Port": 3468, - "Username": "", - "Password": "", - "Proto": 1 - }, - { - "Scheme": 3, - "Host": "", - "Port": 3468, - "Username": "", - "Password": "", - "Proto": 1 - } - ], - "SignalAddr": "", - "WgAddr": "", - "WgIface": "" -} diff --git a/release_files/wiretrustee.service b/release_files/wiretrustee.service deleted file mode 100644 index 97db9be0b..000000000 --- a/release_files/wiretrustee.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Wiretrustee Service -After=multi-user.target network-online.target -Wants=network-online.target - -[Service] -Type=simple -ExecStart=/usr/local/bin/wiretrustee up --config /etc/wiretrustee/config.json --log-level debug -[Install] -WantedBy=multi-user.target \ No newline at end of file