镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,7 @@ MINIO_ENDPOINT_SSL=0

# API key rate limit
API_KEY_RATE_LIMIT="60/minute"

# Number of reverse proxies in front of the API, used to read the client IP from
# X-Forwarded-For for rate limiting. Leave unset to keep the default behaviour.
# NUM_PROXIES=
8 changes: 8 additions & 0 deletions apps/api/plane/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@
"SCHEMA_COERCE_PATH_PK": False,
}

# Number of reverse proxies in front of the API. DRF throttles use it to pick the
# client IP from X-Forwarded-For. Unset keeps DRF's default (None).
_num_proxies_raw = os.environ.get("NUM_PROXIES", "").strip()
if _num_proxies_raw.isdecimal() and len(_num_proxies_raw) <= 3:
REST_FRAMEWORK["NUM_PROXIES"] = int(_num_proxies_raw)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor: this hop count only reaches DRF throttles. Several other places read the client IP through plane.utils.ip_address.get_client_ip, which still takes the leftmost XFF entry:

  • user_ip in authentication/utils/host.py and utils/host.py
  • last_login_ip in authentication/adapter/base.py and license/api/views/admin.py
  • the login audit payload in authentication/utils/login.py
  • remote_addr in middleware/logger.py

In the README's "behind an additional load balancer" setup, the leftmost entry is whatever the client sent. So once this is configured, the IP recorded for logins and request logs can differ from the IP the throttle counts. This was already the case before this PR, but a follow-up could make get_client_ip honour the same setting so that both agree.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed, it would be good for both to agree. It's a pre-existing gap, though, and #9921 is changing get_client_ip at the moment. I'll keep this PR to the throttle setting and align get_client_ip with NUM_PROXIES in a follow-up after #9921.

elif _num_proxies_raw:
_logger.warning("NUM_PROXIES: ignoring invalid value %r", _num_proxies_raw)

# API key throttle rate (DRF SimpleRateThrottle format, e.g. "60/minute")
API_KEY_RATE_LIMIT = os.environ.get("API_KEY_RATE_LIMIT", "60/minute")

Expand Down
38 changes: 38 additions & 0 deletions apps/api/plane/tests/unit/settings/test_num_proxies.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.

"""Unit tests for the optional NUM_PROXIES setting."""

import importlib

import pytest

from plane.settings import common


@pytest.fixture
def load_rest_framework(monkeypatch):
"""Re-execute settings/common.py with NUM_PROXIES set to ``value`` (None = unset)."""

def _load(value):
if value is None:
monkeypatch.delenv("NUM_PROXIES", raising=False)
else:
monkeypatch.setenv("NUM_PROXIES", value)
return importlib.reload(common).REST_FRAMEWORK

yield _load
monkeypatch.undo()
importlib.reload(common)


@pytest.mark.unit
class TestNumProxiesSetting:
@pytest.mark.parametrize("value", [None, "", "abc", "-1", "9" * 5000])
def test_unset_or_invalid_keeps_drf_default(self, load_rest_framework, value):
assert "NUM_PROXIES" not in load_rest_framework(value)

@pytest.mark.parametrize("value, expected", [("1", 1), ("0", 0)])
def test_non_negative_integer_is_applied(self, load_rest_framework, value, expected):
assert load_rest_framework(value)["NUM_PROXIES"] == expected
51 changes: 33 additions & 18 deletions deployments/cli/community/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,15 @@ mkdir plane-selfhost
cd plane-selfhost
```

#### For *Docker Compose* based setup
#### For _Docker Compose_ based setup

```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/setup.sh

chmod +x setup.sh
```

#### For *Docker Swarm* based setup
#### For _Docker Swarm_ based setup

```
curl -fsSL -o setup.sh https://github.com/makeplane/plane/releases/latest/download/swarm.sh
Expand All @@ -89,7 +89,8 @@ Lets get started by running the `./setup.sh` command.

This will prompt you with the below options.

#### Docker Compose
#### Docker Compose

```bash
Select an Action you want to perform:
1) Install (x86_64)
Expand Down Expand Up @@ -152,6 +153,16 @@ Below are the most import keys you must refer to. _<span style="color: #fcba03">

There are many other settings you can play with, but we suggest you configure `EMAIL SETTINGS` as it will enable you to invite your teammates onto the platform.

#### Client IP and rate limiting behind proxies

Some endpoints are rate-limited per client IP. Two settings in `plane.env` control how that IP is determined:

- **Plane directly on the internet behind the bundled proxy:** set `TRUSTED_PROXIES=private_ranges` (or your load balancer's ranges) and `NUM_PROXIES=1`.
- **Behind an additional load balancer or CDN:** add its ranges to `TRUSTED_PROXIES` (space-separated, e.g. `TRUSTED_PROXIES=private_ranges 203.0.113.0/24`) and raise `NUM_PROXIES` by one per extra hop (e.g. `NUM_PROXIES=2`).
- **Leaving `NUM_PROXIES` empty and `TRUSTED_PROXIES` at its default (`0.0.0.0/0`)** keeps the current behaviour.

Restart the services after changing these values.

---

### Continue with setup - Start Server (Docker Compose)
Expand Down Expand Up @@ -189,7 +200,7 @@ You have successfully self hosted `Plane` instance. Access the application by go

In case you want to make changes to `plane.env` variables, we suggest you to stop the services before doing that.

#### Docker Compose
#### Docker Compose

Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `3` to stop the services

Expand Down Expand Up @@ -239,6 +250,7 @@ In case you want to make changes to `plane.env` variables, without stopping the
Lets again run the `./setup.sh` command. You will again be prompted with the below options. This time select `4` to restart the services

#### Docker Compose

```bash
Select a Action you want to perform:
1) Install (x86_64)
Expand Down Expand Up @@ -275,7 +287,7 @@ If all goes well, you will see the confirmation from docker cli

---

### Upgrading Plane Version
### Upgrading Plane Version

It is always advised to keep Plane up to date with the latest release.

Expand Down Expand Up @@ -337,9 +349,9 @@ Once done with making changes in `plane.env` file, jump on to `Redeploy Stack`

### View Logs

There would a time when you might want to check what is happening inside the API, Worker or any other container.
There would a time when you might want to check what is happening inside the API, Worker or any other container.

Lets again run the `./setup.sh` command. You will again be prompted with the below options.
Lets again run the `./setup.sh` command. You will again be prompted with the below options.

This time select `6` to view logs.

Expand All @@ -361,7 +373,6 @@ Action [2]: 6

#### Docker Swarm


```bash
1) Deploy Stack
2) Remove Stack
Expand All @@ -375,7 +386,9 @@ Action [3]: 6
```

#### Service Menu Options for Logs

This will further open sub-menu with list of services

```bash
Select a Service you want to view the logs for:
1) Web
Expand All @@ -395,6 +408,7 @@ Service: 3
```

Select any of the service to view the logs e.g. `3`. Expect something similar to this

```bash
api-1 | Waiting for database...
api-1 | Database available!
Expand Down Expand Up @@ -439,9 +453,9 @@ api-1 | [2024-05-02 03:56:03 +0000] [25] [INFO] Application startup complete.

```

To exit this, use `CTRL+C` and then you will land on to the main-menu with the list of actions.
To exit this, use `CTRL+C` and then you will land on to the main-menu with the list of actions.

Similarly, you can view the logs of other services.
Similarly, you can view the logs of other services.

---

Expand Down Expand Up @@ -500,12 +514,12 @@ When you want to restore the previously backed-up data, follow the instructions

```bash
--------------------------------------------
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
____ _ /////////
| _ \| | __ _ _ __ ___ /////////
| |_) | |/ _` | '_ \ / _ \ ///// /////
| __/| | (_| | | | | __/ ///// /////
|_| |_|\__,_|_| |_|\___| ////
////
--------------------------------------------
Project management tool from the future
--------------------------------------------
Expand Down Expand Up @@ -550,7 +564,7 @@ When you want to restore the previously backed-up data on Plane Commercial Air-G
./restore-airgapped.sh <path to backup folder containing *.tar.gz files>
```

1. After restoration, you are ready to start Plane Commercial (Airgapped) will all your previously saved data.
1. After restoration, you are ready to start Plane Commercial (Airgapped) will all your previously saved data.

---

Expand Down Expand Up @@ -627,4 +641,5 @@ In case the suffixes are wrong or the mentioned volumes are not found, you will
In case of successful migration, it will be a silent exit without error.

Now its time to restart v0.14.0 setup.
</details>

</details>
2 changes: 2 additions & 0 deletions deployments/cli/community/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ x-proxy-env: &proxy-env
LISTEN_HTTPS_PORT: ${LISTEN_HTTPS_PORT:-443}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
SITE_ADDRESS: ${SITE_ADDRESS:-:80}
TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0}

x-mq-env: &mq-env # RabbitMQ Settings
RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq}
Expand All @@ -56,6 +57,7 @@ x-app-env: &app-env
SECRET_KEY: ${SECRET_KEY}
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
NUM_PROXIES: ${NUM_PROXIES:-}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY}
WEBHOOK_ALLOWED_IPS: ${WEBHOOK_ALLOWED_IPS:-}
Expand Down
7 changes: 7 additions & 0 deletions deployments/cli/community/variables.env
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ AMQP_URL=

# If SSL Cert to be generated, set CERT_EMAIl="email <EMAIL_ADDRESS>"
CERT_ACME_CA=https://acme-v02.api.letsencrypt.org/directory
# Proxies whose forwarded headers the bundled proxy trusts, e.g. "private_ranges" or your
# load balancer's CIDR ranges (space-separated). See README: "Client IP and rate limiting behind proxies".
TRUSTED_PROXIES=0.0.0.0/0
SITE_ADDRESS=:80
CERT_EMAIL=
Expand Down Expand Up @@ -84,6 +86,11 @@ API_KEY_RATE_LIMIT=60/minute
# where period is second/minute/hour/day.
AUTHENTICATION_RATE_LIMIT=10/minute

# Number of reverse proxies in front of the API (1 for the bundled proxy, plus one per
# extra load balancer/CDN hop), used to read the client IP for rate limiting.
# Leave empty to keep the default behaviour.
NUM_PROXIES=

# Live server environment variables — change this before deploying to production.
# Generate a secure value with: openssl rand -hex 32
LIVE_SERVER_SECRET_KEY=change-this-key-on-deployment
Expand Down
Loading