Skip to content
Open
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
95 changes: 95 additions & 0 deletions .bright-container-logs.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
=== sentry-app-1 ===
* Unknown config option found: 'system.rate-limit'
* Unknown config option found: 'system.rate-limit-duration'
* Unknown config option found: 'system.auth-rate-limit'
* Unknown config option found: 'system.auth-rate-limit-window'
Traceback (most recent call last):
File "/.venv/bin/sentry", line 4, in <module>
raise SystemExit(main())
~~~~^^
File "/usr/src/sentry/src/sentry/runner/main.py", line 146, in main
func(**kwargs)
~~~~^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 1442, in __call__
return self.main(*args, **kwargs)
~~~~~~~~~^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 1363, in main
rv = self.invoke(ctx)
File "/.venv/lib/python3.13/site-packages/click/core.py", line 1830, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 1830, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 1226, in invoke
return ctx.invoke(self.callback, **ctx.params)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 794, in invoke
return callback(*args, **kwargs)
File "/.venv/lib/python3.13/site-packages/click/decorators.py", line 34, in new_func
return f(get_current_context(), *args, **kwargs)
File "/usr/src/sentry/src/sentry/runner/decorators.py", line 82, in inner
return ctx.invoke(f, *args, **kwargs)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/click/core.py", line 794, in invoke
return callback(*args, **kwargs)
File "/.venv/lib/python3.13/site-packages/click/decorators.py", line 34, in new_func
return f(get_current_context(), *args, **kwargs)
File "/usr/src/sentry/src/sentry/runner/decorators.py", line 33, in inner
configure()
~~~~~~~~~^^
File "/usr/src/sentry/src/sentry/runner/__init__.py", line 33, in configure
_configure(ctx, py, yaml, skip_service_validation)
~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/src/sentry/src/sentry/runner/settings.py", line 118, in configure
initialize_app(
~~~~~~~~~~~~~~^
{"config_path": py, "settings": settings, "options": yaml},
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
skip_service_validation=skip_service_validation,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/usr/src/sentry/src/sentry/runner/initializer.py", line 364, in initialize_app
configure_sdk()
~~~~~~~~~~~~~^^
File "/usr/src/sentry/src/sentry/utils/sdk.py", line 359, in configure_sdk
transport = make_transport(get_options(dsn=internal_project_key.dsn_private, **sdk_options))
File "/.venv/lib/python3.13/site-packages/sentry_sdk/transport.py", line 1166, in make_transport
return transport_cls(options)
File "/.venv/lib/python3.13/site-packages/sentry_sdk/transport.py", line 219, in __init__
Transport.__init__(self, options)
~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/sentry_sdk/transport.py", line 110, in __init__
self.parsed_dsn = Dsn(options["dsn"], options.get("org_id"))
~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/.venv/lib/python3.13/site-packages/sentry_sdk/utils.py", line 349, in __init__
if parts.port is None:
^^^^^^^^^^
File "/usr/local/lib/python3.13/urllib/parse.py", line 182, in port
raise ValueError(f"Port could not be cast to integer value as {port!r}")
ValueError: Port could not be cast to integer value as '9000<script>alert("bright174677");<'

=== sentry-db-1 ===
PostgreSQL Database directory appears to contain a database; Skipping initialization

=== sentry-redis-1 ===
1:C 07 Jun 2026 19:45:15.691 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
1:C 07 Jun 2026 19:45:15.691 * oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1:C 07 Jun 2026 19:45:15.691 * Redis version=7.4.9, bits=64, commit=00000000, modified=0, pid=1, just started
1:C 07 Jun 2026 19:45:15.691 * Configuration loaded
1:M 07 Jun 2026 19:45:15.692 * Increased maximum number of open files to 10032 (it was originally set to 1024).
1:M 07 Jun 2026 19:45:15.692 * monotonic clock: POSIX clock_gettime
1:M 07 Jun 2026 19:45:15.692 * Running mode=standalone, port=6379.
1:M 07 Jun 2026 19:45:15.692 * Server initialized
1:M 07 Jun 2026 19:45:15.692 * Reading RDB base file on AOF loading...
1:M 07 Jun 2026 19:45:15.692 * Loading RDB produced by version 7.4.9
1:M 07 Jun 2026 19:45:15.693 * RDB age 4659 seconds
1:M 07 Jun 2026 19:45:15.693 * RDB memory usage when created 0.90 Mb
1:M 07 Jun 2026 19:45:15.693 * RDB is base AOF
1:M 07 Jun 2026 19:45:15.693 * Done loading RDB, keys loaded: 0, keys expired: 0.
1:M 07 Jun 2026 19:45:15.693 * DB loaded from base file appendonly.aof.1.base.rdb: 0.000 seconds
1:M 07 Jun 2026 19:45:16.017 * DB loaded from incr file appendonly.aof.1.incr.aof: 0.324 seconds
1:M 07 Jun 2026 19:45:16.017 * DB loaded from append only file: 0.325 seconds
1:M 07 Jun 2026 19:45:16.017 * Opening AOF incr file appendonly.aof.1.incr.aof on server start
1:M 07 Jun 2026 19:45:16.017 * Ready to accept connections tcp
81 changes: 81 additions & 0 deletions .bright-fetched-page.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: "Quotas"
url: https://develop.sentry.dev/backend/application-domains/quotas/
---

# Quotas

With the way Sentry works you may find yourself in a situation where you’ll see too much inbound traffic without a good way to drop excess messages. There’s a few solutions to this, and you’ll likely want to employ them all if you are faced with this problem.

## [Event Quotas](https://develop.sentry.dev/backend/application-domains/quotas.md#event-quotas)

One of the primary mechanisms for throttling workloads in Sentry involves setting up event quotas. These can be configured per project as well as system wide and will allow you to limit the maximum number of events accepted within a 60 second period of time.

### [Configuration](https://develop.sentry.dev/backend/application-domains/quotas.md#configuration)

The primary implementation uses Redis, and simply requires you to configure the connection information:

```python
SENTRY_QUOTAS = 'sentry.quotas.redis.RedisQuota'
```

By default, this will use the `default` named Redis cluster. To use a different cluster, provide the `cluster` option, as such:

```python
SENTRY_QUOTA_OPTIONS = {
'cluster': 'quota',
}
```

If you have additional needs, you’re freely available to extend the base Quota class just as the Redis implementation does.

### [System-wide Rate Limiting](https://develop.sentry.dev/backend/application-domains/quotas.md#system-wide-rate-limiting)

You can configure the system-wide maximum per-minute rate limit:

```yaml
system.rate-limit: 500
```

For example, in your project's `sentry.conf.py`, you can do something like this:

```python
from sentry.conf.server import SENTRY_OPTIONS

SENTRY_OPTIONS['system.rate-limit'] = 500
```

Alternatively, if you navigate to `/manage/settings/` you will find an admin panel with an option for setting `Rate Limit`, which gets stored in your quota implementation described above.

### [User-based Rate Limiting](https://develop.sentry.dev/backend/application-domains/quotas.md#user-based-rate-limiting)

You can configure the user-based maximum per-minute rate limit:

```yaml
auth.user-rate-limit: 100
auth.ip-rate-limit: 100
```

### [Project-based Rate Limiting](https://develop.sentry.dev/backend/application-domains/quotas.md#project-based-rate-limiting)

For doing project-based rate limiting, click on a project's `Settings`. Under the `Client Keys (DSN)` tab, find the key that you'd like to rate-limit, and click the corresponding `Configure` button. That should bring up key/project-specific rate-limiting settings.

## [Notification Rate Limits](https://develop.sentry.dev/backend/application-domains/quotas.md#notification-rate-limits)

In some cases there may be concerns about limiting things such as outbound email notifications. To address this Sentry provides a rate limits subsystem which supports arbitrary rate limits.

### [Configuration](https://develop.sentry.dev/backend/application-domains/quotas.md#configuration-1)

Like event quotas, the primary implementation uses Redis:

```python
SENTRY_RATELIMITER = 'sentry.ratelimits.redis.RedisRateLimiter'
```

By default, this will use the `default` named Redis cluster. To use a different cluster, provide the `cluster` option, as such:

```python
SENTRY_RATELIMITER_OPTIONS = {
'cluster': 'ratelimiter',
}
```
122 changes: 122 additions & 0 deletions Dockerfile.bright
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
FROM scratch AS odiff-amd64
ADD --chmod=755 \
--checksum=sha256:2c17e6bcf92a58e6668f19f17f4a27fa4b1d70840994f31bd837b55bb6b297d7 \
https://github.com/dmtrKovalenko/odiff/releases/download/v4.3.2/odiff-linux-x64 \
/odiff

FROM scratch AS odiff-arm64
ADD --chmod=755 \
--checksum=sha256:d65f748c463a6aa78fa7bcdd31acd797eaed5160867e7769a3b291cfea42c9a0 \
https://github.com/dmtrKovalenko/odiff/releases/download/v4.3.2/odiff-linux-arm64 \
/odiff

ARG TARGETARCH
FROM odiff-${TARGETARCH} AS odiff

FROM node:24.14.0-bookworm-slim AS frontend-build

ARG SOURCE_COMMIT=unknown

ENV DEBIAN_FRONTEND=noninteractive \
NODE_OPTIONS="--max-old-space-size=4096" \
SENTRY_BUILD=${SOURCE_COMMIT}

WORKDIR /usr/src/sentry

COPY . .
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 python3-venv make g++ git \
&& rm -rf /var/lib/apt/lists/* \
&& python3 -m venv /.venv \
&& /.venv/bin/pip install uv==0.9.28 \
&& corepack enable pnpm \
&& pnpm install --frozen-lockfile --ignore-scripts \
&& /.venv/bin/python3 -m tools.fast_editable --path . \
&& sed -i 's/pnpm", "install", "--production", "--frozen-lockfile", "--reporter=append-only"/pnpm", "install", "--frozen-lockfile", "--ignore-scripts", "--reporter=append-only"/' src/sentry/build/_static_assets.py \
&& /.venv/bin/python3 -m sentry.build.main

FROM python:3.13.1-slim-bookworm

SHELL ["/bin/bash", "-o", "pipefail", "-c"]

LABEL maintainer="oss@sentry.io"
LABEL org.opencontainers.image.title="Sentry"
LABEL org.opencontainers.image.description="Sentry runtime image"
LABEL org.opencontainers.image.url="https://sentry.io/"
LABEL org.opencontainers.image.documentation="https://develop.sentry.dev/self-hosted/"
LABEL org.opencontainers.image.vendor="Functional Software, Inc."
LABEL org.opencontainers.image.authors="oss@sentry.io"

ENV DEBIAN_FRONTEND=noninteractive \
PATH="/.venv/bin:$PATH" \
UV_PROJECT_ENVIRONMENT=/.venv \
PIP_NO_CACHE_DIR=1 \
PIP_DISABLE_PIP_VERSION_CHECK=1 \
UV_COMPILE_BYTECODE=1 \
UV_NO_CACHE=1 \
SENTRY_CONF=/etc/sentry \
GRPC_POLL_STRATEGY=epoll1 \
MAKEFLAGS="-j$(nproc)" \
CARGO_BUILD_JOBS=$(nproc)

RUN groupadd -r sentry --gid 999 \
&& useradd -r -m -g sentry --uid 999 sentry \
&& apt-get update \
&& apt-get install -y --no-install-recommends \
gcc \
git \
gosu \
libexpat1 \
libpcre2-dev \
zlib1g-dev \
tini \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

COPY --from=odiff /odiff /usr/local/bin/odiff

WORKDIR /usr/src/sentry

RUN python3 -m pip install --index-url 'https://pypi.devinfra.sentry.io/simple' 'uv==0.9.28' \
&& python3 -m venv /.venv

COPY uv.lock pyproject.toml ./
RUN set -eux; \
buildDeps="gcc libpcre2-dev zlib1g-dev"; \
apt-get update; \
apt-get install -y --no-install-recommends $buildDeps; \
uv sync --frozen --quiet --no-install-project; \
apt-get purge -y --auto-remove $buildDeps; \
apt-get clean; \
rm -rf /var/lib/apt/lists/*; \
python -c 'import maxminddb.extension; maxminddb.extension.Reader'; \
mkdir -p "$SENTRY_CONF"

COPY . .
COPY --from=frontend-build /usr/src/sentry/src/sentry/loader/_registry.json /usr/src/sentry/src/sentry/loader/_registry.json
COPY --from=frontend-build /usr/src/sentry/src/sentry/integration-docs/python.json /usr/src/sentry/src/sentry/integration-docs/python.json
COPY --from=frontend-build /usr/src/sentry/src/sentry/static/sentry/dist /usr/src/sentry/src/sentry/static/sentry/dist

RUN set -eux; \
python3 -m tools.fast_editable --path .; \
python3 -m compileall -q src/; \
sentry help | sed '1,/Commands:/d' | awk '{print $1}' > /sentry-commands.txt; \
test -f /usr/src/sentry/src/sentry/loader/_registry.json; \
test -f /usr/src/sentry/src/sentry/integration-docs/python.json; \
test -f /usr/src/sentry/src/sentry/static/sentry/dist/entrypoints/app.js; \
sentry help

COPY self-hosted/sentry.conf.py self-hosted/config.yml "$SENTRY_CONF"/
COPY self-hosted/docker-entrypoint.sh /

EXPOSE 9000
VOLUME ["/data"]

ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["run", "web"]

ARG SOURCE_COMMIT
ENV SENTRY_BUILD=${SOURCE_COMMIT:-unknown}
LABEL org.opencontainers.image.revision=$SOURCE_COMMIT
LABEL org.opencontainers.image.source="https://github.com/getsentry/sentry/tree/${SOURCE_COMMIT:-master}/"
LABEL org.opencontainers.image.licenses="https://github.com/getsentry/sentry/blob/${SOURCE_COMMIT:-master}/LICENSE"
70 changes: 70 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
services:
app:
build:
context: .
dockerfile: Dockerfile.bright
environment:
NODE_ENV: production
DJANGO_SETTINGS_MODULE: sentry.conf.server
SENTRY_POSTGRES_HOST: db
SENTRY_POSTGRES_PORT: "5432"
SENTRY_DB_NAME: postgres
SENTRY_DB_USER: postgres
SENTRY_DB_PASSWORD: postgres
SENTRY_REDIS_HOST: redis
SENTRY_REDIS_PORT: "6379"
SENTRY_SECRET_KEY: change-me-to-a-long-random-secret
SENTRY_SINGLE_ORGANIZATION: "1"
GRPC_POLL_STRATEGY: epoll1
ports:
- "9000:9000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
stdin_open: true
tty: true
restart: on-failure
healthcheck:
test: ["CMD-SHELL", "python -c \"import urllib.request; r=urllib.request.urlopen('http://127.0.0.1:9000/_health/', timeout=5); import sys; sys.exit(0 if r.status == 200 else 1)\""]
interval: 30s
timeout: 10s
retries: 5
start_period: 120s

db:
image: postgres:16
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: postgres
PGDATA: /var/lib/postgresql/data
volumes:
- db-data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s

redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis-data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep -q PONG"]
interval: 10s
timeout: 5s
retries: 10
start_period: 10s

volumes:
db-data:
redis-data:
Loading
Loading