diff --git a/ci/do_ci.sh b/ci/do_ci.sh
index e832dd61ff31e..e8a55c150e034 100755
--- a/ci/do_ci.sh
+++ b/ci/do_ci.sh
@@ -471,7 +471,7 @@ elif [[ "$CI_TARGET" == "tooling" ]]; then
bazel run "${BAZEL_BUILD_OPTIONS[@]}" //tools/testing:all_pytests -- --cov-html /source/generated/tooling "${ENVOY_SRCDIR}"
exit 0
elif [[ "$CI_TARGET" == "verify_examples" ]]; then
- run_ci_verify "*" wasm-cc
+ run_ci_verify "*" "wasm-cc|win32-front-proxy"
exit 0
elif [[ "$CI_TARGET" == "verify_build_examples" ]]; then
run_ci_verify wasm-cc
diff --git a/ci/verify_examples.sh b/ci/verify_examples.sh
index 8f78d54e1a297..8ec2b0701d3e4 100755
--- a/ci/verify_examples.sh
+++ b/ci/verify_examples.sh
@@ -29,7 +29,8 @@ trap exit 1 INT
run_examples () {
local examples example
cd "${SRCDIR}/examples" || exit 1
- examples=$(find . -mindepth 1 -maxdepth 1 -type d -name "$TESTFILTER" ! -iname "_*" ! -name "$TESTEXCLUDES" | sort)
+
+ examples=$(find . -mindepth 1 -maxdepth 1 -type d -name "$TESTFILTER" ! -iname "_*" | grep -Ev "$TESTEXCLUDES" | sort)
for example in $examples; do
pushd "$example" > /dev/null || return 1
./verify.sh
diff --git a/docs/root/start/sandboxes/index.rst b/docs/root/start/sandboxes/index.rst
index cadaaaa45bb13..75dcb29c91d2d 100644
--- a/docs/root/start/sandboxes/index.rst
+++ b/docs/root/start/sandboxes/index.rst
@@ -69,4 +69,5 @@ The following sandboxes are available:
udp
wasm-cc
websocket
+ win32_front_proxy
zipkin_tracing
diff --git a/docs/root/start/sandboxes/setup.rst b/docs/root/start/sandboxes/setup.rst
index 6f4c6067bbda7..eb1c1193823ba 100644
--- a/docs/root/start/sandboxes/setup.rst
+++ b/docs/root/start/sandboxes/setup.rst
@@ -37,6 +37,9 @@ The user account running the examples will need to have permission to use Docker
Full instructions for installing Docker can be found on the `Docker website `_
+If you want to use the Windows based Envoy images make sure that you
+`switch Docker to use Windows containers `_.
+
.. _start_sandboxes_setup_docker_compose:
Install Docker Compose
diff --git a/docs/root/start/sandboxes/win32_front_proxy.rst b/docs/root/start/sandboxes/win32_front_proxy.rst
new file mode 100644
index 0000000000000..625bc6ce2e551
--- /dev/null
+++ b/docs/root/start/sandboxes/win32_front_proxy.rst
@@ -0,0 +1,352 @@
+Windows based Front proxy
+=========================
+
+.. sidebar:: Requirements
+
+ .. include:: _include/docker-env-setup-link.rst
+
+To get a flavor of what Envoy has to offer on Windows, we are releasing a
+`docker compose `_ sandbox that deploys a front Envoy and a
+couple of services (simple Flask apps) colocated with a running service Envoy.
+
+The three containers will be deployed inside a virtual network called ``envoymesh``.
+
+Below you can see a graphic showing the docker compose deployment:
+
+.. image:: /_static/docker_compose_front_proxy.svg
+ :width: 100%
+
+All incoming requests are routed via the front Envoy, which is acting as a reverse proxy sitting on
+the edge of the ``envoymesh`` network. Port ``8080``, ``8443``, and ``8001`` are exposed by docker
+compose (see :download:`docker-compose.yaml <_include/front-proxy/docker-compose.yaml>`) to handle
+``HTTP``, ``HTTPS`` calls to the services and requests to ``/admin`` respectively.
+
+Moreover, notice that all traffic routed by the front Envoy to the service containers is actually
+routed to the service Envoys (routes setup in :download:`front-envoy.yaml <_include/front-proxy/front-envoy.yaml>`).
+
+In turn the service Envoys route the request to the Flask app via the loopback
+address (routes setup in :download:`service-envoy.yaml <_include/front-proxy/service-envoy.yaml>`). This
+setup illustrates the advantage of running service Envoys collocated with your services: all
+requests are handled by the service Envoy, and efficiently routed to your services.
+
+Step 1: Start all of our containers
+***********************************
+
+Change to the ``examples/front-proxy`` directory.
+
+.. code-block:: console
+
+ PS> $PWD
+ D:\envoy\examples\win32-front-proxy
+ PS> docker-compose build --pull
+ PS> docker-compose up -d
+ PS> docker-compose ps
+ Name Command State Ports
+ ------------------------------------------------------------------------------------------------------------------------------------------------------------
+ envoy-front-proxy_front-envoy_1 powershell.exe ./start_env ... Up 10000/tcp, 0.0.0.0:8003->8003/tcp, 0.0.0.0:8080->8080/tcp, 0.0.0.0:8443->8443/tcp
+ envoy-front-proxy_service1_1 powershell.exe ./start_ser ... Up 10000/tcp
+ envoy-front-proxy_service2_1 powershell.exe ./start_ser ... Up 10000/tcp
+
+Step 2: Test Envoy's routing capabilities
+*****************************************
+
+You can now send a request to both services via the ``front-envoy``.
+
+For ``service1``:
+
+.. code-block:: console
+
+ PS> curl -v localhost:8080/service/1
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8080 (#0)
+ > GET /service/1 HTTP/1.1
+ > Host: localhost:8080
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 92
+ < server: envoy
+ < date: Wed, 05 May 2021 05:55:55 GMT
+ < x-envoy-upstream-service-time: 18
+ <
+ Hello from behind Envoy (service 1)! hostname: 8a45bba91d83 resolvedhostname: 172.30.97.237
+ * Connection #0 to host localhost left intact
+
+For ``service2``:
+
+.. code-block:: console
+
+ PS> curl -v localhost:8080/service/2
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8080 (#0)
+ > GET /service/2 HTTP/1.1
+ > Host: localhost:8080
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 93
+ < server: envoy
+ < date: Wed, 05 May 2021 05:57:03 GMT
+ < x-envoy-upstream-service-time: 14
+ <
+ Hello from behind Envoy (service 2)! hostname: 51e28eb3c8b8 resolvedhostname: 172.30.109.113
+ * Connection #0 to host localhost left intact
+
+Notice that each request, while sent to the front Envoy, was correctly routed to the respective
+application.
+
+We can also use ``HTTPS`` to call services behind the front Envoy. For example, calling ``service1``:
+
+.. code-block:: console
+
+ PS> curl https://localhost:8443/service/1 -k -v
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8443 (#0)
+ * schannel: SSL/TLS connection with localhost port 8443 (step 1/3)
+ * schannel: disabled server certificate revocation checks
+ * schannel: verifyhost setting prevents Schannel from comparing the supplied target name with the subject names in server certificates.
+ * schannel: sending initial handshake data: sending 171 bytes...
+ * schannel: sent initial handshake data: sent 171 bytes
+ * schannel: SSL/TLS connection with localhost port 8443 (step 2/3)
+ * schannel: failed to receive handshake, need more data
+ * schannel: SSL/TLS connection with localhost port 8443 (step 2/3)
+ * schannel: encrypted data got 1081
+ * schannel: encrypted data buffer: offset 1081 length 4096
+ * schannel: sending next handshake data: sending 93 bytes...
+ * schannel: SSL/TLS connection with localhost port 8443 (step 2/3)
+ * schannel: encrypted data got 258
+ * schannel: encrypted data buffer: offset 258 length 4096
+ * schannel: SSL/TLS handshake complete
+ * schannel: SSL/TLS connection with localhost port 8443 (step 3/3)
+ * schannel: stored credential handle in session cache
+ > GET /service/1 HTTP/1.1
+ > Host: localhost:8443
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ * schannel: client wants to read 102400 bytes
+ * schannel: encdata_buffer resized 103424
+ * schannel: encrypted data buffer: offset 0 length 103424
+ * schannel: encrypted data got 286
+ * schannel: encrypted data buffer: offset 286 length 103424
+ * schannel: decrypted data length: 257
+ * schannel: decrypted data added: 257
+ * schannel: decrypted data cached: offset 257 length 102400
+ * schannel: encrypted data buffer: offset 0 length 103424
+ * schannel: decrypted data buffer: offset 257 length 102400
+ * schannel: schannel_recv cleanup
+ * schannel: decrypted data returned 257
+ * schannel: decrypted data buffer: offset 0 length 102400
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 92
+ < server: envoy
+ < date: Wed, 05 May 2021 05:57:45 GMT
+ < x-envoy-upstream-service-time: 3
+ <
+ Hello from behind Envoy (service 1)! hostname: 8a45bba91d83 resolvedhostname: 172.30.97.237
+ * Connection #0 to host localhost left intact
+
+Step 3: Test Envoy's load balancing capabilities
+************************************************
+
+Now let's scale up our ``service1`` nodes to demonstrate the load balancing abilities of Envoy:
+
+.. code-block:: console
+
+ PS> docker-compose scale service1=3
+ Creating and starting example_service1_2 ... done
+ Creating and starting example_service1_3 ... done
+
+Now if we send a request to ``service1`` multiple times, the front Envoy will load balance the
+requests by doing a round robin of the three ``service1`` machines:
+
+.. code-block:: console
+
+ PS> curl -v localhost:8080/service/1
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8080 (#0)
+ > GET /service/1 HTTP/1.1
+ > Host: localhost:8080
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 93
+ < server: envoy
+ < date: Wed, 05 May 2021 05:58:40 GMT
+ < x-envoy-upstream-service-time: 22
+ <
+ Hello from behind Envoy (service 1)! hostname: 8d2359ee21a8 resolvedhostname: 172.30.101.143
+ * Connection #0 to host localhost left intact
+ PS> curl -v localhost:8080/service/1
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8080 (#0)
+ > GET /service/1 HTTP/1.1
+ > Host: localhost:8080
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 91
+ < server: envoy
+ < date: Wed, 05 May 2021 05:58:43 GMT
+ < x-envoy-upstream-service-time: 11
+ <
+ Hello from behind Envoy (service 1)! hostname: 41e1141eebf4 resolvedhostname: 172.30.96.11
+ * Connection #0 to host localhost left intact
+ PS> curl -v localhost:8080/service/1
+ * Trying ::1...
+ * TCP_NODELAY set
+ * Trying 127.0.0.1...
+ * TCP_NODELAY set
+ * Connected to localhost (127.0.0.1) port 8080 (#0)
+ > GET /service/1 HTTP/1.1
+ > Host: localhost:8080
+ > User-Agent: curl/7.55.1
+ > Accept: */*
+ >
+ < HTTP/1.1 200 OK
+ < content-type: text/html; charset=utf-8
+ < content-length: 92
+ < server: envoy
+ < date: Wed, 05 May 2021 05:58:44 GMT
+ < x-envoy-upstream-service-time: 7
+ <
+ Hello from behind Envoy (service 1)! hostname: 8a45bba91d83 resolvedhostname: 172.30.97.237
+ * Connection #0 to host localhost left intact
+
+Step 4: Enter containers and curl services
+******************************************
+
+In addition of using ``curl`` from your host machine, you can also enter the
+containers themselves and ``curl`` from inside them. To enter a container you
+can use ``docker-compose exec /bin/bash``. For example we can
+enter the ``front-envoy`` container, and ``curl`` for services locally:
+
+.. code-block:: console
+
+ PS> docker-compose exec front-envoy powershell
+ PS C:\> (curl -UseBasicParsing http://localhost:8080/service/1).Content
+ Hello from behind Envoy (service 1)! hostname: 41e1141eebf4 resolvedhostname: 172.30.96.11
+
+ PS C:\> (curl -UseBasicParsing http://localhost:8080/service/1).Content
+ Hello from behind Envoy (service 1)! hostname: 8a45bba91d83 resolvedhostname: 172.30.97.237
+
+ PS C:\> (curl -UseBasicParsing http://localhost:8080/service/1).Content
+ Hello from behind Envoy (service 1)! hostname: 8d2359ee21a8 resolvedhostname: 172.30.101.143
+
+
+Step 5: Enter container and curl admin interface
+************************************************
+
+When Envoy runs it also attaches an ``admin`` to your desired port.
+
+In the example configs the admin listener is bound to port ``8001``.
+
+We can ``curl`` it to gain useful information:
+
+- :ref:`/server_info ` provides information about the Envoy version you are running.
+- :ref:`/stats ` provides statistics about the Envoy server.
+
+In the example we can enter the ``front-envoy`` container to query admin:
+
+.. code-block:: console
+
+ PS> docker-compose exec front-envoy powershell
+ PS C:\> (curl http://localhost:8003/server_info -UseBasicParsing).Content
+
+.. code-block:: json
+
+ {
+ "version": "093e2ffe046313242144d0431f1bb5cf18d82544/1.15.0-dev/Clean/RELEASE/BoringSSL",
+ "state": "LIVE",
+ "hot_restart_version": "11.104",
+ "command_line_options": {
+ "base_id": "0",
+ "use_dynamic_base_id": false,
+ "base_id_path": "",
+ "concurrency": 8,
+ "config_path": "/etc/front-envoy.yaml",
+ "config_yaml": "",
+ "allow_unknown_static_fields": false,
+ "reject_unknown_dynamic_fields": false,
+ "ignore_unknown_dynamic_fields": false,
+ "admin_address_path": "",
+ "local_address_ip_version": "v4",
+ "log_level": "info",
+ "component_log_level": "",
+ "log_format": "[%Y-%m-%d %T.%e][%t][%l][%n] [%g:%#] %v",
+ "log_format_escaped": false,
+ "log_path": "",
+ "service_cluster": "front-proxy",
+ "service_node": "",
+ "service_zone": "",
+ "drain_strategy": "Gradual",
+ "mode": "Serve",
+ "disable_hot_restart": false,
+ "enable_mutex_tracing": false,
+ "restart_epoch": 0,
+ "cpuset_threads": false,
+ "disabled_extensions": [],
+ "bootstrap_version": 0,
+ "hidden_envoy_deprecated_max_stats": "0",
+ "hidden_envoy_deprecated_max_obj_name_len": "0",
+ "file_flush_interval": "10s",
+ "drain_time": "600s",
+ "parent_shutdown_time": "900s"
+ },
+ "uptime_current_epoch": "188s",
+ "uptime_all_epochs": "188s"
+ }
+
+.. code-block:: console
+
+ PS C:\> (curl http://localhost:8003/stats -UseBasicParsing).Content
+ cluster.service1.external.upstream_rq_200: 7
+ ...
+ cluster.service1.membership_change: 2
+ cluster.service1.membership_total: 3
+ ...
+ cluster.service1.upstream_cx_http2_total: 3
+ ...
+ cluster.service1.upstream_rq_total: 7
+ ...
+ cluster.service2.external.upstream_rq_200: 2
+ ...
+ cluster.service2.membership_change: 1
+ cluster.service2.membership_total: 1
+ ...
+ cluster.service2.upstream_cx_http2_total: 1
+ ...
+ cluster.service2.upstream_rq_total: 2
+ ...
+
+Notice that we can get the number of members of upstream clusters, number of requests fulfilled by
+them, information about http ingress, and a plethora of other useful stats.
+
+.. seealso::
+
+ :ref:`Envoy admin quick start guide `
+ Quick start guide to the Envoy admin interface.
diff --git a/examples/win32-front-proxy/Dockerfile-frontenvoy b/examples/win32-front-proxy/Dockerfile-frontenvoy
new file mode 100644
index 0000000000000..3a3494f54c0d1
--- /dev/null
+++ b/examples/win32-front-proxy/Dockerfile-frontenvoy
@@ -0,0 +1,6 @@
+FROM envoyproxy/envoy-windows-dev:latest
+
+COPY ./front-envoy.yaml './front-envoy.yaml'
+COPY ./start_envoy.ps1 ./start_envoy.ps1
+ENTRYPOINT ["powershell.exe", "./start_envoy.ps1"]
+
diff --git a/examples/win32-front-proxy/Dockerfile-service b/examples/win32-front-proxy/Dockerfile-service
new file mode 100644
index 0000000000000..a347d8c3189fc
--- /dev/null
+++ b/examples/win32-front-proxy/Dockerfile-service
@@ -0,0 +1,12 @@
+FROM envoyproxy/envoy-windows-dev:latest
+
+COPY ./setup_python.ps1 /
+
+RUN powershell.exe .\\setup_python.ps1
+RUN pip3 install -q Flask==0.11.1 requests==2.18.4
+
+RUN powershell mkdir code
+ADD ./service.py ./code
+ADD ./service-envoy.yaml ./service-envoy.yaml
+ADD ./start_service.ps1 ./start_service.ps1
+ENTRYPOINT ["powershell.exe", "./start_service.ps1"]
diff --git a/examples/win32-front-proxy/README.md b/examples/win32-front-proxy/README.md
new file mode 100644
index 0000000000000..cca1fdaf55f96
--- /dev/null
+++ b/examples/win32-front-proxy/README.md
@@ -0,0 +1,2 @@
+To learn about this sandbox and for instructions on how to run it please head over
+to the [envoy docs](https://www.envoyproxy.io/docs/envoy/latest/start/sandboxes/win32_front_proxy.html)
diff --git a/examples/win32-front-proxy/docker-compose.yaml b/examples/win32-front-proxy/docker-compose.yaml
new file mode 100644
index 0000000000000..71ea7751d01c4
--- /dev/null
+++ b/examples/win32-front-proxy/docker-compose.yaml
@@ -0,0 +1,34 @@
+version: "3.7"
+services:
+
+ front-envoy:
+ build:
+ context: .
+ dockerfile: Dockerfile-frontenvoy
+ networks:
+ - envoymesh
+ ports:
+ - "8080:8080"
+ - "8443:8443"
+ - "8003:8003"
+
+ service1:
+ build:
+ context: .
+ dockerfile: Dockerfile-service
+ networks:
+ - envoymesh
+ environment:
+ - SERVICE_NAME=1
+
+ service2:
+ build:
+ context: .
+ dockerfile: Dockerfile-service
+ networks:
+ - envoymesh
+ environment:
+ - SERVICE_NAME=2
+
+networks:
+ envoymesh: {}
diff --git a/examples/win32-front-proxy/front-envoy.yaml b/examples/win32-front-proxy/front-envoy.yaml
new file mode 100644
index 0000000000000..d96a5d31538c3
--- /dev/null
+++ b/examples/win32-front-proxy/front-envoy.yaml
@@ -0,0 +1,167 @@
+static_resources:
+ listeners:
+ - address:
+ socket_address:
+ address: 0.0.0.0
+ port_value: 8080
+ filter_chains:
+ - filters:
+ - name: envoy.filters.network.http_connection_manager
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ codec_type: AUTO
+ stat_prefix: ingress_http
+ route_config:
+ name: local_route
+ virtual_hosts:
+ - name: backend
+ domains:
+ - "*"
+ routes:
+ - match:
+ prefix: "/service/1"
+ route:
+ cluster: service1
+ - match:
+ prefix: "/service/2"
+ route:
+ cluster: service2
+ http_filters:
+ - name: envoy.filters.http.router
+ typed_config: {}
+
+ - address:
+ socket_address:
+ address: 0.0.0.0
+ port_value: 8443
+ filter_chains:
+ - filters:
+ - name: envoy.filters.network.http_connection_manager
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ codec_type: AUTO
+ stat_prefix: ingress_http
+ route_config:
+ name: local_route
+ virtual_hosts:
+ - name: backend
+ domains:
+ - "*"
+ routes:
+ - match:
+ prefix: "/service/1"
+ route:
+ cluster: service1
+ - match:
+ prefix: "/service/2"
+ route:
+ cluster: service2
+ http_filters:
+ - name: envoy.filters.http.router
+ typed_config: {}
+
+ transport_socket:
+ name: envoy.transport_sockets.tls
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
+ common_tls_context:
+ tls_certificates:
+ # The following self-signed certificate pair is generated using:
+ # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem -days 3650 -nodes -subj '/CN=front-envoy'
+ #
+ # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy
+ # via filename. Reference: https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource.
+ #
+ # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via
+ # Secret Discovery Service (SDS). Reference: https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret.
+ - certificate_chain:
+ inline_string: |
+ -----BEGIN CERTIFICATE-----
+ MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm
+ cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS
+ BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+ AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou
+ oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/
+ VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt
+ ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh
+ 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX
+ 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg
+ vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N
+ v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ
+ Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9
+ zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe
+ 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I
+ m+/R4XnmL4cKQ+5Z
+ -----END CERTIFICATE-----
+ private_key:
+ inline_string: |
+ -----BEGIN PRIVATE KEY-----
+ MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD
+ tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8
+ VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg
+ Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj
+ zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ
+ oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw
+ tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB
+ NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx
+ lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx
+ DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9
+ 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO
+ eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL
+ xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09
+ e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO
+ mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR
+ nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB
+ xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO
+ EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R
+ JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359
+ XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg
+ +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK
+ 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9
+ DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2
+ o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4
+ ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU
+ q5sGxGrC1RECGB5Zwx2S2ZY=
+ -----END PRIVATE KEY-----
+
+ clusters:
+ - name: service1
+ connect_timeout: 0.25s
+ type: STRICT_DNS
+ lb_policy: ROUND_ROBIN
+ load_assignment:
+ cluster_name: service1
+ endpoints:
+ - lb_endpoints:
+ - endpoint:
+ address:
+ socket_address:
+ address: service1
+ port_value: 8000
+ - name: service2
+ connect_timeout: 0.25s
+ type: STRICT_DNS
+ lb_policy: ROUND_ROBIN
+ load_assignment:
+ cluster_name: service2
+ endpoints:
+ - lb_endpoints:
+ - endpoint:
+ address:
+ socket_address:
+ address: service2
+ port_value: 8000
+admin:
+ address:
+ socket_address:
+ address: 0.0.0.0
+ port_value: 8001
+layered_runtime:
+ layers:
+ - name: static_layer_0
+ static_layer:
+ envoy:
+ resource_limits:
+ listener:
+ example_listener_name:
+ connection_limit: 10000
diff --git a/examples/win32-front-proxy/service-envoy.yaml b/examples/win32-front-proxy/service-envoy.yaml
new file mode 100644
index 0000000000000..b3ea728cc5f60
--- /dev/null
+++ b/examples/win32-front-proxy/service-envoy.yaml
@@ -0,0 +1,46 @@
+static_resources:
+ listeners:
+ - address:
+ socket_address:
+ address: 0.0.0.0
+ port_value: 8000
+ filter_chains:
+ - filters:
+ - name: envoy.filters.network.http_connection_manager
+ typed_config:
+ "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+ codec_type: AUTO
+ stat_prefix: ingress_http
+ route_config:
+ name: local_route
+ virtual_hosts:
+ - name: service
+ domains:
+ - "*"
+ routes:
+ - match:
+ prefix: "/service"
+ route:
+ cluster: local_service
+ http_filters:
+ - name: envoy.filters.http.router
+ typed_config: {}
+ clusters:
+ - name: local_service
+ connect_timeout: 0.25s
+ type: STRICT_DNS
+ lb_policy: ROUND_ROBIN
+ load_assignment:
+ cluster_name: local_service
+ endpoints:
+ - lb_endpoints:
+ - endpoint:
+ address:
+ socket_address:
+ address: 127.0.0.1
+ port_value: 8080
+admin:
+ address:
+ socket_address:
+ address: 0.0.0.0
+ port_value: 8081
diff --git a/examples/win32-front-proxy/service.py b/examples/win32-front-proxy/service.py
new file mode 100644
index 0000000000000..d08b0a897c9e0
--- /dev/null
+++ b/examples/win32-front-proxy/service.py
@@ -0,0 +1,31 @@
+from flask import Flask
+import os
+import requests
+import socket
+import sys
+
+app = Flask(__name__)
+
+
+@app.route('/service/')
+def hello(service_number):
+ return (
+ 'Hello from behind Envoy (service {})! hostname: {} resolved'
+ 'hostname: {}\n'.format(
+ os.environ['SERVICE_NAME'], socket.gethostname(),
+ socket.gethostbyname(socket.gethostname())))
+
+
+@app.route('/trace/')
+def trace(service_number):
+ if int(os.environ['SERVICE_NAME']) == 1:
+ requests.get("http://localhost:9000/trace/2")
+ return (
+ 'Hello from behind Envoy (service {})! hostname: {} resolved'
+ 'hostname: {}\n'.format(
+ os.environ['SERVICE_NAME'], socket.gethostname(),
+ socket.gethostbyname(socket.gethostname())))
+
+
+if __name__ == "__main__":
+ app.run(host='127.0.0.1', port=8080, debug=True)
diff --git a/examples/win32-front-proxy/setup_python.ps1 b/examples/win32-front-proxy/setup_python.ps1
new file mode 100644
index 0000000000000..0905a4b03062c
--- /dev/null
+++ b/examples/win32-front-proxy/setup_python.ps1
@@ -0,0 +1,54 @@
+$ErrorActionPreference = "Stop";
+
+function DownloadAndCheck
+{
+ param([string]$to, [string]$url, [string]$sha256)
+
+ Write-Host "Downloading $url to $to..."
+ (New-Object System.Net.WebClient).DownloadFile($url, $to)
+ $actual = (Get-FileHash -Path $to -Algorithm SHA256).Hash
+ if ($actual -ne $sha256) {
+ Write-Host "Download of $url to $to is invalid, expected sha256: $sha256, but got: $actual";
+ exit 1
+ }
+ Write-Host "done."
+}
+
+function AddToPath
+{
+ param([string] $directory)
+
+ $oldPath = (Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH).Path
+ $newPath = "$oldPath;$directory"
+ Set-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\Environment' -Name PATH -Value $newPath
+ # Add to local path so subsequent commands have access to the executables they need
+ $env:PATH += ";$directory"
+ Write-Host "Added $directory to PATH"
+}
+
+function RunAndCheckError
+{
+ param([string] $exe, [string[]] $argList, [Parameter(Mandatory=$false)] $isInstaller = $false)
+
+ Write-Host "Running '$exe $argList'..."
+ if ($isInstaller) {
+ Write-Host "(running as Windows software installer)"
+ Start-Process $exe -ArgumentList "$argList" -Wait -NoNewWindow
+ } else {
+ &$exe $argList
+ if ($LASTEXITCODE -ne 0) {
+ Write-Host "$exe $argList exited with code $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ }
+ Write-Host "done."
+}
+
+# Python3 (do not install via msys2 or the MS store's flavors, this version follows Win32 semantics)
+DownloadAndCheck $env:TEMP\python3-installer.exe `
+ https://www.python.org/ftp/python/3.8.5/python-3.8.5-amd64.exe `
+ cd427c7b17337d7c13761ca20877d2d8be661bd30415ddc17072a31a65a91b64
+# python installer needs to be run as an installer with Start-Process
+RunAndCheckError "$env:TEMP\python3-installer.exe" @("/quiet", "InstallAllUsers=1", "Include_launcher=0", "InstallLauncherAllUsers=0") $true
+AddToPath $env:ProgramFiles\Python38
+AddToPath $env:ProgramFiles\Python38\Scripts
diff --git a/examples/win32-front-proxy/start_envoy.ps1 b/examples/win32-front-proxy/start_envoy.ps1
new file mode 100644
index 0000000000000..efe1e2592e248
--- /dev/null
+++ b/examples/win32-front-proxy/start_envoy.ps1
@@ -0,0 +1 @@
+& 'C:\\Program Files\\envoy\\envoy.exe' --config-path .\front-envoy.yaml --service-cluster front-proxy
diff --git a/examples/win32-front-proxy/start_service.ps1 b/examples/win32-front-proxy/start_service.ps1
new file mode 100644
index 0000000000000..0aabb3b0b3deb
--- /dev/null
+++ b/examples/win32-front-proxy/start_service.ps1
@@ -0,0 +1,4 @@
+Start-Process -FilePath "python" -ArgumentList @("./code/service.py")
+
+$serviceName = "service$env:ServiceId"
+& 'C:\\Program Files\\envoy\\envoy.exe' --config-path .\service-envoy.yaml --service-cluster $serviceName