Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(caddy): add Caddy support for Outline services #198

Merged
merged 234 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 207 commits
Commits
Show all changes
234 commits
Select commit Hold shift + click to select a range
1b82d33
Create a new config format so we can expand listener configuration fo…
sbruens May 31, 2024
a4c2007
Remove unused `fakeAddr`.
sbruens May 31, 2024
72b27d7
Split `startPort` up between TCP and UDP.
sbruens Jun 3, 2024
fddfc57
Use listeners to configure TCP and/or UDP services as needed.
sbruens Jun 3, 2024
c1ee12f
Remove commented out line.
sbruens Jun 3, 2024
354301e
Use `ElementsMatch` to compare the services irrespective of element o…
sbruens Jun 3, 2024
751d164
Do not ignore the `keys` field if `services` is used as well.
sbruens Jun 12, 2024
6297304
Add some more tests for failure scenarios and empty files.
sbruens Jun 12, 2024
0ac0a72
Remove unused `GetPort()`.
sbruens Jun 12, 2024
794f860
Move `ResolveAddr` to config.go.
sbruens Jun 12, 2024
01b7e8a
Remove use of `net.Addr` type.
sbruens Jun 12, 2024
87a1565
Pull listener creation into its own function.
sbruens Jun 12, 2024
51a13a7
Move listener validation/creation to `config.go`.
sbruens Jun 14, 2024
f8d7aa5
Use a custom type for listener type.
sbruens Jun 14, 2024
1952036
Fix accept handler.
sbruens Jun 14, 2024
7212265
Add doc comment.
sbruens Jun 14, 2024
6e2068d
Fix tests still supplying the port.
sbruens Jun 14, 2024
7114434
Move old config parsing to `loadConfig`.
sbruens Jun 14, 2024
1b2dd42
Lowercase `readConfig`.
sbruens Jun 14, 2024
4ce06f0
Use `Config` suffix for config types.
sbruens Jun 21, 2024
8660032
Remove the IP version specifiers from the `newListener` config handling.
sbruens Jun 21, 2024
26b9100
refactor: remove use of port in proving metric
sbruens Jun 21, 2024
1b8e903
Fix tests.
sbruens Jun 21, 2024
442b927
Merge branch 'sbruens/absorb-port' into sbruens/proxy
sbruens Jun 21, 2024
4216ce3
Add a TODO comment to allow short-form direct listener config.
sbruens Jun 21, 2024
35c828d
Make legacy key config name consistent with type.
sbruens Jun 21, 2024
1322f2d
Move config validation out of the `loadConfig` function.
sbruens Jun 21, 2024
adc11f2
Remove unused port from bad merge.
sbruens Jun 21, 2024
3084dfd
Add comment describing keys.
sbruens Jun 24, 2024
7e5aae5
Move validation of listeners to config's `Validate()` function.
sbruens Jun 24, 2024
b136c79
Introduce a `NetworkAdd` to centralize parsing and creation of listen…
sbruens Jun 25, 2024
4bf9c27
Use `net.ListenConfig` to listen.
sbruens Jun 24, 2024
b7bb65b
Simplify how we create new listeners.
sbruens Jun 25, 2024
af3ca31
Do not use `io.Closer`.
sbruens Jun 28, 2024
fc72593
Use an inline error check.
sbruens Jul 1, 2024
b24a339
Use shared listeners and packet connections.
sbruens Jul 1, 2024
3bc76bc
Close existing listeners once the new ones are serving.
sbruens Jul 1, 2024
f71b13d
Elevate failure to stop listeners to `ERROR` level.
sbruens Jul 1, 2024
6893e2a
Merge remote-tracking branch 'origin/master' into sbruens/proxy
sbruens Jul 2, 2024
32cc180
Be more lenient in config validation to allow empty listeners or keys.
sbruens Jul 2, 2024
640f80f
Ensure the address is an IP address.
sbruens Jul 3, 2024
22638c7
Use `yaml.v3`.
sbruens Jul 3, 2024
2631b87
Move file reading back to `main.go`.
sbruens Jul 8, 2024
d76efd2
Do not embed the `net.Listener` type.
sbruens Jul 8, 2024
b8c5ab8
Use a `Service` object to abstract away some of the complex logic of …
sbruens Jul 8, 2024
5ac0f46
Fix how we deal with legacy services.
sbruens Jul 8, 2024
1f097be
Remove commented out lines.
sbruens Jul 8, 2024
80b25b1
Use `tcp` and `udp` types for direct listeners.
sbruens Jul 8, 2024
2070d40
Use a `ListenerManager` instead of globals to manage listener state.
sbruens Jul 8, 2024
eacfa0e
Add validation check that no two services have the same listener.
sbruens Jul 8, 2024
dc1075a
Use channels to notify shared listeners they need to stop acceoting.
sbruens Jul 10, 2024
2a343e2
Pass TCP timeout to service.
sbruens Jul 10, 2024
e58b79d
Move go routine call up.
sbruens Jul 10, 2024
c7465fb
Allow inserting single elements directly into the cipher list.
sbruens Jul 11, 2024
43fa0d6
Add the concept of a listener set to track existing listeners and clo…
sbruens Jul 11, 2024
cf9b7d2
Refactor how we create listeners.
sbruens Jul 11, 2024
ae7f41d
Update comments.
sbruens Jul 11, 2024
120db8e
`go mod tidy`.
sbruens Jul 11, 2024
5cbeb54
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Jul 11, 2024
d705603
refactor: don't link the TCP handler to a specific listener
sbruens Jul 16, 2024
2fb4a6b
Merge branch 'sbruens/remove-listener-dependency' into sbruens/shared…
sbruens Jul 16, 2024
d2ef46e
Protect new cipher handling methods with mutex.
sbruens Jul 16, 2024
ab07400
Move `listeners.go` under `/service`.
sbruens Jul 16, 2024
71d7140
Use callback instead of passing in key and manager.
sbruens Jul 16, 2024
9dfa4e2
Move config start into a go routine for easier cleanup.
sbruens Jul 16, 2024
0a63f5c
Make a `StreamListener` type.
sbruens Jul 19, 2024
f018d17
Rename `closeFunc` to `onCloseFunc`.
sbruens Jul 19, 2024
4295c45
Rename `globalListener`.
sbruens Jul 19, 2024
e6963f6
Don't track usage in the shared listeners.
sbruens Jul 19, 2024
7113f02
Add `getAddr()` to avoid some duplicate code.
sbruens Jul 19, 2024
e4d679f
Move listener set creation out of the inner function.
sbruens Jul 22, 2024
be5f9b0
Remove `PushBack()` from `CipherList`.
sbruens Jul 22, 2024
343e412
Move listener set to `main.go`.
sbruens Jul 22, 2024
7f86ff1
Close the accept channel with an atomic value.
sbruens Jul 22, 2024
e80b2c5
Update comment.
sbruens Jul 22, 2024
b1428ed
Address review comments.
sbruens Jul 22, 2024
1c16de8
Close before deleting key.
sbruens Jul 22, 2024
ebc7053
`server.Stop()` does not return a value
sbruens Jul 22, 2024
67fc7fb
Add a comment for `StreamListener`.
sbruens Jul 22, 2024
7a15e7d
Do not delete the listener from the manager until the last user has c…
sbruens Jul 22, 2024
499829e
Consolidate usage counting inside a `listenAddress` type.
sbruens Jul 22, 2024
f165dbd
Remove `atomic.Value`.
sbruens Jul 22, 2024
2a2420a
Add some missing comments.
sbruens Jul 22, 2024
8178d78
Merge branch 'master' into sbruens/shared-listeners
sbruens Jul 25, 2024
cccba1a
address review comments
sbruens Jul 25, 2024
da4ccaa
Add type guard for `sharedListener`.
sbruens Jul 25, 2024
d47f612
Stop the existing config in a goroutine.
sbruens Jul 25, 2024
a928e2c
Add a TODO to wait for all handlers to be stopped.
sbruens Jul 25, 2024
98cc3a0
Run `stopConfig` in a goroutine in `Stop()` as well.
sbruens Jul 25, 2024
48d0931
Create a `TCPListener` that implements a `StreamListener`.
sbruens Jul 25, 2024
2dec847
Track close functions instead of the entire listener, which is not ne…
sbruens Jul 25, 2024
ab22e47
Delegate usage tracking to a reference counter.
sbruens Jul 30, 2024
3c2a3ef
Remove the `Get()` method from `refCount`.
sbruens Jul 31, 2024
5e282f1
Return immediately.
sbruens Jul 31, 2024
547e9e6
Rename `shared` to `virtual` as they are not actually shared.
sbruens Jul 31, 2024
c6774c8
Simplify `listenAddr`.
sbruens Jul 31, 2024
df2f9d0
Fix use of the ref count.
sbruens Jul 31, 2024
c678372
Add simple test case for early closing of stream listener.
sbruens Jul 31, 2024
e41abab
Add tests for creating stream listeners.
sbruens Jul 31, 2024
b626a1c
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Jul 31, 2024
f9432d2
Create handlers on demand.
sbruens Jul 31, 2024
6b11f4f
Refactor create methods.
sbruens Aug 2, 2024
3e03394
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Aug 2, 2024
fe8bbdd
Address review comments.
sbruens Aug 5, 2024
36a0a1d
Use a mutex to ensure another user doesn't acquire a new closer while…
sbruens Aug 5, 2024
aeb2652
Move mutex up.
sbruens Aug 6, 2024
8873b10
Manage the ref counting next to the listener creation.
sbruens Aug 6, 2024
899d13d
Do the lazy initialization inside an anonymous function.
sbruens Aug 6, 2024
80e5d49
Fix concurrent access to `acceptCh` and `closeCh`.
sbruens Aug 7, 2024
aa00f2e
Use `/` in key instead of `-`.
sbruens Aug 7, 2024
e658b90
Return error from stopping listeners.
sbruens Aug 7, 2024
fede4d8
Use channels to ensure `virtualPacketConn`s get closed.
sbruens Aug 7, 2024
4730d74
Add more test cases for packet listeners.
sbruens Aug 7, 2024
30bbdfa
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Aug 7, 2024
458cf41
Only log errors from stopping old configs.
sbruens Aug 9, 2024
81bf20e
Remove the `closed` field from the virtual listeners.
sbruens Aug 9, 2024
53b1e96
Remove the `RefCount`.
sbruens Aug 9, 2024
8f9f1ea
Implement channel-based packet read for virtual connections.
sbruens Aug 9, 2024
1ac265d
Use a done channel.
sbruens Aug 9, 2024
f5afdcb
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Aug 9, 2024
1538a9a
Set listeners and `onCloseFunc`'s to nil when closing.
sbruens Aug 14, 2024
4df0b9f
Set `onCloseFunc`'s to nil when closing.
sbruens Aug 14, 2024
16feaf9
Fix race condition.
sbruens Aug 14, 2024
288b88b
Add some benchmarks for listener manager.
sbruens Aug 14, 2024
de64b8a
Add structure logging with `slog`.
sbruens Aug 15, 2024
38602b5
Structure forgotten log.
sbruens Aug 16, 2024
56c7b11
Another forgotten log.
sbruens Aug 16, 2024
27e28c7
Remove IPInfo logic from TCP and UDP handling into the metrics collec…
sbruens Aug 16, 2024
8df1dd3
Refactor metrics into separate collectors.
sbruens Aug 16, 2024
e6334e1
Rename some types to remove `Collector` suffix.
sbruens Aug 16, 2024
1565ab5
Use an LRU cache to manage the ipInfos for Prometheus metrics.
sbruens Aug 19, 2024
d80ba6a
Use `nil` instead of `context.TODO()`.
sbruens Aug 19, 2024
30a285e
Use `LogAttrs` for `debug...()` log functions.
sbruens Aug 19, 2024
2748d55
Merge branch 'sbruens/slog' into sbruens/metrics
sbruens Aug 19, 2024
5233167
Update logging in `metrics.go`.
sbruens Aug 19, 2024
2f5077e
Merge branch 'master' into sbruens/metrics
sbruens Aug 19, 2024
feb30b6
Fix another race condition.
sbruens Aug 19, 2024
b74f5a0
Revert renaming.
sbruens Aug 19, 2024
dcc99f6
Replace LRU cache with a simpler map that expires unused items.
sbruens Aug 19, 2024
26c4624
Move `SetBuildInfo()` call up.
sbruens Aug 19, 2024
80fe8d3
refactor: change `outlineMetrics` to implement the `prometheus.Collec…
sbruens Aug 19, 2024
18ad469
Merge branch 'sbruens/prom-collectors' into sbruens/metrics
sbruens Aug 19, 2024
d688dd9
Merge branch 'master' into sbruens/shared-listeners
sbruens Aug 21, 2024
c702159
Merge branch 'sbruens/shared-listeners' into sbruens/proxy
sbruens Aug 21, 2024
e509d86
Address review comments.
sbruens Aug 21, 2024
2c57ad3
Merge branch 'sbruens/prom-collectors' into sbruens/metrics
sbruens Aug 22, 2024
9399e95
Refactor collectors so the connections/associations keep track of the…
sbruens Aug 22, 2024
573d5f2
Merge branch 'master' into sbruens/prom-collectors
sbruens Aug 28, 2024
c7df66d
Merge branch 'sbruens/prom-collectors' into sbruens/metrics
sbruens Aug 28, 2024
dcc47cf
Address review comments.
sbruens Aug 28, 2024
f7fb25d
Make metrics interfaces for bytes consistently use `int64`.
sbruens Aug 28, 2024
e9739b8
Merge branch 'master' into sbruens/proxy
sbruens Aug 28, 2024
cf5a676
Add license header.
sbruens Aug 28, 2024
0a8fbd0
Merge branch 'master' into sbruens/metrics
sbruens Aug 28, 2024
3becca2
Merge branch 'master' into sbruens/proxy
sbruens Aug 28, 2024
c5937b5
Merge branch 'sbruens/metrics' into sbruens/caddy2
sbruens Aug 29, 2024
0e55a6f
Support multi-module workspaces so we can develop Caddy and ss-server…
sbruens Aug 29, 2024
74d3c67
Rename `Collector` to `Metrics`.
sbruens Aug 29, 2024
3b02104
Merge branch 'sbruens/metrics' into sbruens/caddy2
sbruens Aug 29, 2024
0f12feb
Merge branch 'master' into sbruens/caddy2
sbruens Aug 31, 2024
7c061e4
Move service creation into the service package so it can be re-used b…
sbruens Aug 31, 2024
76e320e
Ignore custom Caddy binary.
sbruens Aug 31, 2024
469a18b
Merge branch 'master' into sbruens/caddy
sbruens Sep 4, 2024
e80ccc3
refactor: create re-usable service that can be re-used by Caddy
sbruens Sep 6, 2024
6e330fa
Remove need to return errors in opt functions.
sbruens Sep 6, 2024
2738b45
Move the service into `shadowsocks.go`.
sbruens Sep 6, 2024
2270f6c
Merge branch 'sbruens/service' into sbruens/caddy
sbruens Sep 6, 2024
8935465
Add Caddy module with app and handler.
sbruens Sep 9, 2024
2073a27
Refactor metrics to not share with Caddy.
sbruens Sep 9, 2024
0dfafcb
Set Prometheus metrics handler.
sbruens Sep 9, 2024
e2cc62f
Catch already registered collectors instead of using `once.Sync`.
sbruens Sep 9, 2024
654e0e9
refactor: pass in logger to service so caller can control logs
sbruens Sep 9, 2024
3b6c873
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 9, 2024
be43e84
Fix test.
sbruens Sep 9, 2024
bca42a0
Add `--watch` flag to README.
sbruens Sep 9, 2024
62206c8
Remove changes moved to another PR.
sbruens Sep 9, 2024
d284612
Remove arguments from `Logger()`.
sbruens Sep 10, 2024
04faca2
Use `slog` instead of `zap`.
sbruens Sep 10, 2024
46e2f66
Log error in `Provision()` instead of `defineMetrics()`.
sbruens Sep 10, 2024
a32378e
Do not panic on bad metrics registrations.
sbruens Sep 10, 2024
f2b1b6f
Check if the cast to `OutlineApp` is ok.
sbruens Sep 10, 2024
ac98ed9
Remove `version` from the config.
sbruens Sep 10, 2024
40ff316
Use `outline_` prefix for Caddy metrics.
sbruens Sep 10, 2024
f998612
Remove unused `NatTimeoutSec` config option.
sbruens Sep 10, 2024
e6686d1
Move initialization of handlers to the constructor.
sbruens Sep 11, 2024
1259af8
Pass a `list.List` instead of a `CipherList`.
sbruens Sep 11, 2024
3a64e35
Rename `SSServer` to `OutlineServer`.
sbruens Sep 11, 2024
39da61b
refactor: make connection metrics optional
sbruens Sep 12, 2024
28cc6c7
Merge branch 'master' into sbruens/logger
sbruens Sep 16, 2024
48796e1
Make setting the logger a setter function.
sbruens Sep 16, 2024
68c095f
Merge branch 'master' into sbruens/service
sbruens Sep 16, 2024
9d126f9
Revert "Pass a `list.List` instead of a `CipherList`."
sbruens Sep 16, 2024
213903d
Create noop metrics if nil.
sbruens Sep 16, 2024
e5e8549
Revert some more changes.
sbruens Sep 16, 2024
724260e
Use a noop metrics struct if no metrics provided.
sbruens Sep 16, 2024
655c3cc
Add noop implementation for `ShadowsocksConnMetrics`.
sbruens Sep 16, 2024
7480f3c
Merge branch 'sbruens/service' into sbruens/logger
sbruens Sep 16, 2024
fd04a2b
Move logger arg.
sbruens Sep 16, 2024
aa3f70f
Merge branch 'sbruens/service' into sbruens/logger
sbruens Sep 16, 2024
c2bae13
Resolve nil metrics.
sbruens Sep 16, 2024
e336213
Merge branch 'sbruens/optional-metrics' into sbruens/service
sbruens Sep 16, 2024
00d9b84
Merge branch 'sbruens/service' into sbruens/logger
sbruens Sep 16, 2024
24d97f9
Merge branch 'master' into sbruens/service
sbruens Sep 16, 2024
082859f
Merge branch 'sbruens/service' into sbruens/logger
sbruens Sep 16, 2024
d3e6027
Set logger explicitly to `noopLogger` in service creation.
sbruens Sep 16, 2024
12de843
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 17, 2024
bb19080
Address review comments.
sbruens Sep 17, 2024
7d8892c
Set `noopLogger` in `NewShadowsocksStreamAuthenticator()` if nil.
sbruens Sep 18, 2024
f6dd019
Merge branch 'master' into sbruens/logger
sbruens Sep 18, 2024
53ddc31
Fix logger reference.
sbruens Sep 18, 2024
44563eb
Merge branch 'master' into sbruens/logger
sbruens Sep 18, 2024
c98d9d7
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 18, 2024
6463406
Add TODO comment to persist replay cache.
sbruens Sep 18, 2024
72c635c
Remove use of zap.
sbruens Sep 18, 2024
5849c1e
Use a `ModuleRegistration` approach as per review comments.
sbruens Sep 19, 2024
8ef6247
Add regression test that covers the issue.
sbruens Sep 20, 2024
aafb802
Fix the test.
sbruens Sep 20, 2024
7e9f6f4
Use consistent comments.
sbruens Sep 20, 2024
88bf8cb
Merge branch 'sbruens/udp-buffer' into sbruens/caddy
sbruens Sep 20, 2024
2f3393e
Use a `noopLogger` if `SetLogger()` is called with `nil`.
sbruens Sep 20, 2024
9b1b801
Update tests.
sbruens Sep 20, 2024
5e2c496
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 20, 2024
1220437
Remove empty newline.
sbruens Sep 20, 2024
425568e
Update `outline-ss-server` and remove now unused `zap`.
sbruens Sep 20, 2024
3aebc3e
Merge branch 'master' into sbruens/caddy
sbruens Sep 20, 2024
9675391
Update `outline-ss-server`.
sbruens Sep 20, 2024
3af803b
Use concrete `slog.Logger` instead of `Logger` interface now that we …
sbruens Sep 23, 2024
030b557
Move `WithLogger()` down.
sbruens Sep 23, 2024
b5a1ea6
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 23, 2024
22b6f97
Remove `nil` check.
sbruens Sep 23, 2024
a5a2e4a
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 23, 2024
12a0c90
Use `math.MaxInt` to make sure no error log records are created.
sbruens Sep 23, 2024
4c7f6fd
Merge branch 'sbruens/logger' into sbruens/caddy
sbruens Sep 23, 2024
89cfd5d
Merge branch 'master' into sbruens/caddy
sbruens Sep 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@
# Go workspace
go.work
go.work.sum

# Custom caddy binary
/caddy/caddy
25 changes: 25 additions & 0 deletions caddy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Caddy Module

The Caddy module provides an app and handler for Caddy Server
(https://caddyserver.com/) allowing it to turn any Caddy Server into an Outline
Shadowsocks backend.

## Prerequisites

- [xcaddy](https://github.com/caddyserver/xcaddy)

## Usage

From this directory, build and run a custom binary with `xcaddy`:

```sh
xcaddy run --config config_example.json --watch
```

In a separate window, confirm you can fetch a page using this server:

```sh
go run github.com/Jigsaw-Code/outline-sdk/x/examples/fetch -transport "ss://chacha20-ietf-poly1305:Secret1@:9000" http://ipinfo.io
```

Prometheus metrics are available on http://localhost:9091/metrics.
130 changes: 130 additions & 0 deletions caddy/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright 2024 The Outline 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 provides an app and handler for Caddy Server (https://caddyserver.com/)
// allowing it to turn any handler into one supporting the Vulcain protocol.

package caddy

import (
"errors"
"log/slog"

outline_prometheus "github.com/Jigsaw-Code/outline-ss-server/prometheus"
outline "github.com/Jigsaw-Code/outline-ss-server/service"
"github.com/caddyserver/caddy/v2"
"github.com/prometheus/client_golang/prometheus"
)

func init() {
sbruens marked this conversation as resolved.
Show resolved Hide resolved
caddy.RegisterModule(OutlineApp{})
}

const outlineModuleName = "outline"

type ShadowsocksConfig struct {
ReplayHistory int `json:"replay_history,omitempty"`
}

type OutlineApp struct {
ShadowsocksConfig *ShadowsocksConfig `json:"shadowsocks,omitempty"`

ReplayCache outline.ReplayCache
logger *slog.Logger
Metrics outline.ServiceMetrics
buildInfo *prometheus.GaugeVec
}

var (
_ caddy.App = (*OutlineApp)(nil)
_ caddy.Provisioner = (*OutlineApp)(nil)
)

func (OutlineApp) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: outlineModuleName,
New: func() caddy.Module { return new(OutlineApp) },
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something seems wrong here. Is OutlineApp both an App and a Module?
You create an OutlineApp to then create another OutlineApp? That's a circular dependency and looks like a bug.

Copy link

@fortuna fortuna Sep 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API is so broken... I think we should create something like:

type ModuleRegistration caddy.ModuleInfo

func (m ModuleRegistration) CaddyModule() caddy.ModuleInfo {
  return m
}

func init() {
  caddy.RegisterModule(ModuleRegistration{
    ID: "outline"
    New: func() caddy.Module { return new(OutlineApp) }
  })
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something seems wrong here. Is OutlineApp both an App and a Module?

In Caddy apps are modules. So yes, OutlineApp is both an App and a Module.

You create an OutlineApp to then create another OutlineApp? That's a circular dependency and looks like a bug.

Yeah it's a bit of an odd API. I don't think we can get around it though; OutlineApp must implement caddy.Module.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline. I misunderstood the suggestion. Will split them out.

Copy link

@fortuna fortuna Sep 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, this API is so bad. Typical global registration badness, unfortunately... I had to deal with that a lot at Google.

I would still take the ModuleRegistration approach, and change OutlineApp to have a constructor that takes the replayCache as input. This is a more extensible approach and doesn't confuse the OutlineApp lifecycle (otherwise you have two OutlineApp objects!).

In order to do that, I think you will need to add a dummy CaddyModule() method to OutlineApp so the compiler doesn't complain, but that can just log error and return.

}
}

// Provision sets up Outline.
func (app *OutlineApp) Provision(ctx caddy.Context) error {
app.logger = ctx.Slogger()

app.logger.Info("provisioning app instance")

if app.ShadowsocksConfig != nil {
app.ReplayCache = outline.NewReplayCache(app.ShadowsocksConfig.ReplayHistory)
sbruens marked this conversation as resolved.
Show resolved Hide resolved
}

if err := app.defineMetrics(); err != nil {
app.logger.Error("failed to define Prometheus metrics", "err", err)
}
// TODO: Set version at build time.
app.buildInfo.WithLabelValues("dev").Set(1)
// TODO: Add replacement metrics for `shadowsocks_keys` and `shadowsocks_ports`.

return nil
}

func (app *OutlineApp) defineMetrics() error {
r := prometheus.WrapRegistererWithPrefix("outline_", prometheus.DefaultRegisterer)

var err error
buildInfo := prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "build_info",
Help: "Information on the outline-ss-server build",
}, []string{"version"})
app.buildInfo, err = registerCollector(r, buildInfo)
if err != nil {
return err
}

// TODO: Allow the configuration of ip2info.
metrics, err := outline_prometheus.NewServiceMetrics(nil)
if err != nil {
return err
}
app.Metrics, err = registerCollector(r, metrics)
if err != nil {
return err
}
return nil
}

func registerCollector[T prometheus.Collector](registerer prometheus.Registerer, coll T) (T, error) {
if err := registerer.Register(coll); err != nil {
are := &prometheus.AlreadyRegisteredError{}
if !errors.As(err, are) {
// This collector has been registered before. This is expected during a config reload.
coll = are.ExistingCollector.(T)
} else {
// Something else went wrong.
return coll, err
}
}
return coll, nil
}

// Start starts the App.
func (app *OutlineApp) Start() error {
app.logger.Debug("started app instance")
sbruens marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

// Stop stops the App.
func (app *OutlineApp) Stop() error {
app.logger.Debug("stopped app instance")
return nil
}
97 changes: 97 additions & 0 deletions caddy/config_example.json
sbruens marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"admin": {
"disabled": true
},
"logging": {
"logs": {
"default": {"level":"DEBUG", "encoder": {"format":"console"}}
}
},
"apps": {
"http": {
"servers": {
"": {
"listen": [
":9091"
],
"routes": [
{
"match": [
{
"path": [
"/metrics"
]
}
],
"handle": [
{
"disable_openmetrics": true,
"handler": "metrics"
}
]
}
]
}
}
},
"layer4": {
"servers": {

"1": {
"listen": [
"tcp/[::]:9000",
"udp/[::]:9000"
],
"routes": [
{
"handle": [
{
"handler": "shadowsocks",
"keys": [
{
"id": "user-0",
"cipher": "chacha20-ietf-poly1305",
"secret": "Secret0"
},
{
"id": "user-1",
"cipher": "chacha20-ietf-poly1305",
"secret": "Secret1"
}
]
}
]
}
]
},
"2": {
"listen": [
"tcp/[::]:9001",
"udp/[::]:9001"
],
"routes": [
{
"handle": [
{
"handler": "shadowsocks",
"keys": [
{
"id": "user-2",
"cipher": "chacha20-ietf-poly1305",
"secret": "Secret2"
}
]
}
]
}
]
}
}
},
"outline": {
"shadowsocks": {
"replay_history": 10000
}
}
}
}
123 changes: 123 additions & 0 deletions caddy/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
module github.com/Jigsaw-Code/outline-ss-server/caddy

go 1.23

require (
github.com/Jigsaw-Code/outline-sdk v0.0.16
github.com/Jigsaw-Code/outline-ss-server v1.6.0
github.com/caddyserver/caddy/v2 v2.8.4
github.com/mholt/caddy-l4 v0.0.0-20240812213304-afa78d72257b
github.com/prometheus/client_golang v1.20.0
go.uber.org/zap v1.27.0
)

require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/caddyserver/certmagic v0.21.3 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-kit/kit v0.13.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/glog v1.2.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.20.1 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/libdns/libdns v0.2.2 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/acmez/v2 v2.0.1 // indirect
github.com/miekg/dns v1.1.59 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/onsi/ginkgo/v2 v2.15.0 // indirect
github.com/oschwald/geoip2-golang v1.8.0 // indirect
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.44.0 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shadowsocks/go-shadowsocks2 v0.1.5 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/slackhq/nebula v1.7.2 // indirect
github.com/smallstep/certificates v0.26.1 // indirect
github.com/smallstep/nosql v0.6.1 // indirect
github.com/smallstep/pkcs7 v0.0.0-20231024181729-3b98ecc1ca81 // indirect
github.com/smallstep/scep v0.0.0-20231024192529-aee96d7ad34d // indirect
github.com/smallstep/truststore v0.13.0 // indirect
github.com/spf13/cast v1.5.1 // indirect
github.com/spf13/cobra v1.8.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/tailscale/tscert v0.0.0-20240517230440-bbccfbf48933 // indirect
github.com/urfave/cli v1.22.14 // indirect
github.com/zeebo/blake3 v0.2.3 // indirect
go.etcd.io/bbolt v1.3.9 // indirect
go.step.sm/cli-utils v0.9.0 // indirect
go.step.sm/crypto v0.45.0 // indirect
go.step.sm/linkedca v0.20.1 // indirect
go.uber.org/automaxprocs v1.5.3 // indirect
go.uber.org/mock v0.4.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap/exp v0.2.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20240507223354-67b13616a595 // indirect
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6 // indirect
google.golang.org/grpc v1.63.2 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
howett.net/plist v1.0.0 // indirect
)
Loading
Loading