Skip to main content

Configuration of Cloudflare

Hanging Aivory behind Cloudflare can get three things at a time: ** Hidden source IP ** (Visitors can only see the addresses of the Cloudflare edge nodes) ** Free and automatic renewal of edge certificates ** (Browser to Cloudflare this section of HTTPS does not need to worry you), and Cloudflare ** DDoS mitigation and basic WAF ** Additional advantages include global Anycast near-access and static resource edge caching.

This page offers two complete routes:

  • ** Solution A: orange-cloud proxy ** Source stations have a public IP, DNS records open the Cloudflare proxy (orange cloud), and traffic path is “Visitors → Cloudflare → Source station Nginx → app”.
  • ** Project B: Cloudflare Tunnel ** The source station does not have a public network IP or does not want to open any input port. cloudflared The container actively builds outbound tunnels for Cloudflare.

Both routes are based on the same fact: Aivory’s app Single container single source serving SPA and /api Which domain name can be used. ** not need ** Changes to Cloudflare ALLOWED_ORIGINS Or any domain name configuration (this variable only makes sense when it is deployed separately from the front and back end).

Prerequisite: Domain Name Access to Cloudflare

  1. Register a Cloudflare account, click on the panel Add a domain Enter your domain name (such as example.com Choose a free package.
  2. Cloudflare scans existing DNS records and gives two NS server addresses to your domain name registrar to change Nameserver to both.
  3. Waiting to change. Active (usually minutes to hours), then the domain name’s DNS and agents are managed in the Cloudflare panel.

At the same time, confirm the basic deployment on the Aivory side has been completed: Deployment of Docker Compose It has been completed, and Plan A has been completed. Reverse Proxy and HTTPS Install Nginx at the source station.

Solution A: orange-cloud proxy

Step 1: Open the DNS record for the orange-cloud proxy

In the Cloudflare panel. DNS → Records Add (or modify) the record pointing to the source station and Proxy status Established as Proxied The Orange Cloud:

TypeNameContentProxy status
AchatThe source IPv4 addressProxied (orange cloud proxy)
AAAAchatSource station IPv6 address (if available)Proxied (orange cloud proxy)

Open the Orange-Cloud Proxy. dig chat.example.com Cloudflare’s edge IP is resolved, and the real address of the source station is no longer exposed.

Try to hide the source more thoroughly.

The orange-cloud proxy just keeps DNS from leaking the source station’s IP. If you want the source station firewall level to accept only back source traffic from Cloudflare, you can only allow access to the 443 port in the firewall (ufw/cloud security group) that is officially announced by Cloudflare (https://www.cloudflare.com/ips/). This step is optionally enhanced and does not affect functionality.

Step 2: Select the SSL/TLS encryption mode

SSL/TLS → Overview Choose the encryption mode.The three modes differ in how the “Cloudflare to source station” section goes:

The modelInstalled by CloudflareCloudflare → Source StationSource Requirementsis recommended
FlexibleHTTPS** Clearly HTTP **The source station only needs to listen to 80, no certificate is requiredOnly internal network/trusted links
FullHTTPSHTTPS is ** No school certificate. **Optional certificate (including self-signature)transitional use
Full (strict)HTTPSHTTPS, ** School certificate validity **True and trusted certificate.** Recommended **

** Recommended full (strict) ** The source station Reverse Proxy and HTTPS With Let's Encrypt certificate, you can meet the requirements. If you don't want to run a certbot, you can also SSL/TLS → Origin Server Issuing a Cloudflare Origin CA certificate (valid for up to 15 years, trusted only by Cloudflare back source) on the source station Nginx is also compliant with Full (strict).

** The advantages and disadvantages of flexible when using HTTP only **:

  • Advantages: Aivory supports HTTP explicit deployment in the production environment (the application's request signature algorithm has a pure JS return, and does not rely on the encrypted API for the browser's security context). https:// The address, the page is secure, instead. ** Avoid various browser restrictions under pure text HTTP deployments ** The source station does not have a certificate configuration at all, and is the fastest path to zero certificate maintenance costs.
  • Disadvantages: Cloudflare to the source station this paragraph is clear, any intermediate network can see traffic content (including login credentials and conversation content). only when this link is reliable (such as in-room network, cloud provider private network) is recommended to use; go public network back source must be upgraded to Full (strict).
The most common rollover in the flexible mode: redirecting the dead cycle

Reverse Proxy and HTTPS For example, the Nginx configuration translates requests from 80 ports to 301 to HTTPS. In Flexible mode, Cloudflare always uses the HTTP source and the source station always 301 times. https:// With Flexible, the source station 80 port must serve the business directly without HTTPS jumping.

Source stations Nginx in flexible mode (pure HTTP, still retaining SSE with real IP processing):

server {
listen 80;
listen [::]:80;
server_name chat.example.com;

# 普通上传默认上限 50MB(MAX_UPLOAD_BYTES),留出余量
client_max_body_size 100m;

location / {
proxy_pass http://127.0.0.1:8787;

# SSE 流式输出
proxy_buffering off;
proxy_read_timeout 3600s;
proxy_http_version 1.1;
proxy_set_header Connection "";

# 真实客户端 IP(配合下一步的 real_ip 配置)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
Combination of Flexible + OAuth

The source station link in the Flexible mode is HTTP, if you have configured OAuth logins, select OAUTH_CALLBACK_BASE_URL Obviously external. https://chat.example.com Avoid returning addresses. http:// and synchronize the https referral address on the OAuth provider side. FAQ

Step 3: Source Station Nginx Restores Real Visitor IP

This step ** Not to omit. ** Aivory counts the stream limit according to the client IP maintenance, judging the rule is: only trusted when the direct link is an internal network or back-end address. X-Forwarded-For / X-Real-IP (Take the non-internal entry on the right side of it), and ignore these heads at the same time as the public network.

When the orange-cloud proxy is turned on, the TCP peer that the source station Nginx sees is the Cloudflare edge node. If it is not restored, the “real IP” that Nginx sends to the app is the Cloudflare node IP: Visitors worldwide are folded into a few Cloudflare node addresses, shared traffic limit count, and a single trigger limit will connect a large number of users.

Cloudflare will place real IPs of visitors CF-Connecting-IP Restore the real_ip module with Nginx: New /etc/nginx/conf.d/cloudflare-realip.conf The content is as follows:

# /etc/nginx/conf.d/cloudflare-realip.conf
# 信任的 Cloudflare 回源网段,官方列表:https://www.cloudflare.com/ips/
# IPv4
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;

# IPv6
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;

# 从 Cloudflare 注入的头里取访客真实 IP
real_ip_header CF-Connecting-IP;
sudo nginx -t
sudo systemctl reload nginx

The mainstream distribution. nginx.conf Default includes include /etc/nginx/conf.d/*.conf; (within HTTP blocks), the above file will automatically take effect; if your distribution does not, put this content in any HTTP blocks level configuration.

The working principle is a complete chain of trust:

  1. The real_ip module can be seen at the opposite end. set_real_ip_from In the white list. CF-Connecting-IP The value * is written $remote_addr * at this time $remote_addr The real IP of the visitor.
  2. The original server. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; No need to change, it adds the real IP after restoration. X-Forwarded-For Transfer to App.
  3. The app is directly linked to the end of the app. 127.0.0.1:8787), meeting the "internal / back-end" condition, so trust the head and take the most right-hand non-internal entry, which gets exactly the real IP of the visitor.

Verification: access to the site after re-load, tail -f /var/log/nginx/access.log The source IP should be your own public network IP, not the address of a Cloudflare web segment.

Will the web list change?

Cloudflare’s back source network segment has remained stable for many years, but it is still recommended to check the official pairs list from time to time.

{ curl -s https://www.cloudflare.com/ips-v4; echo; curl -s https://www.cloudflare.com/ips-v6; } \
| sed '/^$/d; s/^/set_real_ip_from /; s/$/;/'

SSE Long Connection: Open the box, but do not cache the API

Aivory’s AI response is streaming through SSE (Server-Sent Events) without WebSocket.Cloudflare’s proxy transmission to SSE is open-box for two reasons:

  • ** Free overtime ** Cloudflare proxy connections have a free overtime of about 100 seconds, while Aivory server sends a ping heartbeat every 15 seconds, the connection will never be judged as empty, and long answers and Deep Research tasks will not be interrupted. ** No additional configuration needed. **。
  • ** by BUSH ** Cloudflare does not do a total buffer on responses that do not enter the cache, so long as the API response is not cached, the token reaches the browser in real time.

Therefore, the only thing to guarantee on the Cloudflare side is:** /api/* Do not cache** (Cache Rule processing in the next section). proxy_buffering off With relaxed reading overtime must still be retained, see Reverse Proxy and HTTPS

Cache Rules: API bypass, static resources safely cache

Cloudflare is no cache. text/html Dynamic responses such as those with APIs can also work without rules in theory, but explicit statements can prevent global rules such as "Cache Everything" from being mistakenly opened later. Caching → Cache Rules There are two rules:

The Rulesmatching conditionsMovement isExplained
Fire is around.URI Path starts with /api/Bypass cacheEnsure SSE is never cached with all interfaces
Static resourcesURI Path starts with /assets/Eligible for cache, Edge TTL extension (for example 1 month)Construction of product file name with the content of the fingerprint, the content of the file name change, long cache is absolutely safe.

Rules Order: Around the API is placed in front (Cache Rules match in order).

Panel switches: what to turn off and what to open

switchedLocatedrecommendedReasons
Rocket LoaderSpeed → Optimization** closed **It rearranges script loading order, making it easy for SPA to create white screen or functional abnormalities.
Always Use HTTPSSSL/TLS → Edge Certificates** Opened **All of http:// Visit to Edge 301 https://
Auto MinifyNo need to treat.This feature has been downloaded by Cloudflare, no need to find it.
Brotli CompressionSpeedKeep in mind (open)Default is enabled.
HTTP/2 / HTTP/3NetworkKeep in mind (open)Default is enabled.
WebSocketsNetworknot relatedAivory streaming goes SSE, not WebSocket, this switch does not affect the switch and shutdown.

Bypass the request body upper limit and “backup import”

Cloudflare limits the size of individual requests by package:

The packageRequest a maximum limit
Free / Pro100MB
Business200MB
Enterprise500MB

Two categories of large requests for Aivory:

The SceneThe service limit.orange-cloud proxy is affected
General documents/documents uploaded (MAX_UPLOAD_BYTES)50MBNot affected, free package can be covered
Registration of administrators (MAX_BACKUP_BYTES)20GiB** Rejected by Cloudflare ** No package is enough.

Executive Administrator Backup of imports When archiving up to 20GiB, you have to bypass the Cloudflare agent and select one:

  1. ** Direct connection to the Internet (recommended) ** Direct access to the server or internal network http://127.0.0.1:8787 The admin console executes imports without any volume restrictions for Cloudflare and source Nginx.
  2. ** Gray-Cloud (DNS only) Subdomain ** Create a DNS record. direct.chat.example.com Proxy status is set. DNS only (grey cloud), direct source station imports. source station Nginx needs to prepare a server block for the domain name and client_max_body_size Move to 21g Reference to Reverse Proxy and HTTPS The large request section).
grey-cloud (DNS only) subdomains will expose the source station IP

DNS only records resolve directly to the real address of the source station, conflicting with the "hidden source station" target. It is recommended to delete the record after importation is completed, or use an internal connection from the start.

Project B: Cloudflare Tunnel

Tunnel from the source station. cloudflared The process ** Proactively out. ** Connect to the Cloudflare edge and get traffic back through the tunnel. Suitable for situations where there is no public network IP (home width NAT, internal server) or you don’t want to open any ports: a firewall can completely block the station, the source station IP is not exposed naturally, and no longer requires the source station Nginx and certificates.

Step 1: Create a Tunnel in the Panel

  1. Enter the Cloudflare panel. Zero Trust (First use requires initialization, free plan is available.)
  2. Networks → Tunnels → Create a tunnel Select the type of connector. Cloudflared with a name (such as aivory)。
  3. After creation, the page will display the installation command, which contains a long string of tokens (eyJh... Only copy the token itself, and the next step is to deliver it to the container as an environmental variable.

Step 2: Adding cloudflared services

deploy/docker-compose.prod.ymlservices Additional (and app The same level):

cloudflared:
image: cloudflare/cloudflared:latest
restart: unless-stopped
command: tunnel run
environment:
TUNNEL_TOKEN: ${TUNNEL_TOKEN:?请在 .env 中设置 Cloudflare Tunnel token}
networks:
- internal
depends_on:
app:
condition: service_healthy

.env Joining in :

TUNNEL_TOKEN=eyJh...你的token...

The point:

  • cloudflared Join an existing private network. internal and with app The container is directly interconnected, the return source does not leave the host.
  • Tunnel is a pure exit connection. cloudflared No need of anything. ports The Mapping.
  • app of service. ports can be admitted. "80:8787" Stretch to "127.0.0.1:8787:8787" All public network traffic goes through the tunnel, and the 8787 direct link is reserved for administrator backup imports (see below).
docker compose -f docker-compose.prod.yml up -d
docker compose -f docker-compose.prod.yml logs -f cloudflared # 看到 Registered tunnel connection 即连通

Step 3: Configuring a Public Hostname (ingress)

Return to the Tunnel. Public Hostname The label page, adding:

The field
Subdomainchat
Domainexample.com
TypeHTTP
URLapp:8787

The ingress direction. http://app:8787: cloudflaredapp Together with internal Cloudflare automatically creates the corresponding orange-cloud proxy DNS record, which is accessed by the browser. https://chat.example.com Open the Aivory.

Real IPs and Stream Limits in Tunnel Mode

Tunnel mode does not require Nginx, real IP links are automatically established: Cloudflare edge writes the visitor IP X-Forwarded-ForCF-Connecting-IP, cloudflared transmitted to app; app The opposite end is cloudflared The private network address of the container, which meets the conditions of trust, so take X-Forwarded-For The most right-hand non-intranet entry, i.e. the real IP of the visitor, can be verified once by the end list after deployment is completed.

Backup imports in tunnel mode

Tunnel traffic also passes through the edge of Cloudflare. ** The request body ceiling is completely consistent with the orange-cloud proxy. ** (Free/Pro from 100MB).20GiB-level backup imports still need to be bypassed: with the previously reserved 127.0.0.1:8787 It is imported directly on the server native, which is why compose recommends keeping the port mapping.

Comparison of two programs

DimensionsSolution A: orange-cloud proxyProject B: Cloudflare Tunnel
Public network IP / open portRequired at least 443No need for entry port.
Components of Source StationNginx + Certificate (Full strict)Cloudflared containers
Certificate operationsThe source station requires a true certificate (certbot or Origin CA)No, edge certificates are managed by Cloudflare
Hidden sourceorange-cloud proxy hides DNS, recommended with a firewall white listNatural hiding, firewalls can be completely sealed into the station
Real IP is restored.Requires the Nginx real_ip moduleAutomated, no configuration required
The SSE flow.Normal (15s heartbeat overtime covering the edge)Normal (with the left)
Request a maximum limitBy CF package (Free 100MB)the same
Backup of importsDirect Internet or grey-cloud (DNS only) subdomainsDirectly connected 127.0.0.1:8787
Faulty sideNginx, Certificate Renewal, CF ThreeCloudflared Process and CF

One suggestion: having a public network IP and already running Nginx, option A; new deployment, home width or not wanting to touch certificate, option B.

Finish checking the list.

Repeat after completion:

  • ** The SSL/TLS model ** Solution A is Full (strict) (or explicitly accepts Flexible's acceptance and the backlink is reliable); Solution B does not need to be set.
  • Always Use HTTPS Opened and visited. http://chat.example.com 301 to HTTPS.
  • Rocket Loader has been closed.
  • Cache Rules: /api/* The bypass cache rule exists and ranks first.
  • ** Reviews of OAuth ** (If OAuth login is enabled): OAUTH_CALLBACK_BASE_URL Set for external. https:// Domain names, OAuth provider-side referral addresses have been synchronized and updated. FAQ
  • ** SSE flow is normal. **: Send a message and reply should be written by word.If the card pops out after a long time, first check if the source station Nginx is missed. proxy_buffering off Check if there is a cache rule. /api/*
  • ** The limitation is effective on the real IP. ** Solution A View Nginx access log, source should be the visitor’s public network IP instead of the Cloudflare segment; Solution B Access from two different networks (such as mobile traffic and home broadband) confirms that there is no influence on each other’s flow limit count. If all users find a shared stream limit, review the real_ip configuration or X-Forwarded-For and transmitted.
  • ** Introduction to the passage. **: Confirmed to reserve direct access to the Internet (127.0.0.1:8787 If you are familiar with the grey-cloud (DNS only) subdomain practice, do not find a 100MB ceiling when data needs to be recovered.
  • ** Health inspection ** (If external distribution is used): the root path GET / Return 200 represents survival.

A common idea in case of disruption: first bypass the Cloudflare direct source station (native curl http://127.0.0.1:8787/ Confirm that the application itself is normal, then layer by layer examine the Nginx, Cloudflare panel configuration.