Skip to content

Commit 4afac29

Browse files
v3.0.5 - add support for dockflare.disable_chunked_encoding and dockflare.http2_origin
1 parent 134bcf7 commit 4afac29

File tree

11 files changed

+63
-3
lines changed

11 files changed

+63
-3
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
---
99

10+
## [v3.0.5] - 2025-10-14
11+
12+
### Added
13+
- **HTTP/2 Origin Support:** Added support for enabling HTTP/2 protocol between `cloudflared` and origin services via the new `dockflare.http2_origin` label and UI controls. Required for gRPC services. Only applies to HTTP/HTTPS services.
14+
- **Disable Chunked Encoding Support:** Added support for disabling chunked transfer encoding over HTTP/1.1 via the new `dockflare.disable_chunked_encoding` label and UI controls. Useful for WSGI servers (Flask, Django, FastAPI) and other origins that don't properly support chunked requests. Only applies to HTTP/HTTPS services.
15+
16+
---
17+
1018
## [v3.0.4] - 2025-10-11
1119

1220
### Added

README.MD

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</p>
1212

1313
<p align="center">
14-
<a href="https://github.com/ChrispyBacon-dev/DockFlare/releases"><img src="https://img.shields.io/badge/Release-v3.0.4-blue.svg?style=for-the-badge" alt="Release"></a>
14+
<a href="https://github.com/ChrispyBacon-dev/DockFlare/releases"><img src="https://img.shields.io/badge/Release-v3.0.5-blue.svg?style=for-the-badge" alt="Release"></a>
1515
<a href="https://hub.docker.com/r/alplat/dockflare"><img src="https://img.shields.io/docker/pulls/alplat/dockflare?style=for-the-badge" alt="Docker Pulls"></a>
1616
<a href="https://www.python.org/"><img src="https://img.shields.io/badge/Made%20with-Python-1f425f.svg?style=for-the-badge" alt="Python"></a>
1717
<a href="https://github.com/ChrispyBacon-dev/DockFlare/blob/main/LICENSE.MD"><img src="https://img.shields.io/badge/License-GPL--3.0-blue.svg?style=for-the-badge" alt="License"></a>

dockflare/app/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def _get_int_env(name, default, minimum=None):
3434
return default
3535

3636
# --- DockFlare Version ---
37-
APP_VERSION = "v3.0.4"
37+
APP_VERSION = "v3.0.5"
3838
# --- web: https://dockflare.app ---
3939
# --- github: https://github.com/ChrispyBacon-dev/DockFlare ---
4040

dockflare/app/core/docker_handler.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ def process_container_start(container_obj):
158158
zone_name_label = get_label(labels, "zonename")
159159
no_tls_verify_label = get_label(labels, "no_tls_verify", "false").lower() in ["true", "1", "t", "yes"]
160160
http2_origin_label = get_label(labels, "http2_origin", "false").lower() in ["true", "1", "t", "yes"]
161+
disable_chunked_encoding_label = get_label(labels, "disable_chunked_encoding", "false").lower() in ["true", "1", "t", "yes"]
161162

162163
if hostname_label and service_label:
163164
if is_valid_hostname(hostname_label) and is_valid_service(service_label):
@@ -168,6 +169,7 @@ def process_container_start(container_obj):
168169
"origin_server_name": default_originsrvname_label.strip() if default_originsrvname_label else None,
169170
"http_host_header": default_http_host_header_label.strip() if default_http_host_header_label else None,
170171
"http2_origin": http2_origin_label,
172+
"disable_chunked_encoding": disable_chunked_encoding_label,
171173
"access_group": default_access_group,
172174
"access_policy_type": default_access_policy_type_label,
173175
"access_app_name": default_access_app_name_label,
@@ -198,6 +200,8 @@ def process_container_start(container_obj):
198200
http_host_header_indexed_val = get_label(labels, f"{index}.httpHostHeader", default_http_host_header_label)
199201
http2_origin_indexed_val = get_label(labels, f"{index}.http2_origin", str(http2_origin_label).lower())
200202
http2_origin_indexed = http2_origin_indexed_val.lower() in ["true", "1", "t", "yes"]
203+
disable_chunked_encoding_indexed_val = get_label(labels, f"{index}.disable_chunked_encoding", str(disable_chunked_encoding_label).lower())
204+
disable_chunked_encoding_indexed = disable_chunked_encoding_indexed_val.lower() in ["true", "1", "t", "yes"]
201205

202206
access_groups_indexed = get_label(labels, f"{index}.access.groups")
203207
raw_access_group_indexed = get_label(labels, f"{index}.access.group") if not access_groups_indexed else None
@@ -249,6 +253,7 @@ def process_container_start(container_obj):
249253
"origin_server_name": originsrvname_indexed_val.strip() if originsrvname_indexed_val else None,
250254
"http_host_header": http_host_header_indexed_val.strip() if http_host_header_indexed_val else None,
251255
"http2_origin": http2_origin_indexed,
256+
"disable_chunked_encoding": disable_chunked_encoding_indexed,
252257
"access_group": access_group_indexed,
253258
"access_policy_type": access_policy_type_indexed,
254259
"access_app_name": access_app_name_indexed,
@@ -291,6 +296,7 @@ def process_container_start(container_obj):
291296
origin_server_name_from_item = config_item.get("origin_server_name")
292297
http_host_header_from_item = config_item.get("http_host_header")
293298
http2_origin_from_item = config_item.get("http2_origin", False)
299+
disable_chunked_encoding_from_item = config_item.get("disable_chunked_encoding", False)
294300

295301
target_zone_id = None
296302
detected_zone_name = zone_name_from_item
@@ -358,6 +364,9 @@ def process_container_start(container_obj):
358364
if existing_rule.get("http2_origin") != http2_origin_from_item:
359365
existing_rule["http2_origin"] = http2_origin_from_item
360366
rule_data_changed = True
367+
if existing_rule.get("disable_chunked_encoding") != disable_chunked_encoding_from_item:
368+
existing_rule["disable_chunked_encoding"] = disable_chunked_encoding_from_item
369+
rule_data_changed = True
361370

362371
existing_rule["source"] = "docker"
363372
if master_tunnel_id and existing_rule.get("tunnel_id") != master_tunnel_id:
@@ -394,6 +403,7 @@ def process_container_start(container_obj):
394403
"origin_server_name": origin_server_name_from_item,
395404
"http_host_header": http_host_header_from_item,
396405
"http2_origin": http2_origin_from_item,
406+
"disable_chunked_encoding": disable_chunked_encoding_from_item,
397407
"access_app_id": None,
398408
"access_policy_type": None,
399409
"access_app_config_hash": None,

dockflare/app/core/state_manager.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def load_state():
144144
rule_copy.setdefault("no_tls_verify", False)
145145
rule_copy.setdefault("origin_server_name", None)
146146
rule_copy.setdefault("http2_origin", False)
147+
rule_copy.setdefault("disable_chunked_encoding", False)
147148

148149
tunnel_name = rule_copy.get("tunnel_name")
149150
if not tunnel_name or tunnel_name == "dockflare-tunnel":
@@ -502,6 +503,7 @@ def save_state():
502503
"origin_server_name": rule.get("origin_server_name"),
503504
"http_host_header": rule.get("http_host_header"),
504505
"http2_origin": rule.get("http2_origin", False),
506+
"disable_chunked_encoding": rule.get("disable_chunked_encoding", False),
505507
"access_app_id": rule.get("access_app_id"),
506508
"access_policy_type": rule.get("access_policy_type"),
507509
"access_app_config_hash": rule.get("access_app_config_hash"),

dockflare/app/core/tunnel_manager.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ def _build_ingress_entry_from_rule(rule_details):
263263
origin_request["httpHostHeader"] = http_host_header
264264
if rule_details.get("http2_origin"):
265265
origin_request["http2Origin"] = True
266+
if rule_details.get("disable_chunked_encoding"):
267+
origin_request["disableChunkedEncoding"] = True
266268
if origin_request:
267269
entry["originRequest"] = origin_request
268270
return entry
@@ -302,7 +304,8 @@ def _ingress_to_comparable(rule):
302304
origin_name = origin.get("originServerName") or ""
303305
http_host = origin.get("httpHostHeader") or ""
304306
http2_origin = bool(origin.get("http2Origin"))
305-
return (hostname, service, path, no_tls, origin_name, http_host, http2_origin)
307+
disable_chunked = bool(origin.get("disableChunkedEncoding"))
308+
return (hostname, service, path, no_tls, origin_name, http_host, http2_origin, disable_chunked)
306309

307310

308311
def _is_catch_all_rule(rule):

dockflare/app/static/js/main.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ function initializeEditRuleModal() {
232232
const http2OriginField = modal.querySelector('#edit_http2_origin');
233233
if (http2OriginField) http2OriginField.checked = details.http2_origin || false;
234234

235+
const disableChunkedEncodingField = modal.querySelector('#edit_disable_chunked_encoding');
236+
if (disableChunkedEncodingField) disableChunkedEncodingField.checked = details.disable_chunked_encoding || false;
237+
235238
const tunnelDisplay = modal.querySelector('#edit_rule_tunnel_value');
236239
const zoneDisplay = modal.querySelector('#edit_rule_zone_value');
237240
const agentHint = modal.querySelector('#edit_rule_agent_hint');

dockflare/app/templates/docs/Container-Labels.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ These labels control the fundamental routing and service definition for a contai
1717
| `dockflare.originsrvname` | Sets a specific Server Name Indication (SNI) hostname for the TLS connection to the origin. This is also known as "Origin Server Name" in the Cloudflare dashboard. | `dockflare.originsrvname=internal.service.local` |
1818
| `dockflare.httpHostHeader` | Overrides the `Host` header sent from `cloudflared` to your origin service. | `dockflare.httpHostHeader=custom-host.internal` |
1919
| `dockflare.http2_origin` | If set to `true`, enables HTTP/2 protocol for the connection between `cloudflared` and your origin service. Required for gRPC services. Only applies to HTTP/HTTPS services. | `dockflare.http2_origin=true` |
20+
| `dockflare.disable_chunked_encoding` | If set to `true`, disables chunked transfer encoding over HTTP/1.1. Useful for WSGI servers (Flask, Django, FastAPI) and other origins that don't properly support chunked requests. Only applies to HTTP/HTTPS services. | `dockflare.disable_chunked_encoding=true` |
2021

2122
> **Tip:** Starting with DockFlare v3.0, you can skip `dockflare.zonename` for most workloads. The master detects the correct Cloudflare zone by matching the hostname suffix and only falls back to the configured default zone when it cannot find a match. Provide the label when you intentionally want to place a record in a different zone.
2223

dockflare/app/templates/status_page.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ <h3 class="font-bold text-xs uppercase opacity-80">Last Action</h3>
200200
{% if details.http2_origin %}
201201
<span class="badge badge-success badge-xs ml-1" title="HTTP/2 protocol enabled for origin connection">HTTP/2 Origin</span>
202202
{% endif %}
203+
{% if details.disable_chunked_encoding %}
204+
<span class="badge badge-info badge-xs ml-1" title="Chunked transfer encoding disabled for HTTP/1.1">No Chunked Encoding</span>
205+
{% endif %}
203206
</div>
204207
</td>
205208
<td class="p-3 whitespace-nowrap">
@@ -513,6 +516,13 @@ <h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
513516
</label>
514517
<div class="text-xs opacity-60 ml-8">Enable HTTP/2 protocol between Cloudflare and your origin server. Required for gRPC services. (Only applies to HTTP/HTTPS services).</div>
515518
</div>
519+
<div id="manual_disable_chunked_encoding_div" class="form-control">
520+
<label class="label cursor-pointer justify-start gap-2">
521+
<input type="checkbox" name="manual_disable_chunked_encoding" id="manual_disable_chunked_encoding" class="checkbox checkbox-sm" />
522+
<span class="label-text">Disable Chunked Encoding</span>
523+
</label>
524+
<div class="text-xs opacity-60 ml-8">Disables chunked transfer encoding over HTTP/1.1. Useful for WSGI servers (Flask, Django) and other origins that don't support chunked requests. (Only applies to HTTP/HTTPS services).</div>
525+
</div>
516526
</div>
517527
</div>
518528
<div id="manual_rule_feedback" class="hidden alert mt-4"></div>
@@ -657,6 +667,13 @@ <h4 class="text-md font-semibold mb-2">Access Policy (Optional)</h4>
657667
</label>
658668
<div class="text-xs opacity-60 ml-8">Enable HTTP/2 protocol between Cloudflare and your origin server. Required for gRPC services. (Only applies to HTTP/HTTPS services).</div>
659669
</div>
670+
<div id="edit_disable_chunked_encoding_div" class="form-control">
671+
<label class="label cursor-pointer justify-start gap-2">
672+
<input type="checkbox" name="edit_disable_chunked_encoding" id="edit_disable_chunked_encoding" class="checkbox checkbox-sm" />
673+
<span class="label-text">Disable Chunked Encoding</span>
674+
</label>
675+
<div class="text-xs opacity-60 ml-8">Disables chunked transfer encoding over HTTP/1.1. Useful for WSGI servers (Flask, Django) and other origins that don't support chunked requests. (Only applies to HTTP/HTTPS services).</div>
676+
</div>
660677
</div>
661678
</div>
662679
<div class="modal-action mt-8 pt-4 border-t border-base-300">

dockflare/app/web/api_v2_routes.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ def create_manual_rule_api():
563563
"origin_server_name": None,
564564
"http_host_header": None,
565565
"http2_origin": False,
566+
"disable_chunked_encoding": False,
566567
"access_app_id": None,
567568
"access_policy_type": None,
568569
"access_app_config_hash": None,
@@ -814,6 +815,7 @@ def process_agent_container_start(payload, agent_id):
814815
zone_name_label = get_label(labels, "zonename")
815816
no_tls_verify_label = get_label(labels, "no_tls_verify", "false").lower() in ["true", "1", "t", "yes"]
816817
http2_origin_label = get_label(labels, "http2_origin", "false").lower() in ["true", "1", "t", "yes"]
818+
disable_chunked_encoding_label = get_label(labels, "disable_chunked_encoding", "false").lower() in ["true", "1", "t", "yes"]
817819

818820
if hostname_label and service_label:
819821
if is_valid_hostname(hostname_label) and is_valid_service(service_label):
@@ -826,6 +828,7 @@ def process_agent_container_start(payload, agent_id):
826828
"origin_server_name": default_originsrvname_label.strip() if default_originsrvname_label else None,
827829
"http_host_header": default_http_host_header_label.strip() if default_http_host_header_label else None,
828830
"http2_origin": http2_origin_label,
831+
"disable_chunked_encoding": disable_chunked_encoding_label,
829832
"access_group": default_access_group,
830833
"access_policy_type": default_access_policy_type_label,
831834
"access_app_name": default_access_app_name_label,
@@ -856,6 +859,8 @@ def process_agent_container_start(payload, agent_id):
856859
http_host_header_indexed_val = get_label(labels, f"{index}.httpHostHeader", default_http_host_header_label)
857860
http2_origin_indexed_val = get_label(labels, f"{index}.http2_origin", str(http2_origin_label).lower())
858861
http2_origin_indexed = http2_origin_indexed_val.lower() in ["true", "1", "t", "yes"]
862+
disable_chunked_encoding_indexed_val = get_label(labels, f"{index}.disable_chunked_encoding", str(disable_chunked_encoding_label).lower())
863+
disable_chunked_encoding_indexed = disable_chunked_encoding_indexed_val.lower() in ["true", "1", "t", "yes"]
859864

860865
access_groups_indexed = get_label(labels, f"{index}.access.groups")
861866
raw_access_group_indexed = get_label(labels, f"{index}.access.group") if not access_groups_indexed else None
@@ -909,6 +914,7 @@ def process_agent_container_start(payload, agent_id):
909914
"origin_server_name": originsrvname_indexed_val.strip() if originsrvname_indexed_val else None,
910915
"http_host_header": http_host_header_indexed_val.strip() if http_host_header_indexed_val else None,
911916
"http2_origin": http2_origin_indexed,
917+
"disable_chunked_encoding": disable_chunked_encoding_indexed,
912918
"access_group": access_group_indexed,
913919
"access_policy_type": access_policy_type_indexed,
914920
"access_app_name": access_app_name_indexed,
@@ -946,7 +952,9 @@ def process_agent_container_start(payload, agent_id):
946952
zone_name_from_item = config_item["zone_name"]
947953
no_tls_verify_from_item = config_item["no_tls_verify"]
948954
origin_server_name_from_item = config_item.get("origin_server_name")
955+
http_host_header_from_item = config_item.get("http_host_header")
949956
http2_origin_from_item = config_item.get("http2_origin", False)
957+
disable_chunked_encoding_from_item = config_item.get("disable_chunked_encoding", False)
950958

951959
target_zone_id = None
952960
if zone_name_from_item:
@@ -996,6 +1004,9 @@ def process_agent_container_start(payload, agent_id):
9961004
if existing_rule.get("http2_origin") != http2_origin_from_item:
9971005
existing_rule["http2_origin"] = http2_origin_from_item
9981006
rule_data_changed = True
1007+
if existing_rule.get("disable_chunked_encoding") != disable_chunked_encoding_from_item:
1008+
existing_rule["disable_chunked_encoding"] = disable_chunked_encoding_from_item
1009+
rule_data_changed = True
9991010
if existing_rule.get("tunnel_name") != assigned_tunnel_name:
10001011
existing_rule["tunnel_name"] = assigned_tunnel_name
10011012
rule_data_changed = True
@@ -1033,6 +1044,7 @@ def process_agent_container_start(payload, agent_id):
10331044
"origin_server_name": origin_server_name_from_item,
10341045
"http_host_header": config_item.get("http_host_header"),
10351046
"http2_origin": http2_origin_from_item,
1047+
"disable_chunked_encoding": disable_chunked_encoding_from_item,
10361048
"access_app_id": None,
10371049
"access_policy_type": None,
10381050
"access_app_config_hash": None,

0 commit comments

Comments
 (0)