Repository: caddyserver/caddy (language: go)

Issue:
Minimal windows service stub
It would be a nice addition to integrate [Minimal windows service stub](https://pkg.go.dev/github.com/kardianos/minwinsvc) in Caddy (built for Windows).

At the moment, it is necessary to use for example NSSM to install Caddy as a service on Windows.

See how it becomes much more natural to [install the service and remove it in the case of another project (Gitea) with the Windows tools](https://docs.gitea.io/en-us/windows-service/).


Discussion / hints:
FYI, we have instructions for running Caddy as a service here: https://caddyserver.com/docs/running#windows-service
> FYI, we have instructions for running Caddy as a service here: https://caddyserver.com/docs/running#windows-service

Thanks. I didn't know *WinSW*.

Even under NSSM, however, Caddy runs without problems on various Windows installations I have done.

The real problem behind this issue is the extra step that requires the installation of third-party software to make Caddy work as a service.
We're generally wary of adding new dependencies to Caddy, for various reasons.

I think we if we add this, we'd likely just copy code into this project (with attribution of course, as [their licence](https://github.com/kardianos/minwinsvc/blob/master/LICENSE) requires) to avoid the added dependency.

I have no other objections, really. Seems pretty harmless to add otherwise.

Thinking we could put it alongside https://github.com/caddyserver/caddy/tree/master/notify (and maybe rename that package from `notify` to `platform`?)

PRs welcome!
I have did some researches and make an implement for this in: https://github.com/WingLim/caddy/blob/dev/windows-service/notify/notify_windows.go

But there is a problem, when using `service.msc` to stop service, it can not stop gracefully.
The code in here:
https://github.com/WingLim/caddy/blob/dc0b52111c13ecb3ec9eaa3583fe76b8ac62a04a/notify/notify_windows.go#L40

Do you guys have any idea for it?
See sigtrap.go which has the shutdown logic

Fix patch:
diff --git a/caddyconfig/caddyfile/formatter_fuzz.go b/caddyconfig/caddyfile/formatter_fuzz.go
index c07a2268331..7c1fc643928 100644
--- a/caddyconfig/caddyfile/formatter_fuzz.go
+++ b/caddyconfig/caddyfile/formatter_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package caddyfile
 
diff --git a/caddyconfig/caddyfile/lexer_fuzz.go b/caddyconfig/caddyfile/lexer_fuzz.go
index 179fd87c9b6..6f75694b5a0 100644
--- a/caddyconfig/caddyfile/lexer_fuzz.go
+++ b/caddyconfig/caddyfile/lexer_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package caddyfile
 
diff --git a/caddyconfig/httpcaddyfile/addresses_fuzz.go b/caddyconfig/httpcaddyfile/addresses_fuzz.go
index be873ef159d..364ff971b11 100644
--- a/caddyconfig/httpcaddyfile/addresses_fuzz.go
+++ b/caddyconfig/httpcaddyfile/addresses_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package httpcaddyfile
 
diff --git a/cmd/removebinary.go b/cmd/removebinary.go
index adef6b104b9..c74d2b2e212 100644
--- a/cmd/removebinary.go
+++ b/cmd/removebinary.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build !windows
-// +build !windows
 
 package caddycmd
 
diff --git a/duration_fuzz.go b/duration_fuzz.go
index aa01a46a37a..8a1f0c7cba5 100644
--- a/duration_fuzz.go
+++ b/duration_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package caddy
 
diff --git a/go.mod b/go.mod
index c30afdf7ed9..026d06dfbf2 100644
--- a/go.mod
+++ b/go.mod
@@ -121,7 +121,7 @@ require (
 	go.uber.org/atomic v1.9.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	golang.org/x/mod v0.4.2 // indirect
-	golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
+	golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e
 	golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b // indirect
 	golang.org/x/tools v0.1.7 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
diff --git a/listeners_fuzz.go b/listeners_fuzz.go
index 95f1e327157..02b65ab2e19 100644
--- a/listeners_fuzz.go
+++ b/listeners_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package caddy
 
diff --git a/modules/caddyhttp/templates/frontmatter_fuzz.go b/modules/caddyhttp/templates/frontmatter_fuzz.go
index 361b4b62696..7af301312f8 100644
--- a/modules/caddyhttp/templates/frontmatter_fuzz.go
+++ b/modules/caddyhttp/templates/frontmatter_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package templates
 
diff --git a/notify/notify_linux.go b/notify/notify_linux.go
index 8ba49d2cdbc..1e8da742827 100644
--- a/notify/notify_linux.go
+++ b/notify/notify_linux.go
@@ -12,6 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// Package notify provides facilities for notifying process managers
+// of state changes, mainly for when running as a system service.
 package notify
 
 import (
diff --git a/notify/notify_other.go b/notify/notify_other.go
index 6ffec89bd1f..7fc618b7bbb 100644
--- a/notify/notify_other.go
+++ b/notify/notify_other.go
@@ -12,19 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//go:build !linux
-// +build !linux
+//go:build !linux && !windows
 
 package notify
 
-func notifyReadiness() error {
-	return nil
-}
-
-func notifyReloading() error {
-	return nil
-}
-
-func notifyStopping() error {
-	return nil
-}
+func notifyReadiness() error { return nil }
+func notifyReloading() error { return nil }
+func notifyStopping() error  { return nil }
diff --git a/notify/notify_windows.go b/notify/notify_windows.go
new file mode 100644
index 00000000000..a551fc7e41d
--- /dev/null
+++ b/notify/notify_windows.go
@@ -0,0 +1,49 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package notify
+
+import "golang.org/x/sys/windows/svc"
+
+// globalStatus store windows service status, it can be
+// use to notify caddy status.
+var globalStatus chan<- svc.Status
+
+func SetGlobalStatus(status chan<- svc.Status) {
+	globalStatus = status
+}
+
+func notifyReadiness() error {
+	if globalStatus != nil {
+		globalStatus <- svc.Status{
+			State:   svc.Running,
+			Accepts: svc.AcceptStop | svc.AcceptShutdown,
+		}
+	}
+	return nil
+}
+
+func notifyReloading() error {
+	if globalStatus != nil {
+		globalStatus <- svc.Status{State: svc.StartPending}
+	}
+	return nil
+}
+
+func notifyStopping() error {
+	if globalStatus != nil {
+		globalStatus <- svc.Status{State: svc.StopPending}
+	}
+	return nil
+}
diff --git a/replacer_fuzz.go b/replacer_fuzz.go
index a837e33f859..50fb0b61107 100644
--- a/replacer_fuzz.go
+++ b/replacer_fuzz.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build gofuzz
-// +build gofuzz
 
 package caddy
 
diff --git a/service_windows.go b/service_windows.go
new file mode 100644
index 00000000000..7590fc3ca53
--- /dev/null
+++ b/service_windows.go
@@ -0,0 +1,49 @@
+// Copyright 2015 Matthew Holt and The Caddy Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package caddy
+
+import (
+	"github.com/caddyserver/caddy/v2/notify"
+	"golang.org/x/sys/windows/svc"
+)
+
+func init() {
+	isService, err := svc.IsWindowsService()
+	if err != nil || isService {
+		return
+	}
+	go func() {
+		_ = svc.Run("", runner{})
+	}()
+}
+
+type runner struct{}
+
+func (runner) Execute(args []string, request <-chan svc.ChangeRequest, status chan<- svc.Status) (bool, uint32) {
+	notify.SetGlobalStatus(status)
+	status <- svc.Status{State: svc.StartPending}
+
+	for {
+		req := <-request
+		switch req.Cmd {
+		case svc.Interrogate:
+			status <- req.CurrentStatus
+		case svc.Stop, svc.Shutdown:
+			status <- svc.Status{State: svc.StopPending}
+			exitProcessFromSignal("SIGINT")
+			return false, 0
+		}
+	}
+}
diff --git a/sigtrap_nonposix.go b/sigtrap_nonposix.go
index 7855e13a548..f80f593b03d 100644
--- a/sigtrap_nonposix.go
+++ b/sigtrap_nonposix.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build windows || plan9 || nacl || js
-// +build windows plan9 nacl js
 
 package caddy
 
diff --git a/sigtrap_posix.go b/sigtrap_posix.go
index 706d0c257cc..7033f16357e 100644
--- a/sigtrap_posix.go
+++ b/sigtrap_posix.go
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 //go:build !windows && !plan9 && !nacl && !js
-// +build !windows,!plan9,!nacl,!js
 
 package caddy
 


Test patch: