Repository: envoyproxy/gateway

Issue:
docs: HTTP Connect based Tunnels
*Description*:
>Describe the issue.

Add docs for this feature

Relates to https://github.com/envoyproxy/gateway/issues/3663

[optional *Relevant Links*:]
>Any extra documentation required to understand the issue.


Hints from issue comments:

Solution patch:
diff --git a/site/content/en/v1.5/tasks/traffic/http-connect-tunnels.md b/site/content/en/v1.5/tasks/traffic/http-connect-tunnels.md
new file mode 100644
index 000000000..a3c782390
--- /dev/null
+++ b/site/content/en/v1.5/tasks/traffic/http-connect-tunnels.md
@@ -0,0 +1,175 @@
+---
+title: "HTTP CONNECT Tunnels"
+---
+
+HTTP CONNECT tunnels are a mechanism that allows a client to establish a tunnel through an HTTP proxy server 
+to communicate directly with a destination server. This is commonly used for HTTPS traffic through proxies, 
+but can also be used for other protocols.
+
+This task will help you get started using HTTP Connect based tunnels using Envoy Gateway.
+
+## Prerequisites
+
+{{< boilerplate prerequisites >}}
+
+## Proxy CONNECT request
+
+Envoy Gateway supports proxy CONNECT requests, allowing you to route traffic through a Gateway and HTTPRoute to a Backend service.
+
+```mermaid
+graph LR
+    Client--CONNECT-->ProxyEnvoy[proxy the CONNECT request]
+    ProxyEnvoy[proxy the CONNECT request]--CONNECT-->Socat
+```
+
+Create a Gateway and HTTPRoute to route proxy CONNECT requests to a Backend service:
+
+```shell
+cat <<EOF | kubectl apply -f -
+# curl -ik -v -x 172.18.0.201:80 https://www.httpbin.org | grep -o "<title>.*</title>"
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: connect-proxy
+spec:
+  gatewayClassName: eg
+  listeners:
+    - name: http
+      protocol: HTTP
+      port: 80
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: connect-proxy
+spec:
+  parentRefs:
+    - group: gateway.networking.k8s.io
+      kind: Gateway
+      name: connect-proxy
+  rules:
+    - backendRefs:
+        - group: ""
+          kind: Service
+          name: socat
+          port: 8080
+      matches:
+        - path:
+            type: PathPrefix
+            value: /
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: BackendTrafficPolicy
+metadata:
+  name: connect-proxy
+spec:
+  targetRef:
+    group: gateway.networking.k8s.io
+    kind: Gateway
+    name: connect-proxy
+  httpUpgrade:
+    - type: CONNECT
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: socat
+spec:
+  selector:
+    matchLabels:
+      app: socat
+  template:
+    metadata:
+      labels:
+        app: socat
+    spec:
+      serviceAccountName: socat
+      containers:
+        - name: socat
+          image: alpine/socat:1.8.0.3
+          command:
+            - socat
+            - TCP-LISTEN:8080,fork,reuseaddr
+            - TCP:httpbin.org:80
+          imagePullPolicy: IfNotPresent
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: socat
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: socat
+  labels:
+    app: socat
+spec:
+  ports:
+    - port: 8080
+      name: http
+  selector:
+    app: socat
+---
+EOF
+```
+
+Verify the Gateway status:
+
+```shell
+kubectl get gateway/connect-proxy -o yaml
+```
+
+### Testing
+
+{{< tabpane text=true >}}
+{{% tab header="With External LoadBalancer Support" %}}
+
+Get the External IP of the Gateway:
+
+```shell
+export PROXY_GATEWAY_HOST=$(kubectl get gateway/connect-proxy -o jsonpath='{.status.addresses[0].value}')
+```
+
+```shell
+curl -ik -v -x ${PROXY_GATEWAY_HOST}:80 https://httpbin.org | grep -o "<title>.*</title>"
+```
+
+Verify the method from the access log:
+
+```shell
+kubectl logs -n envoy-gateway-system deployments/envoy-default-connect-proxy-f7d7286e | tail -n 1 | jq | grep method
+```
+
+{{% /tab %}}
+{{% tab header="Without LoadBalancer Support" %}}
+
+Get the name of the Envoy service created the by the example Gateway:
+
+```shell
+export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=connect-proxy -o jsonpath='{.items[0].metadata.name}')
+```
+
+Port forward to the Envoy service:
+
+```shell
+kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8080:80 &
+```
+
+```shell
+curl -ik -v -x localhost:8080 https://httpbin.org
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+## Clean up
+
+```shell
+kubectl delete HTTPRoute connect-proxy
+kubectl delete Gateway connect-proxy
+kubectl delete BackendTrafficPolicy connect-proxy
+kubectl delete deployment socat
+kubectl delete service socat
+kubectl delete serviceaccount socat
+```
\ No newline at end of file
diff --git a/tools/hack/cherrypick-for-patch-release.sh b/tools/hack/cherrypick-for-patch-release.sh
new file mode 100755
index 000000000..02d1f6183
--- /dev/null
+++ b/tools/hack/cherrypick-for-patch-release.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+
+# shellcheck disable=SC2207,SC2145,SC2181
+
+REPO=${REPO:-"envoyproxy/gateway"}
+LABEL=${LABEL:-"cherrypick/release-v1.5.1"}
+DRY_RUN=${DRY_RUN:-true}
+# SKIP specific PR numbers, e.g. "123 456" after resolved conflicts.
+SKIP_PR_NUMBERS=${SKIP_PR_NUMBERS:-""}
+
+if ! command -v jq >/dev/null 2>&1; then
+  echo "jq is not installed, exiting."
+  exit 1
+fi
+
+if ! command -v curl >/dev/null 2>&1; then
+  echo "curl is not installed, exiting."
+  exit 1
+fi
+
+if [[ -z "$GITHUB_TOKEN" ]]; then
+  echo "GITHUB_TOKEN not found, exiting."
+  exit 1
+fi
+
+# ensure we are in a git repo and not on the main branch
+if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
+  echo "Not inside a git repository, exiting."
+  exit 1
+fi
+
+CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
+if [[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]]; then
+  echo "On main or master branch, please switch to a feature or release branch."
+  exit 1
+fi
+
+# current branch should create from the target release branch
+# e.g. for LABEL=cherrypick/release-v1.5.1
+# git checkout release/v1.5
+# git checkout -b cherry-pick/v1.5.1
+BRANCH_SUFFIX=${LABEL#cherrypick/release-}
+TARGET_BRANCH="cherry-pick/$BRANCH_SUFFIX"
+if [[ "$CURRENT_BRANCH" != "$TARGET_BRANCH" ]]; then
+  echo "Current branch $CURRENT_BRANCH does not match $TARGET_BRANCH, exiting."
+  exit 1
+fi
+
+# get all merged PR numbers with the specified label, sorted by merged date ascending
+PR_NUMBERS=($(curl -s -H "Authorization: token $GITHUB_TOKEN" \
+  "https://api.github.com/repos/$REPO/pulls?state=closed&per_page=100" | \
+  jq -r ".[] | select(.labels[].name==\"$LABEL\" and .merged_at!=null) | {number, merged_at}" | \
+  jq -s "sort_by(.merged_at) | .[].number"))
+
+echo "Total PRs to cherry-pick: ${#PR_NUMBERS[@]}"
+echo "PR_NUMBERS: ${PR_NUMBERS[@]}"
+
+# cherry-pick each PR by its merge commit SHA
+for PR in "${PR_NUMBERS[@]}"; do
+  if [[ "$SKIP_PR_NUMBERS" == *"$PR"* ]]; then
+    echo "Skipping PR #$PR as it is in SKIP_PR_NUMBERS"
+    continue
+  fi
+
+  SHA=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
+    "https://api.github.com/repos/$REPO/pulls/$PR" | \
+    jq -r ".merge_commit_sha")
+
+  echo "PR #$PR merge commit SHA: $SHA"
+  if [[ -z "$SHA" || "$SHA" == "null" ]]; then
+    echo "PR #$PR merge commit $SHA not found"
+    exit 1
+  fi
+  echo "Cherry-pick PR #$PR commit $SHA"
+  if [[ "$DRY_RUN" == "true" ]]; then
+    echo "Dry run: git cherry-pick PR #$PR with SHA: $SHA"
+    continue
+  fi
+  git cherry-pick "$SHA"
+  make build
+  if [[ $? -ne 0 ]]; then
+    echo "Cherry-pick $SHA failed, please resolve conflicts and run the script again."
+    exit 1
+  fi
+done



Test patch:
diff --git a/site/content/en/latest/tasks/traffic/http-connect-tunnels.md b/site/content/en/latest/tasks/traffic/http-connect-tunnels.md
new file mode 100644
index 000000000..a3c782390
--- /dev/null
+++ b/site/content/en/latest/tasks/traffic/http-connect-tunnels.md
@@ -0,0 +1,175 @@
+---
+title: "HTTP CONNECT Tunnels"
+---
+
+HTTP CONNECT tunnels are a mechanism that allows a client to establish a tunnel through an HTTP proxy server 
+to communicate directly with a destination server. This is commonly used for HTTPS traffic through proxies, 
+but can also be used for other protocols.
+
+This task will help you get started using HTTP Connect based tunnels using Envoy Gateway.
+
+## Prerequisites
+
+{{< boilerplate prerequisites >}}
+
+## Proxy CONNECT request
+
+Envoy Gateway supports proxy CONNECT requests, allowing you to route traffic through a Gateway and HTTPRoute to a Backend service.
+
+```mermaid
+graph LR
+    Client--CONNECT-->ProxyEnvoy[proxy the CONNECT request]
+    ProxyEnvoy[proxy the CONNECT request]--CONNECT-->Socat
+```
+
+Create a Gateway and HTTPRoute to route proxy CONNECT requests to a Backend service:
+
+```shell
+cat <<EOF | kubectl apply -f -
+# curl -ik -v -x 172.18.0.201:80 https://www.httpbin.org | grep -o "<title>.*</title>"
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: connect-proxy
+spec:
+  gatewayClassName: eg
+  listeners:
+    - name: http
+      protocol: HTTP
+      port: 80
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: connect-proxy
+spec:
+  parentRefs:
+    - group: gateway.networking.k8s.io
+      kind: Gateway
+      name: connect-proxy
+  rules:
+    - backendRefs:
+        - group: ""
+          kind: Service
+          name: socat
+          port: 8080
+      matches:
+        - path:
+            type: PathPrefix
+            value: /
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: BackendTrafficPolicy
+metadata:
+  name: connect-proxy
+spec:
+  targetRef:
+    group: gateway.networking.k8s.io
+    kind: Gateway
+    name: connect-proxy
+  httpUpgrade:
+    - type: CONNECT
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: socat
+spec:
+  selector:
+    matchLabels:
+      app: socat
+  template:
+    metadata:
+      labels:
+        app: socat
+    spec:
+      serviceAccountName: socat
+      containers:
+        - name: socat
+          image: alpine/socat:1.8.0.3
+          command:
+            - socat
+            - TCP-LISTEN:8080,fork,reuseaddr
+            - TCP:httpbin.org:80
+          imagePullPolicy: IfNotPresent
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: socat
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: socat
+  labels:
+    app: socat
+spec:
+  ports:
+    - port: 8080
+      name: http
+  selector:
+    app: socat
+---
+EOF
+```
+
+Verify the Gateway status:
+
+```shell
+kubectl get gateway/connect-proxy -o yaml
+```
+
+### Testing
+
+{{< tabpane text=true >}}
+{{% tab header="With External LoadBalancer Support" %}}
+
+Get the External IP of the Gateway:
+
+```shell
+export PROXY_GATEWAY_HOST=$(kubectl get gateway/connect-proxy -o jsonpath='{.status.addresses[0].value}')
+```
+
+```shell
+curl -ik -v -x ${PROXY_GATEWAY_HOST}:80 https://httpbin.org | grep -o "<title>.*</title>"
+```
+
+Verify the method from the access log:
+
+```shell
+kubectl logs -n envoy-gateway-system deployments/envoy-default-connect-proxy-f7d7286e | tail -n 1 | jq | grep method
+```
+
+{{% /tab %}}
+{{% tab header="Without LoadBalancer Support" %}}
+
+Get the name of the Envoy service created the by the example Gateway:
+
+```shell
+export ENVOY_SERVICE=$(kubectl get svc -n envoy-gateway-system --selector=gateway.envoyproxy.io/owning-gateway-namespace=default,gateway.envoyproxy.io/owning-gateway-name=connect-proxy -o jsonpath='{.items[0].metadata.name}')
+```
+
+Port forward to the Envoy service:
+
+```shell
+kubectl -n envoy-gateway-system port-forward service/${ENVOY_SERVICE} 8080:80 &
+```
+
+```shell
+curl -ik -v -x localhost:8080 https://httpbin.org
+```
+
+{{% /tab %}}
+{{< /tabpane >}}
+
+## Clean up
+
+```shell
+kubectl delete HTTPRoute connect-proxy
+kubectl delete Gateway connect-proxy
+kubectl delete BackendTrafficPolicy connect-proxy
+kubectl delete deployment socat
+kubectl delete service socat
+kubectl delete serviceaccount socat
+```
\ No newline at end of file