snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
location /health {
allow 127.0.0.1;
allow ::1;
<% @loadbalancers.each do |host| -%>
allow <%= host %>;
<% end -%>
deny all;
include uwsgi_params;
# Healthchecks may not supply a Host header; but also nothing in
# the response is host-specific, as the Django processes
# themselves are what are being healthchecked. we hardcode a Host
# that we know is in ALLOWED_HOSTS. The alternative is injecting
# a new Django middleware before
# `django.middleware.security.SecurityMiddleware` which only kicks
# in for this one specific path.
uwsgi_param HTTP_HOST "127.0.0.1";
}

View File

@@ -0,0 +1,26 @@
# nginx does its own DNS resolution, which is necessary here to
# resolve the IP of the S3 server. Point it at whatever is configured
# first in /etc/resolv.conf. The validity duration is set to match
# S3's DNS validity.
resolver <%= @nginx_resolver_ip %> valid=300s;
resolver_timeout 10s;
# This cache is only used if S3 file storage is configured.
proxy_cache_path /srv/zulip-uploaded-files-cache
levels=1:2
keys_zone=uploads:<%= @s3_memory_cache_size %>
inactive=<%= @s3_cache_inactive_time %>
max_size=<%= @s3_disk_cache_size %>;
# This is used when proxying requests to S3; we wish to know if the
# proxied request is asking to override the Content-Disposition in its
# response, so we can adjust our cache key. Unfortunately, $arg_foo
# style variables pre-parsed from query parameters don't work with
# query parameters with dashes, so we parse it out by hand. Despite
# needing to be declared at the 'http' level,. nginx applies maps like
# this lazily, so this only affects internal S3 proxied requests.
map $args $s3_disposition_cache_key {
default "";
"~(^|&)(?<param>response-content-disposition=[^&]+)" "?$param";
}

View File

@@ -0,0 +1,24 @@
<% if @tornado_ports.length > 1 -%>
<% @tornado_ports.each do |port| -%>
upstream tornado<%= port %> {
server 127.0.0.1:<%= port %>;
keepalive 10000;
}
<% end -%>
<% @tornado_groups.each do |group| -%>
<% if group.length > 1 -%>
upstream tornado<%= group.join('_') %> {
random;
<% group.each do |port| -%>
server 127.0.0.1:<%= port %>;
<% end -%>
keepalive 10000;
}
<% end -%>
<% end -%>
<% else -%>
upstream tornado {
server 127.0.0.1:9800;
keepalive 10000;
}
<% end -%>

View File

@@ -0,0 +1,54 @@
<% if @loadbalancers.any? %>
# Configuration for making Zulip app frontends accept the
# X-Forwarded-For header used by proxies. The trusted IP addresses
# here are set by `loadbalancer.ips` in /etc/zulip/zulip.conf.
#
# This causes us to update $remote_addr, which we use in logging, and
# also pass down to Zulip as X-Real-Ip.
real_ip_header X-Forwarded-For;
real_ip_recursive on;
<% @loadbalancers.each do |host| -%>
set_real_ip_from <%= host %>;
<% end -%>
<% if @true_client_header == '' %>
# real_ip has done the work of updating $remote_addr based
# on the trusted @loadbalancers
map $remote_addr $trusted_remote_addr {
default $remote_addr;
}
<% else %>
<% if @true_client_header_from.any? %>
# We have a separate set of post-X-Forwarded-For IPs we
# trust with $http_<%= @true_client_header %>
geo $remote_addr $do_trust_<%= @true_client_header %> {
default 0;
<% @true_client_header_from.each do |host| %>
<%= host %> 1;
<%- end %>
}
<% else %>
# If our most recent hop came from a trusted source, we
# trust $http_<%= @true_client_header %>
geo $realip_remote_addr $do_trust_<%= @true_client_header %> {
default 0;
<% @loadbalancers.each do |host| %>
<%= host %> 1;
<%- end %>
}
<% end %>
# This is done in two steps because geo handles CIDRs,
# and map handles interpolation.
map "$do_trust_<%= @true_client_header %>:$http_<%= @true_client_header %>" $trusted_remote_addr {
"~^0:" $remote_addr;
"~^1:$" $remote_addr;
"~^1:" $http_<%= @true_client_header %>;
}
<% end %>
<% else %>
# No remote proxies -- the remote_addr is what it is
map $remote_addr $trusted_remote_addr {
default $remote_addr;
}
<% end %>

View File

@@ -0,0 +1,50 @@
<% if @loadbalancers.empty? %>
# "set" is not supported at the server level, so use a map:
map $remote_addr $trusted_x_forwarded_proto {
default $scheme;
}
map "$scheme:$http_x_forwarded_for" $x_proxy_misconfiguration {
"~^https?:." "No proxies configured in Zulip, but reverse proxy headers were detected from $remote_addr; Zulip must be configured with the IP addresses of reverse proxies to trust. See https://zulip.readthedocs.io/en/latest/production/reverse-proxies.html";
"~^http:$" "Request came in over HTTP, with no proxy headers; if HTTPS is disabled in Zulip, it must be behind a proxy which does TLS termination. See https://zulip.readthedocs.io/en/latest/production/reverse-proxies.html";
default "";
}
<% else %>
# Check if the request's original `REMOTE_ADDR` header was from a
# trusted host -- that is, the request did bounce through a proxy and
# we should trust `X-Forwarded-Proto`
geo $realip_remote_addr $is_x_forwarded_proto_trusted {
default 0;
<% @loadbalancers.each do |host| -%>
<%= host %> 1;
<% end -%>
}
# Check if the IP address that we resolved the request as coming
# (after looking at X-Forwarded-For, if any) from is actually the proxy
# itself.
geo $remote_addr $is_from_proxy {
default 0;
<% @loadbalancers.each do |host| -%>
<%= host %> 1;
<% end -%>
}
# We set $trusted_x_forwarded_proto in two steps because `geo` does
# not support variable interpolation in the value, but does support
# CIDR notation, which the loadbalancer list may use.
map "$is_x_forwarded_proto_trusted:$http_x_forwarded_proto" $trusted_x_forwarded_proto {
"~^0:" $scheme;
<%- if @lb_rejects_http_requests -%>
"~^1:$" "https";
<% end -%>
"~^1:" $http_x_forwarded_proto;
}
map "$is_from_proxy:$is_x_forwarded_proto_trusted:$http_x_forwarded_proto" $x_proxy_misconfiguration {
"~^0:0:" "Incorrect reverse proxy IPs set in Zulip (try $remote_addr?); see https://zulip.readthedocs.io/en/latest/production/reverse-proxies.html";
<%- if not @lb_rejects_http_requests -%>
"~^0:1:$" "No X-Forwarded-Proto header sent from trusted proxy $realip_remote_addr; see example configurations in https://zulip.readthedocs.io/en/latest/production/reverse-proxies.html";
<% end -%>
default "";
}
<% end %>

View File

@@ -0,0 +1,54 @@
# For local IPC -- tusd to Django, or Django to Tornado
server {
<% if @nginx_http_only -%>
listen 127.0.0.1:<%= @nginx_listen_port %>;
<% else -%>
listen 127.0.0.1:80;
<% end -%>
include /etc/nginx/zulip-include/app;
include /etc/nginx/zulip-include/localhost.d/*.conf;
}
<% if @nginx_http_only -%>
<% else -%>
server {
listen 80;
listen [::]:80;
<% if @nginx_server_name != '' -%>
server_name <%= @nginx_server_name %>;
<% end -%>
location / {
return 301 https://$host$request_uri;
}
include /etc/nginx/zulip-include/certbot;
}
<% end -%>
include /etc/nginx/zulip-include/trusted-ip;
include /etc/nginx/zulip-include/trusted-proto;
include /etc/nginx/zulip-include/s3-cache;
include /etc/nginx/zulip-include/upstreams;
include /etc/zulip/nginx_sharding_map.conf;
server {
<% if @nginx_http_only -%>
listen <%= @nginx_listen_port %>;
listen [::]:<%= @nginx_listen_port %>;
<% else -%>
listen <%= @nginx_listen_port %> ssl http2;
listen [::]:<%= @nginx_listen_port %> ssl http2;
ssl_certificate <%= @ssl_dir %>/certs/zulip.combined-chain.crt;
ssl_certificate_key <%= @ssl_dir %>/private/zulip.key;
<% end -%>
<% if @nginx_server_name != '' -%>
server_name <%= @nginx_server_name %>;
<% end -%>
include /etc/nginx/zulip-include/certbot;
include /etc/nginx/zulip-include/app;
}