Compare commits

..

24 commits

Author SHA1 Message Date
Sarah Laplante
de566bfc9f
chore: upgrade lib versions for quay security scanner (#1704)
Some checks are pending
Build and Test / Lint (push) Waiting to run
Build and Test / Shadowbox (push) Blocked by required conditions
Build and Test / Shadowbox (arm64) (push) Blocked by required conditions
Build and Test / Manual Install Script (push) Waiting to run
Build and Test / Metrics Server (push) Blocked by required conditions
Build and Test / Sentry Webhook (push) Blocked by required conditions
CodeQL analysis / Analyze (push) Waiting to run
License checks / license-check (push) Waiting to run
* upgrade lib versions for quay security scanner

* update image version

* upgrade go to latest stable 1.26.3
2026-05-13 10:50:59 +02:00
Sarah Laplante
38eca18e93
Merge pull request #1700 from oceanapplications/master
chore(server): port shadowbox Docker image to arm64
2026-04-14 16:43:34 +02:00
Sean Baker
847d66f8e4 Use original test 2026-04-07 19:39:31 +08:00
Sean Baker
eb1ae915a8 Update build_and_test_debug.yml
Use go.mod
2026-04-07 18:44:45 +08:00
Sean Baker
1f1c03cfc4 Update build_and_test_debug.yml 2026-04-07 08:33:54 +08:00
Sean Baker
23e468b434 Skip Chromium install on arm64
Tests passing on ACT
2026-04-06 23:20:18 +08:00
Sean Baker
fa185b0f90 Added support for MacOS and Linux ARM64 2026-03-25 14:49:02 -06:00
Sarah Laplante
326b527d0f
Merge pull request #1690 from OutlineFoundation/new-watchtower
fix(server): switch to maintained watchtower fork
2026-02-23 15:39:42 +01:00
J. Yi
f9ea8edbb5
chore: update Jigsaw-Code references to OutlineFoundation (#1693) 2026-01-08 13:03:17 -05:00
Sarah Laplante
db19f85194 switch from github name to container name 2026-01-07 16:58:54 +01:00
Sarah Laplante
48d336d95b switch to maintained watchtower fork 2026-01-07 16:58:54 +01:00
Sarah Laplante
3370399012
Merge pull request #1691 from OutlineFoundation/update-name-linter
chore: update PR name linter
2026-01-07 16:58:08 +01:00
Sarah Laplante
3d2ce1f93e revert to node 18 2026-01-06 14:02:14 +01:00
Sarah Laplante
846c0685c3 update node version 2026-01-06 13:43:10 +01:00
Sarah Laplante
9b44fe58b1 update PR name linter 2026-01-06 13:38:45 +01:00
Daniel LaCosse
26803710c9
chore(server): remove bandwidth spot query (#1656) 2025-03-31 11:02:33 -04:00
Sander Bruens
4f59eea8a9
chore(server): update Prometheus to LTS (#1655)
* chore(server): update Prometheus to LTS

* Add arm64 archives.
2025-03-21 11:58:19 -04:00
dependabot[bot]
0bfa80262c
chore: bump braces from 3.0.2 to 3.0.3 (#1559)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 14:03:06 -04:00
dependabot[bot]
9dbfc44a06
chore: bump golang.org/x/crypto from 0.18.0 to 0.31.0 (#1625)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.18.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.18.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-19 13:23:27 -04:00
Sander Bruens
9013feafa7
chore(server): set Content-Type header (#1651) 2025-03-10 14:25:18 -04:00
Sander Bruens
d9aa8560ce
ci(sentry_webhook): pin Ubuntu due to Chromium bug (via Puppeteer) (#1652) 2025-03-04 20:24:13 -05:00
Sander Bruens
067d0d47ae
revert(server): revert upgrade of outline-ss-server version (#1645)
* Revert "fix(server): set empty IP to bind on all available networks (#1640)"

This reverts commit 47f24520d3.

* Revert "refactor(server): use the new service config format (#1628)"

This reverts commit 13f62390bf.
2025-02-24 18:07:13 -05:00
Daniel LaCosse
d262f5242f
feat: cache recent prometheus queries in memory (#1643)
* [DO NOT MERGE] prometheus query timer

* add cache layer

* add query result data

* ready for a look

* remove logger
2025-02-21 17:00:59 -05:00
Sander Bruens
15a9e54e5e
refactor(server): use a reusable http.Agent (#1644) 2025-02-21 16:15:14 -05:00
23 changed files with 291 additions and 297 deletions

2
.github/CODEOWNERS vendored
View file

@ -1,4 +1,4 @@
* @Jigsaw-Code/outline-dev
* @OutlineFoundation/outline-dev
/src/server_manager/model/ @fortuna
/src/shadowbox/ @fortuna

View file

@ -43,8 +43,16 @@ jobs:
node-version: 18
cache: npm
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Install NPM Dependencies
run: npm ci
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true'
- name: Lint
run: ./task lint
@ -81,6 +89,40 @@ jobs:
files: |
src/shadowbox/server/api.yml
shadowbox-arm64:
name: Shadowbox (arm64)
runs-on: ubuntu-22.04-arm
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 18
cache: npm
- name: Install Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: false
- name: Install NPM Dependencies
run: npm ci
env:
PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true'
- name: Shadowbox Debug Build (arm64)
run: TARGET_ARCH=aarch64 ./task shadowbox:build
- name: Shadowbox Unit Test
run: ./task shadowbox:test
- name: Shadowbox Docker Build (arm64)
run: TARGET_ARCH=aarch64 ./task shadowbox:docker:build
manual-install-script:
name: Manual Install Script
runs-on: ubuntu-latest
@ -119,7 +161,8 @@ jobs:
sentry-webhook:
name: Sentry Webhook
runs-on: ubuntu-latest
# TODO(puppeteer/puppeteer#12818): Update when chromium bug is resolved.
runs-on: ubuntu-22.04
needs: lint
steps:
- name: Checkout

View file

@ -37,10 +37,10 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Clone Repository
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Install Node
uses: actions/setup-node@v2.2.0
uses: actions/setup-node@v6.1.0
with:
node-version: 18
cache: npm
@ -49,7 +49,7 @@ jobs:
run: npm ci
- name: Ensure Commitizen Format
uses: JulienKode/pull-request-name-linter-action@98794a8b815ec05560813c42e55fd8d32d3fd248
uses: JulienKode/pull-request-name-linter-action@v20.1.0
size_label:
name: Change Size Label

View file

@ -1,12 +1,12 @@
# Outline Server
![Build and Test](https://github.com/Jigsaw-Code/outline-server/actions/workflows/build_and_test_debug.yml/badge.svg?branch=master) [![Mattermost](https://badgen.net/badge/Mattermost/Outline%20Community/blue)](https://community.internetfreedomfestival.org/community/channels/outline-community) [![Reddit](https://badgen.net/badge/Reddit/r%2Foutlinevpn/orange)](https://www.reddit.com/r/outlinevpn/)
![Build and Test](https://github.com/OutlineFoundation/outline-server/actions/workflows/build_and_test_debug.yml/badge.svg?branch=master) [![Mattermost](https://badgen.net/badge/Mattermost/Outline%20Community/blue)](https://community.internetfreedomfestival.org/community/channels/outline-community) [![Reddit](https://badgen.net/badge/Reddit/r%2Foutlinevpn/orange)](https://www.reddit.com/r/outlinevpn/)
Outline Server is the component that provides the Shadowsocks service (via [outline-ss-server](https://github.com/Jigsaw-Code/outline-ss-server/)) and a service management API. You can deploy this server directly following simple instructions in this repository, or if you prefer a ready-to-use graphical interface you can use the [Outline Manager](https://github.com/Jigsaw-Code/outline-apps/).
Outline Server is the component that provides the Shadowsocks service (via [outline-ss-server](https://github.com/OutlineFoundation/tunnel-server/)) and a service management API. You can deploy this server directly following simple instructions in this repository, or if you prefer a ready-to-use graphical interface you can use the [Outline Manager](https://github.com/OutlineFoundation/outline-apps/).
**Components:**
- **Outline Server** ([`src/shadowbox`](src/shadowbox)): The core proxy server that runs and manages [outline-ss-server](https://github.com/Jigsaw-Code/outline-ss-server/), a Shadowsocks backend. It provides a REST API for access key management.
- **Outline Server** ([`src/shadowbox`](src/shadowbox)): The core proxy server that runs and manages [outline-ss-server](https://github.com/OutlineFoundation/tunnel-server/), a Shadowsocks backend. It provides a REST API for access key management.
- **Metrics Server** ([`src/metrics_server`](src/metrics_server)): A REST service for optional, anonymous metrics sharing.

View file

@ -20,6 +20,6 @@ The censors used to block Shadowsocks, but Shadowsocks has evolved, and in 2021,
In 2022 China started blocking seemingly random traffic ([report](https://www.opentech.fund/news/exposing-the-great-firewalls-dynamic-blocking-of-fully-encrypted-traffic/)). While there is no evidence they could detect Shadowsocks, the protocol ended up blocked.
As a reponse, we [added a feature to the Outline Client](https://github.com/Jigsaw-Code/outline-apps/pull/1454) that allows service managers to specify a **[connection prefix disguise](https://www.reddit.com/r/outlinevpn/wiki/index/prefixing/)** to be used in the Shadowsocks initialization, which can be used to bypass the blocking in China by making it look like a protocol that is allowed.
As a reponse, we [added a feature to the Outline Client](https://github.com/OutlineFoundation/outline-apps/pull/1454) that allows service managers to specify a **[connection prefix disguise](https://www.reddit.com/r/outlinevpn/wiki/index/prefixing/)** to be used in the Shadowsocks initialization, which can be used to bypass the blocking in China by making it look like a protocol that is allowed.
Shadowsocks remains our protocol of choice because it's simple, well understood and very performant. Furthermore, it has an enthusiastic community of very smart people behind it.

20
go.mod
View file

@ -1,16 +1,15 @@
module localhost
go 1.22
go 1.26.3
require (
github.com/Jigsaw-Code/outline-ss-server v1.9.2-0.20250218165321-888b9dcbdf1c
github.com/Jigsaw-Code/outline-ss-server v1.7.3
github.com/go-task/task/v3 v3.36.0
github.com/google/addlicense v1.1.1
)
require (
github.com/Jigsaw-Code/outline-sdk v0.0.18-0.20241106233708-faffebb12629 // indirect
github.com/Jigsaw-Code/outline-sdk/x v0.0.0-20250130222646-80b6430a1fc8 // indirect
github.com/Jigsaw-Code/outline-sdk v0.0.14 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.0.2 // indirect
@ -18,10 +17,7 @@ require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/lmittmann/tint v1.0.5 // indirect
@ -41,11 +37,11 @@ require (
github.com/shadowsocks/go-shadowsocks2 v0.1.5 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/crypto v0.26.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.23.0 // indirect
golang.org/x/term v0.23.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/term v0.37.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
mvdan.cc/sh/v3 v3.8.0 // indirect
)

36
go.sum
View file

@ -1,9 +1,7 @@
github.com/Jigsaw-Code/outline-sdk v0.0.18-0.20241106233708-faffebb12629 h1:sHi1X4vwtNNBUDCbxynGXe7cM/inwTbavowHziaxlbk=
github.com/Jigsaw-Code/outline-sdk v0.0.18-0.20241106233708-faffebb12629/go.mod h1:CFDKyGZA4zatKE4vMLe8TyQpZCyINOeRFbMAmYHxodw=
github.com/Jigsaw-Code/outline-sdk/x v0.0.0-20250130222646-80b6430a1fc8 h1:TsWEVm5XU/SalHlZ6VztE9YwHmN0akCgbWFgQ0j7Mys=
github.com/Jigsaw-Code/outline-sdk/x v0.0.0-20250130222646-80b6430a1fc8/go.mod h1:aFUEz6Z/eD0NS3c3fEIX+JO2D9aIrXCmWTb1zJFlItw=
github.com/Jigsaw-Code/outline-ss-server v1.9.2-0.20250218165321-888b9dcbdf1c h1:e8G2DgRGZmhJCgrJw//+IQYkBckmGA4ZeOP4GjkQEDw=
github.com/Jigsaw-Code/outline-ss-server v1.9.2-0.20250218165321-888b9dcbdf1c/go.mod h1:ArtQJ43aUTB5r1gr27E6aMj4nDOZz5vG4WY4NNKJ6ZM=
github.com/Jigsaw-Code/outline-sdk v0.0.14 h1:uJLvIne7YJNolbX7KDacd8gLidrUzRuweBO2APmQEmI=
github.com/Jigsaw-Code/outline-sdk v0.0.14/go.mod h1:9cEaF6sWWMzY8orcUI9pV5D0oFp2FZArTSyJiYtMQQs=
github.com/Jigsaw-Code/outline-ss-server v1.7.3 h1:UF8AaOV2agRb6edF0U0CtTcwpyIxm6NVDa5QLkQh28E=
github.com/Jigsaw-Code/outline-ss-server v1.7.3/go.mod h1:cKPicPWlLWZKJfkQ3CBpQm8a3gXrA2+dpQvsECqBVz8=
github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=
github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@ -24,8 +22,6 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/go-task/task/v3 v3.36.0 h1:XVJ5hQ5hdzTAulHpAGzbUMUuYr9MUOEQFOFazI3hUsY=
github.com/go-task/task/v3 v3.36.0/go.mod h1:XBCIAzuyG/mgZVHMUm3cCznz4+IpsBQRlW1gw7OA5sA=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
@ -36,10 +32,6 @@ github.com/google/addlicense v1.1.1/go.mod h1:Sm/DHu7Jk+T5miFHHehdIjbi4M5+dJDRS3
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33 h1:893HsJqtxp9z1SF76gg6hY70hRY1wVlTSnC/h1yUDCo=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
@ -99,28 +91,28 @@ github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM=
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU=
golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk=
golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

239
package-lock.json generated
View file

@ -1891,6 +1891,19 @@
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/browserslist": {
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
@ -3819,6 +3832,19 @@
"node": "^10.12.0 || >=12.0.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "1.1.2",
"dev": true,
@ -4774,6 +4800,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/is-number-object": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
@ -5210,17 +5246,6 @@
"node": ">=8"
}
},
"node_modules/karma/node_modules/braces": {
"version": "3.0.2",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/karma/node_modules/chokidar": {
"version": "3.5.3",
"dev": true,
@ -5247,17 +5272,6 @@
"fsevents": "~2.3.2"
}
},
"node_modules/karma/node_modules/fill-range": {
"version": "7.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/karma/node_modules/fsevents": {
"version": "2.3.2",
"dev": true,
@ -5292,14 +5306,6 @@
"node": ">=8"
}
},
"node_modules/karma/node_modules/is-number": {
"version": "7.0.0",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/karma/node_modules/readdirp": {
"version": "3.6.0",
"dev": true,
@ -5325,17 +5331,6 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/karma/node_modules/to-regex-range": {
"version": "5.0.1",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@ -5614,51 +5609,6 @@
"node": ">=8.6"
}
},
"node_modules/micromatch/node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"dependencies": {
"fill-range": "^7.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/micromatch/node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/micromatch/node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/micromatch/node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/mime": {
"version": "2.6.0",
"dev": true,
@ -6094,8 +6044,7 @@
},
"node_modules/outline-shadowsocksconfig": {
"version": "0.2.0",
"resolved": "git+ssh://git@github.com/Jigsaw-Code/outline-shadowsocksconfig.git#add590ed57277653d02dd2031ae301500ae881e1",
"license": "Apache-2.0",
"resolved": "git+ssh://git@github.com/OutlineFoundation/shadowsocksconfig.git#add590ed57277653d02dd2031ae301500ae881e1",
"dependencies": {
"ipaddr.js": "^2.0.0",
"js-base64": "^3.5.2",
@ -8131,6 +8080,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"license": "MIT",
@ -9056,7 +9018,7 @@
"dependencies": {
"ip-regex": "^4.1.0",
"js-yaml": "^3.12.0",
"outline-shadowsocksconfig": "github:Jigsaw-Code/outline-shadowsocksconfig#v0.2.0",
"outline-shadowsocksconfig": "github:OutlineFoundation/shadowsocksconfig#v0.2.0",
"prom-client": "^11.1.3",
"randomstring": "^1.1.5",
"restify": "^11.1.0",
@ -10423,6 +10385,15 @@
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"requires": {
"fill-range": "^7.1.1"
}
},
"browserslist": {
"version": "4.22.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz",
@ -11731,6 +11702,15 @@
"flat-cache": "^3.0.4"
}
},
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"finalhandler": {
"version": "1.1.2",
"dev": true,
@ -12352,6 +12332,12 @@
"integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
"dev": true
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"is-number-object": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
@ -12588,13 +12574,6 @@
"version": "2.2.0",
"dev": true
},
"braces": {
"version": "3.0.2",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"chokidar": {
"version": "3.5.3",
"dev": true,
@ -12609,13 +12588,6 @@
"readdirp": "~3.6.0"
}
},
"fill-range": {
"version": "7.0.1",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"fsevents": {
"version": "2.3.2",
"dev": true,
@ -12635,10 +12607,6 @@
"binary-extensions": "^2.0.0"
}
},
"is-number": {
"version": "7.0.0",
"dev": true
},
"readdirp": {
"version": "3.6.0",
"dev": true,
@ -12652,13 +12620,6 @@
"requires": {
"glob": "^7.1.3"
}
},
"to-regex-range": {
"version": "5.0.1",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
@ -12926,41 +12887,6 @@
"requires": {
"braces": "^3.0.2",
"picomatch": "^2.3.1"
},
"dependencies": {
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"dev": true,
"requires": {
"fill-range": "^7.0.1"
}
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"dev": true,
"requires": {
"to-regex-range": "^5.0.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
}
}
},
"mime": {
@ -13264,7 +13190,7 @@
"@types/tmp": "^0.2.1",
"ip-regex": "^4.1.0",
"js-yaml": "^3.12.0",
"outline-shadowsocksconfig": "github:Jigsaw-Code/outline-shadowsocksconfig#v0.2.0",
"outline-shadowsocksconfig": "github:OutlineFoundation/shadowsocksconfig#v0.2.0",
"prom-client": "^11.1.3",
"randomstring": "^1.1.5",
"restify": "^11.1.0",
@ -13284,8 +13210,8 @@
}
},
"outline-shadowsocksconfig": {
"version": "git+ssh://git@github.com/Jigsaw-Code/outline-shadowsocksconfig.git#add590ed57277653d02dd2031ae301500ae881e1",
"from": "outline-shadowsocksconfig@github:Jigsaw-Code/outline-shadowsocksconfig#v0.2.0",
"version": "git+ssh://git@github.com/OutlineFoundation/shadowsocksconfig.git#add590ed57277653d02dd2031ae301500ae881e1",
"from": "outline-shadowsocksconfig@github:OutlineFoundation/shadowsocksconfig#v0.2.0",
"requires": {
"ipaddr.js": "^2.0.0",
"js-base64": "^3.5.2",
@ -14741,6 +14667,15 @@
}
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"requires": {
"is-number": "^7.0.0"
}
},
"toidentifier": {
"version": "1.0.1"
},

View file

@ -34,7 +34,7 @@ const VALID_USER_REPORT2: HourlyUserConnectionMetricsReport = {
/*
* Legacy access key user reports to ensure backwards compatibility with servers not
* synced past https://github.com/Jigsaw-Code/outline-server/pull/1529).
* synced past https://github.com/OutlineFoundation/outline-server/pull/1529).
*/
const LEGACY_PER_KEY_USER_REPORT: HourlyUserConnectionMetricsReport = {
userId: 'foo',
@ -43,7 +43,7 @@ const LEGACY_PER_KEY_USER_REPORT: HourlyUserConnectionMetricsReport = {
/*
* Legacy multiple countries user reports to ensure backwards compatibility with servers
* not synced past https://github.com/Jigsaw-Code/outline-server/pull/1242.
* not synced past https://github.com/OutlineFoundation/outline-server/pull/1242.
*/
const LEGACY_PER_LOCATION_USER_REPORT: HourlyUserConnectionMetricsReport = {
userId: 'foobar',

View file

@ -1,5 +1,5 @@
# Outline Manager
> THIS PROJECT HAS MOVED TO A [NEW LOCATION](https://github.com/Jigsaw-Code/outline-apps/tree/master/): Outline Manager is now part of the [Outline Apps repository](https://github.com/Jigsaw-Code/outline-apps).
> THIS PROJECT HAS MOVED TO A [NEW LOCATION](https://github.com/OutlineFoundation/outline-apps/tree/master/server_manager): Outline Manager is now part of the [Outline Apps repository](https://github.com/OutlineFoundation/outline-apps).
We are keeping this folder to support legacy versions of the app that point to the old [server install script](https://github.com/Jigsaw-Code/outline-server/blob/master/src/server_manager/install_scripts/install_server.sh).
We are keeping this folder to support legacy versions of the app that point to the old [server install script](https://github.com/OutlineFoundation/outline-server/blob/master/src/server_manager/install_scripts/install_server.sh).

View file

@ -160,7 +160,7 @@ function fetch() {
function install_docker() {
(
# Change umask so that /usr/share/keyrings/docker-archive-keyring.gpg has the right permissions.
# See https://github.com/Jigsaw-Code/outline-server/issues/951.
# See https://github.com/OutlineFoundation/outline-server/issues/951.
# We do this in a subprocess so the umask for the calling process is unaffected.
umask 0022
fetch https://get.docker.com/ | sh
@ -376,7 +376,7 @@ function start_watchtower() {
-v /var/run/docker.sock:/var/run/docker.sock)
# By itself, local messes up the return code.
local STDERR_OUTPUT
STDERR_OUTPUT="$(docker run -d "${docker_watchtower_flags[@]}" containrrr/watchtower --cleanup --label-enable --scope=outline --tlsverify --interval "${WATCHTOWER_REFRESH_SECONDS}" 2>&1 >/dev/null)" && return
STDERR_OUTPUT="$(docker run -d "${docker_watchtower_flags[@]}" nickfedor/watchtower --cleanup --label-enable --scope=outline --tlsverify --interval "${WATCHTOWER_REFRESH_SECONDS}" 2>&1 >/dev/null)" && return
readonly STDERR_OUTPUT
log_error "FAILED"
if docker_container_exists watchtower; then
@ -440,7 +440,7 @@ Make sure to open the following ports on your firewall, router or cloud provider
function set_hostname() {
# These are URLs that return the client's apparent IP address.
# We have more than one to try in case one starts failing
# (e.g. https://github.com/Jigsaw-Code/outline-server/issues/776).
# (e.g. https://github.com/OutlineFoundation/outline-server/issues/776).
local -ar urls=(
'https://icanhazip.com/'
'https://ipinfo.io/ip'
@ -456,8 +456,8 @@ function set_hostname() {
install_shadowbox() {
local MACHINE_TYPE
MACHINE_TYPE="$(uname -m)"
if [[ "${MACHINE_TYPE}" != "x86_64" ]]; then
log_error "Unsupported machine type: ${MACHINE_TYPE}. Please run this script on a x86_64 machine"
if [[ "${MACHINE_TYPE}" != "x86_64" && "${MACHINE_TYPE}" != "aarch64" && "${MACHINE_TYPE}" != "arm64" ]]; then
log_error "Unsupported machine type: ${MACHINE_TYPE}. Supported architectures: x86_64, aarch64/arm64."
exit 1
fi

View file

@ -1,20 +1,22 @@
# 1.7.2
- Fixes
- Fix reporting of country metrics and improve logging output (https://github.com/Jigsaw-Code/outline-server/pull/1242)
- Fix reporting of country metrics and improve logging output (https://github.com/OutlineFoundation/outline-server/pull/1242)
# 1.7.1
- Fixes
- Corner case of isPortUsed that could result in infinite restart loop (https://github.com/Jigsaw-Code/outline-server/pull/1238)
- Prevent excessive logging (https://github.com/Jigsaw-Code/outline-server/pull/1232)
- Corner case of isPortUsed that could result in infinite restart loop (https://github.com/OutlineFoundation/outline-server/pull/1238)
- Prevent excessive logging (https://github.com/OutlineFoundation/outline-server/pull/1232)
# 1.7.0
- Features
- Add encryption cipher selection to create access key API (https://github.com/Jigsaw-Code/outline-server/pull/1002)
- Make access key secrets longer (https://github.com/Jigsaw-Code/outline-server/pull/1098)
- Add encryption cipher selection to create access key API (https://github.com/OutlineFoundation/outline-server/pull/1002)
- Make access key secrets longer (https://github.com/OutlineFoundation/outline-server/pull/1098)
- Fixes
- Race condition on concurrent API calls (https://github.com/Jigsaw-Code/outline-server/pull/995)
- Upgrades (https://github.com/Jigsaw-Code/outline-server/pull/1211)
- Race condition on concurrent API calls (https://github.com/OutlineFoundation/outline-server/pull/995)
- Upgrades (https://github.com/OutlineFoundation/outline-server/pull/1211)
- Base image to `node:16.18.0-alpine3.16`
- outline-ss-server from 1.3.5 to [1.4.0](https://github.com/Jigsaw-Code/outline-ss-server/releases/tag/v1.4.0)
- outline-ss-server from 1.3.5 to [1.4.0](https://github.com/OutlineFoundation/outline-ss-server/releases/tag/v1.4.0)
- Prometheus from 2.33.5 to [2.37.1](https://github.com/prometheus/prometheus/releases/tag/v2.37.1)

View file

@ -1,6 +1,6 @@
# Outline Server (Shadowbox)
The Outline Server, internal name "Shadowbox," is designed to streamline the setup and sharing of Shadowsocks servers. It includes a user management API and creates Shadowsocks instances when needed. It's managed by the [Outline Manager](https://github.com/Jigsaw-Code/outline-apps/) and used as proxy by the [Outline Client](https://github.com/Jigsaw-Code/outline-apps/) apps. Shadowbox is also compatible with standard Shadowsocks clients.
The Outline Server, internal name "Shadowbox," is designed to streamline the setup and sharing of Shadowsocks servers. It includes a user management API and creates Shadowsocks instances when needed. It's managed by the [Outline Manager](https://github.com/OutlineFoundation/outline-apps/) and used as proxy by the [Outline Client](https://github.com/OutlineFoundation/outline-apps/) apps. Shadowbox is also compatible with standard Shadowsocks clients.
## Installation
@ -9,7 +9,7 @@ The Outline Server, internal name "Shadowbox," is designed to streamline the set
1. **Run the Installation Script**
```sh
sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/Jigsaw-Code/outline-apps/master/server_manager/install_scripts/install_server.sh)"
sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/OutlineFoundation/outline-apps/master/server_manager/install_scripts/install_server.sh)"
```
1. **Customize (Optional)**
@ -17,7 +17,7 @@ The Outline Server, internal name "Shadowbox," is designed to streamline the set
Add flags for hostname, port, etc. Example:
```sh
sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/Jigsaw-Code/outline-apps/master/server_manager/install_scripts/install_server.sh)" install_server.sh \
sudo bash -c "$(wget -qO- https://raw.githubusercontent.com/OutlineFoundation/outline-apps/master/server_manager/install_scripts/install_server.sh)" install_server.sh \
--hostname=myserver.com \
--keys-port=443
```
@ -113,7 +113,7 @@ The Outline Server provides a REST API for access key management. If you know th
1. **Further Options:**
Consult the [OpenAPI spec](./server/api.yml) and [documentation](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/Jigsaw-Code/outline-server/master/src/shadowbox/server/api.yml) for more options.
Consult the [OpenAPI spec](./server/api.yml) and [documentation](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/OutlineFoundation/outline-server/master/src/shadowbox/server/api.yml) for more options.
## Testing

View file

@ -23,7 +23,7 @@ tasks:
vars:
TARGET_OS: '{{.TARGET_OS | default "linux"}}'
TARGET_ARCH: '{{.TARGET_ARCH | default "x86_64"}}'
GOARCH: '{{get (dict "x86_64" "amd64") .TARGET_ARCH | default .TARGET_ARCH}}'
GOARCH: '{{get (dict "x86_64" "amd64" "aarch64" "arm64") .TARGET_ARCH | default .TARGET_ARCH}}'
TARGET_DIR: '{{.TARGET_DIR | default (joinPath .OUTPUT_BASE .TARGET_OS .TARGET_ARCH)}}'
NODE_DIR: '{{joinPath .TARGET_DIR "app"}}'
BIN_DIR: '{{joinPath .TARGET_DIR "bin"}}'
@ -76,13 +76,21 @@ tasks:
IMAGE_NAME: '{{.IMAGE_NAME | default "localhost/outline/shadowbox"}}'
TARGET_ARCH: '{{.TARGET_ARCH | default "x86_64"}}'
IMAGE_ROOT: '{{joinPath .OUTPUT_BASE "image_root" .TARGET_ARCH}}'
# Newer node images have no valid content trust data.
# Pin the image node:16.18.0-alpine3.16 by hash.
# See image at https://hub.docker.com/_/node/tags?page=1&name=18.18.0-alpine3.18
# Pin the image node:18.20.8-alpine3.21 by hash.
# See image at https://hub.docker.com/_/node/tags?page=1&name=18.20.8-alpine3.21
# Note: "aarch64" is an alias for "arm64" — Linux ARM64 hosts report "aarch64" via uname -m.
NODE_IMAGE: '{{get
(dict
"x86_64" "node@sha256:a0b787b0d53feacfa6d606fb555e0dbfebab30573277f1fe25148b05b66fa097"
"arm64" "node@sha256:b4b7a1dd149c65ee6025956ac065a843b4409a62068bd2b0cbafbb30ca2fab3b"
"x86_64" "node@sha256:929b04d7c782f04f615cf785488fed452b6569f87c73ff666ad553a7554f0006"
"arm64" "node@sha256:c2281c62c4aadf92ea71a6c05e6c8e640634b6a99dc52a6e54575f9cb298a037"
"aarch64" "node@sha256:c2281c62c4aadf92ea71a6c05e6c8e640634b6a99dc52a6e54575f9cb298a037"
) .TARGET_ARCH
}}'
DOCKER_PLATFORM: '{{get
(dict
"x86_64" "linux/amd64"
"arm64" "linux/arm64"
"aarch64" "linux/arm64"
) .TARGET_ARCH
}}'
env:
@ -103,6 +111,7 @@ tasks:
# Build image with given root
- |
"${DOCKER:-docker}" build --force-rm \
--platform '{{.DOCKER_PLATFORM}}' \
--build-arg NODE_IMAGE='{{.NODE_IMAGE}}' \
--build-arg VERSION='{{.VERSION}}' \
-f '{{joinPath .TASKFILE_DIR "docker" "Dockerfile"}}' \

View file

@ -18,16 +18,17 @@ FROM ${NODE_IMAGE}
ARG VERSION
# Save metadata on the software versions we are using.
LABEL shadowbox.node_version=16.18.0
LABEL shadowbox.node_version=18.20.8
LABEL shadowbox.github.release=${VERSION}
# The user management service doesn't quit with SIGTERM.
STOPSIGNAL SIGKILL
# Upgrade installed Alpine packages to pick up security fixes (musl-utils, busybox, ssl_client, etc.).
# We use curl to detect the server's public IP. We need to use the --date option in `date` to
# safely grab the ip-to-country database.
RUN apk add --no-cache --upgrade coreutils curl
RUN apk upgrade --no-cache && apk add --no-cache --upgrade coreutils curl
COPY . /

View file

@ -102,12 +102,17 @@ export interface PrometheusClient {
}
export class ApiPrometheusClient implements PrometheusClient {
constructor(private address: string) {}
private readonly agent: http.Agent;
constructor(private address: string) {
this.agent = new http.Agent({ keepAlive: true });
}
private request(url: string): Promise<QueryResultData> {
return new Promise<QueryResultData>((fulfill, reject) => {
const options = {agent: this.agent};
http
.get(url, (response) => {
.get(url, options, (response) => {
if (response.statusCode < 200 || response.statusCode > 299) {
reject(new Error(`Got error ${response.statusCode}`));
response.resume();

View file

@ -14,7 +14,7 @@
# Alpine 3.19 curl is using the c-ares resolver instead of the system resolver,
# which caused DNS issues. Upgrade once the Alpine image includes the fix. See
# https://github.com/Jigsaw-Code/outline-server/pull/1566.
# https://github.com/OutlineFoundation/outline-server/pull/1566.
FROM docker.io/golang:1-alpine3.18
# curl for fetching pages using the local proxy

View file

@ -11,7 +11,7 @@
"dependencies": {
"ip-regex": "^4.1.0",
"js-yaml": "^3.12.0",
"outline-shadowsocksconfig": "github:Jigsaw-Code/outline-shadowsocksconfig#v0.2.0",
"outline-shadowsocksconfig": "github:OutlineFoundation/shadowsocksconfig#v0.2.0",
"prom-client": "^11.1.3",
"randomstring": "^1.1.5",
"restify": "^11.1.0",

View file

@ -48,6 +48,7 @@ const MMDB_LOCATION_ASN = '/var/lib/libmaxminddb/ip-asn.mmdb';
async function exportPrometheusMetrics(registry: prometheus.Registry, port): Promise<http.Server> {
return new Promise<http.Server>((resolve, _) => {
const server = http.createServer((_, res) => {
res.setHeader('Content-Type', registry.contentType);
res.write(registry.metrics());
res.end();
});
@ -122,7 +123,7 @@ async function main() {
const prometheusPort = await portProvider.reserveFirstFreePort(9090);
// Use 127.0.0.1 instead of localhost for Prometheus because it's resolving incorrectly for some users.
// See https://github.com/Jigsaw-Code/outline-server/issues/341
// See https://github.com/OutlineFoundation/outline-server/issues/341
const prometheusLocation = `127.0.0.1:${prometheusPort}`;
const nodeMetricsPort = await portProvider.reserveFirstFreePort(prometheusPort + 1);

View file

@ -16,6 +16,7 @@ import {
PrometheusClient,
PrometheusMetric,
PrometheusValue,
QueryResultData,
} from '../infrastructure/prometheus_scraper';
import {DataUsageByUser, DataUsageTimeframe} from '../model/metrics';
@ -111,8 +112,9 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
Math.ceil(now / PROMETHEUS_RANGE_QUERY_STEP_SECONDS) * PROMETHEUS_RANGE_QUERY_STEP_SECONDS;
const start = end - timeframe.seconds;
this.prunePrometheusCache();
const [
bandwidth,
bandwidthRange,
dataTransferredByLocation,
tunnelTimeByLocation,
@ -121,34 +123,31 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
dataTransferredByAccessKeyRange,
tunnelTimeByAccessKeyRange,
] = await Promise.all([
this.prometheusClient.query(
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`
),
this.prometheusClient.queryRange(
this.cachedPrometheusClient.queryRange(
`sum(rate(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s]))`,
start,
end,
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
),
this.prometheusClient.query(
this.cachedPrometheusClient.query(
`sum(increase(shadowsocks_data_bytes_per_location{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (location, asn, asorg)`
),
this.prometheusClient.query(
this.cachedPrometheusClient.query(
`sum(increase(shadowsocks_tunnel_time_seconds_per_location[${timeframe.seconds}s])) by (location, asn, asorg)`
),
this.prometheusClient.query(
this.cachedPrometheusClient.query(
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${timeframe.seconds}s])) by (access_key)`
),
this.prometheusClient.query(
this.cachedPrometheusClient.query(
`sum(increase(shadowsocks_tunnel_time_seconds[${timeframe.seconds}s])) by (access_key)`
),
this.prometheusClient.queryRange(
this.cachedPrometheusClient.queryRange(
`sum(increase(shadowsocks_data_bytes{dir=~"c<p|p>t"}[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
start,
end,
`${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s`
),
this.prometheusClient.queryRange(
this.cachedPrometheusClient.queryRange(
`sum(increase(shadowsocks_tunnel_time_seconds[${PROMETHEUS_RANGE_QUERY_STEP_SECONDS}s])) by (access_key)`,
start,
end,
@ -165,13 +164,15 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
},
locations: [],
};
for (const result of bandwidth.result) {
if (result.value) {
serverMetrics.bandwidth.current.data.bytes = parseFloat(result.value[1]);
serverMetrics.bandwidth.current.timestamp = result.value[0];
}
break; // There should only be one result.
const bandwidthRangeValues = bandwidthRange.result[0].values ?? [];
const currentBandwidth = bandwidthRangeValues[bandwidthRangeValues.length - 1];
if (currentBandwidth) {
serverMetrics.bandwidth.current.data.bytes = parseFloat(currentBandwidth[1]);
serverMetrics.bandwidth.current.timestamp = currentBandwidth[0];
}
for (const result of bandwidthRange.result) {
const peakDataTransferred = findPeak(result.values ?? []);
if (peakDataTransferred !== null) {
@ -231,6 +232,41 @@ export class PrometheusManagerMetrics implements ManagerMetrics {
accessKeys: Array.from(accessKeyMap.values()),
};
}
private prometheusCache = new Map<string, {timestamp: number; result: QueryResultData}>();
private get cachedPrometheusClient() {
return new Proxy(this.prometheusClient, {
get: (target, prop) => {
if (typeof target[prop] !== 'function') {
return target[prop];
}
return async (query, ...args) => {
const cacheId = `${String(prop)}: ${query} (args: ${args.join(', ')}))`;
if (this.prometheusCache.has(cacheId)) {
return this.prometheusCache.get(cacheId).result;
}
const result = await (target[prop] as Function)(query, ...args);
this.prometheusCache.set(cacheId, {timestamp: Date.now(), result});
return result;
};
},
});
}
private prunePrometheusCache() {
const now = Date.now();
for (const [key, value] of this.prometheusCache) {
if (now - value.timestamp > PROMETHEUS_RANGE_QUERY_STEP_SECONDS * 1000) {
this.prometheusCache.delete(key);
}
}
}
}
function getServerMetricsLocationEntry(

View file

@ -21,26 +21,12 @@ import * as file from '../infrastructure/file';
import * as logging from '../infrastructure/logging';
import {ShadowsocksAccessKey, ShadowsocksServer} from '../model/shadowsocks_server';
/** Represents an outline-ss-server configuration with multiple services. */
export interface OutlineSSServerConfig {
services: {
listeners: {
type: string;
address: string;
}[];
keys: {
id: string;
cipher: string;
secret: string;
}[];
}[];
}
// Runs outline-ss-server.
export class OutlineShadowsocksServer implements ShadowsocksServer {
private ssProcess: child_process.ChildProcess;
private ipCountryFilename?: string;
private ipAsnFilename?: string;
private isAsnMetricsEnabled = false;
private isReplayProtectionEnabled = false;
/**
@ -95,42 +81,22 @@ export class OutlineShadowsocksServer implements ShadowsocksServer {
private writeConfigFile(keys: ShadowsocksAccessKey[]): Promise<void> {
return new Promise((resolve, reject) => {
const validKeys: ShadowsocksAccessKey[] = keys.filter((key) => {
const keysJson = {keys: [] as ShadowsocksAccessKey[]};
for (const key of keys) {
if (!isAeadCipher(key.cipher)) {
logging.error(
`Cipher ${key.cipher} for access key ${key.id} is not supported: use an AEAD cipher instead.`
);
return false;
continue;
}
return true;
});
const config: OutlineSSServerConfig = {services: []};
const keysByPort: Record<number, ShadowsocksAccessKey[]> = {};
for (const key of validKeys) {
(keysByPort[key.port] ??= []).push(key);
}
for (const port in keysByPort) {
const service = {
listeners: [
// NOTE: We explicitly specify the address string with only the port
// number. This will result in an address that listens on all
// available network interfaces (both IPv4 and IPv6).
{type: 'tcp', address: `:${port}`},
{type: 'udp', address: `:${port}`},
],
keys: keysByPort[port].map((key) => ({
id: key.id,
cipher: key.cipher,
secret: key.secret,
})),
};
config.services.push(service);
keysJson.keys.push(key);
}
mkdirp.sync(path.dirname(this.configFilename));
try {
file.atomicWriteFileSync(this.configFilename, jsyaml.safeDump(config, {sortKeys: true}));
file.atomicWriteFileSync(this.configFilename, jsyaml.safeDump(keysJson, {sortKeys: true}));
resolve();
} catch (error) {
reject(error);

View file

@ -11,17 +11,17 @@ tasks:
prometheus:download-*-*:
desc: Download and extract prometheus binary
vars:
VERSION: '2.37.1'
VERSION: '2.53.4'
GOOS: '{{index .MATCH 0}}'
GOARCH: '{{index .MATCH 1}}'
TEMPFILE: {sh: mktemp}
SHA256: '{{printf "%v/%v" .GOOS .GOARCH | get
(dict
"linux/amd64" "753f66437597cf52ada98c2f459aa8c03745475c249c9f2b40ac7b3919131ba6"
"linux/arm64" "b59a66fb5c7ec5acf6bf426793528a5789a1478a0dad8c64edc2843caf31b1b8"
"darwin/amd64" "e03a43d98955ac3500f57353ea74b5df829074205f195ea6b3b88f55c4575c79"
"darwin/arm64" "eb8a174c82a0fb6c84e81d9a73214318fb4a605115ad61505d7883d02e5a6f52"
)
"linux/amd64" "b8b497c4610d1b93208252b60c8f20f6b2e78596ae8df43397a2e805aa53d475"
"linux/arm64" "ec7236ecea7154d0bfe142921708b1ae7b5e921e100e0ee85ab92b7c444357e0"
"darwin/amd64" "10066a1aa21c4ddb8d5e61c31b52e898d8ac42c7e99fd757e2fc4b6c20b8075f"
"darwin/arm64" "cb3e638d8e9b4b27a6aa1f45a4faa3741b548aac67d4649aea7a2fad3c09f0a1"
)
}}'
TARGET_DIR: '{{joinPath .OUTPUT_BASE "prometheus" .GOOS .GOARCH}}'
TARGET: '{{joinPath .TARGET_DIR "prometheus"}}'

View file

@ -10,13 +10,21 @@ third_party {
}
url {
type: ARCHIVE
value: "https://github.com/prometheus/prometheus/releases/download/2.37.1/prometheus-2.37.1.linux-amd64.tar.gz"
value: "https://github.com/prometheus/prometheus/releases/download/v2.53.4/prometheus-2.53.4.linux-amd64.tar.gz"
}
url {
type: ARCHIVE
value: "https://github.com/prometheus/prometheus/releases/download/2.37.1/prometheus-2.37.1.darwin-amd64.tar.gz"
value: "https://github.com/prometheus/prometheus/releases/download/v2.53.4/prometheus-2.53.4.linux-arm64.tar.gz"
}
version: "2.37.1"
last_upgrade_date { year: 2022 month: 10 day: 24 }
url {
type: ARCHIVE
value: "https://github.com/prometheus/prometheus/releases/download/v2.53.4/prometheus-2.53.4.darwin-amd64.tar.gz"
}
url {
type: ARCHIVE
value: "https://github.com/prometheus/prometheus/releases/download/v2.53.4/prometheus-2.53.4.darwin-arm64.tar.gz"
}
version: "2.53.4"
last_upgrade_date { year: 2025 month: 3 day: 20 }
license_type: PERMISSIVE
}