Switch feedback reverse proxy from IIS to NGINX
- Add nginx-wp-suite.conf: static site + /api/feedback proxy to the Power Automate trigger (SNI on, Host header, POST-only, body cap) - Remove IIS web.config - Update feedback-config.js comment and DEPLOYMENT.md to the NGINX setup Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,20 +78,27 @@ app.listen(8080);
|
|||||||
Each line of `feedback.jsonl` is one submission; download it anytime. (PHP/
|
Each line of `feedback.jsonl` is one submission; download it anytime. (PHP/
|
||||||
Python/ASP.NET equivalents are a few lines too.)
|
Python/ASP.NET equivalents are a few lines too.)
|
||||||
|
|
||||||
#### Option B — Internal IIS reverse proxy → Power Automate (the chosen setup)
|
#### Option B — Internal NGINX reverse proxy → Power Automate (the chosen setup)
|
||||||
|
|
||||||
The browser posts to a **same-origin** path `/api/feedback`; IIS forwards that to
|
The browser posts to a **same-origin** path `/api/feedback`; NGINX forwards that
|
||||||
the Power Automate trigger. This avoids CORS entirely and keeps the secret
|
to the Power Automate trigger. This avoids CORS entirely and keeps the secret
|
||||||
trigger URL off the client. `FEEDBACK_ENDPOINT` is already set to
|
trigger URL off the client. `FEEDBACK_ENDPOINT` is already set to
|
||||||
`/api/feedback`, and [`web.config`](web.config) contains the proxy rule.
|
`/api/feedback`, and [`nginx-wp-suite.conf`](nginx-wp-suite.conf) contains the
|
||||||
|
full server block.
|
||||||
|
|
||||||
**On the IIS box (one-time, server admin):**
|
**On the NGINX box (one-time, server admin):**
|
||||||
1. Install the **URL Rewrite** and **Application Request Routing (ARR)** modules.
|
1. Copy the project files to the web root (e.g. `/var/www/wp-suite`).
|
||||||
2. Enable the proxy: IIS Manager → server node → *Application Request Routing
|
2. Install [`nginx-wp-suite.conf`](nginx-wp-suite.conf) (e.g. into
|
||||||
Cache* → *Server Proxy Settings* → check **Enable proxy**.
|
`/etc/nginx/conf.d/`), and set `server_name`, the `ssl_certificate` paths
|
||||||
3. Bind the site to **HTTPS** with an internal certificate.
|
(internal cert), and the `root`.
|
||||||
4. In `web.config`, replace `POWER_AUTOMATE_TRIGGER_URL` with the real trigger
|
3. In the `location = /api/feedback` block, replace the `proxy_pass` URL and the
|
||||||
URL (write every `&` as `&`).
|
`Host` header with your real trigger URL / region host (keep the full query
|
||||||
|
string incl. `sig=`).
|
||||||
|
4. `sudo nginx -t && sudo systemctl reload nginx`.
|
||||||
|
|
||||||
|
> Two NGINX details that matter: `proxy_ssl_server_name on;` (SNI is required for
|
||||||
|
> `*.logic.azure.com` or the TLS handshake fails) and the `Host` header set to
|
||||||
|
> the Azure region host. Both are already in the provided config.
|
||||||
|
|
||||||
**In Power Automate:**
|
**In Power Automate:**
|
||||||
1. Create a flow with the **"When an HTTP request is received"** trigger.
|
1. Create a flow with the **"When an HTTP request is received"** trigger.
|
||||||
@@ -126,7 +133,7 @@ trigger URL off the client. `FEEDBACK_ENDPOINT` is already set to
|
|||||||
(`POWER_AUTOMATE_TRIGGER_URL`).
|
(`POWER_AUTOMATE_TRIGGER_URL`).
|
||||||
5. A Power App (or just the list/Excel) reads that store to show live comments.
|
5. A Power App (or just the list/Excel) reads that store to show live comments.
|
||||||
|
|
||||||
Chain: `browser → /api/feedback (IIS proxy) → Power Automate → SharePoint/Dataverse → Power App`.
|
Chain: `browser → /api/feedback (NGINX proxy) → Power Automate → SharePoint/Dataverse → Power App`.
|
||||||
|
|
||||||
The "downloadable file" is then just the Excel/SharePoint list, viewable live or
|
The "downloadable file" is then just the Excel/SharePoint list, viewable live or
|
||||||
exported — all inside your corporate cloud.
|
exported — all inside your corporate cloud.
|
||||||
|
|||||||
BIN
favicon.ico
Normal file
BIN
favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -16,11 +16,11 @@
|
|||||||
Leave it as an empty string to stay fully local (export/import only).
|
Leave it as an empty string to stay fully local (export/import only).
|
||||||
See DEPLOYMENT.md for setup details and sample receivers.
|
See DEPLOYMENT.md for setup details and sample receivers.
|
||||||
|
|
||||||
This is set to the same-origin path '/api/feedback', which the IIS reverse
|
This is set to the same-origin path '/api/feedback', which the NGINX reverse
|
||||||
proxy (see web.config) forwards to the Power Automate HTTP trigger. Keeping it
|
proxy (see nginx-wp-suite.conf) forwards to the Power Automate HTTP trigger.
|
||||||
relative means no CORS and the secret trigger URL never appears in client
|
Keeping it relative means no CORS and the secret trigger URL never appears in
|
||||||
code. Locally (no proxy) the POST simply fails silently and feedback is still
|
client code. Locally (no proxy) the POST simply fails silently and feedback is
|
||||||
saved/exported from the browser.
|
still saved/exported from the browser.
|
||||||
────────────────────────────────────────────────────────────────────────── */
|
────────────────────────────────────────────────────────────────────────── */
|
||||||
window.FEEDBACK_ENDPOINT = '/api/feedback';
|
window.FEEDBACK_ENDPOINT = '/api/feedback';
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Work Package Suite — Prime Controls</title>
|
<title>Work Package Suite — Prime Controls</title>
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="any">
|
||||||
<link rel="stylesheet" href="theme-light.css">
|
<link rel="stylesheet" href="theme-light.css">
|
||||||
<style>
|
<style>
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
|||||||
56
nginx-wp-suite.conf
Normal file
56
nginx-wp-suite.conf
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
# Work Package Suite — NGINX site config
|
||||||
|
#
|
||||||
|
# Serves the static site and reverse-proxies feedback to a Power Automate
|
||||||
|
# "When an HTTP request is received" trigger. The browser only ever sees the
|
||||||
|
# same-origin path /api/feedback, so there is NO CORS and the secret trigger URL
|
||||||
|
# (with its sig= token) never reaches client code.
|
||||||
|
#
|
||||||
|
# Install:
|
||||||
|
# 1. Copy the project files to the web root (e.g. /var/www/wp-suite).
|
||||||
|
# 2. Put this file at /etc/nginx/conf.d/wp-suite.conf
|
||||||
|
# (or /etc/nginx/sites-available/ + symlink into sites-enabled/).
|
||||||
|
# 3. Replace server_name, the ssl_certificate paths, and the proxy_pass URL.
|
||||||
|
# 4. sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Redirect plain HTTP to HTTPS
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name wp-suite.company.local; # <-- your internal hostname
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
listen 443 ssl;
|
||||||
|
server_name wp-suite.company.local; # <-- your internal hostname
|
||||||
|
|
||||||
|
# Internal certificate from your company CA
|
||||||
|
ssl_certificate /etc/nginx/ssl/wp-suite.crt; # <-- cert path
|
||||||
|
ssl_certificate_key /etc/nginx/ssl/wp-suite.key; # <-- key path
|
||||||
|
ssl_protocols TLSv1.2 TLSv1.3;
|
||||||
|
|
||||||
|
# Static site
|
||||||
|
root /var/www/wp-suite; # <-- web root
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ── Feedback proxy → Power Automate ──────────────────────────────────────
|
||||||
|
# Paste your real trigger URL into proxy_pass below, keeping the FULL query
|
||||||
|
# string (api-version, sp, sv, sig). A small body cap keeps this endpoint safe.
|
||||||
|
location = /api/feedback {
|
||||||
|
limit_except POST { deny all; } # only accept POST
|
||||||
|
client_max_body_size 256k;
|
||||||
|
|
||||||
|
proxy_pass https://prod-XX.westus.logic.azure.com/workflows/REPLACE_WORKFLOW_ID/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=REPLACE_SIGNATURE;
|
||||||
|
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_ssl_server_name on; # SNI — required for *.logic.azure.com
|
||||||
|
proxy_set_header Host prod-XX.westus.logic.azure.com; # <-- match your region host
|
||||||
|
proxy_set_header Content-Type application/json;
|
||||||
|
proxy_set_header Cookie ""; # don't leak site cookies upstream
|
||||||
|
}
|
||||||
|
}
|
||||||
62
web.config
62
web.config
@@ -1,62 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!--
|
|
||||||
IIS configuration for the Work Package Suite (static site) + feedback proxy.
|
|
||||||
|
|
||||||
PREREQUISITES (one-time, done by the server admin in IIS Manager):
|
|
||||||
1. Install the "URL Rewrite" module.
|
|
||||||
2. Install "Application Request Routing" (ARR).
|
|
||||||
3. Enable the proxy: IIS Manager > (server node) >
|
|
||||||
Application Request Routing Cache > Server Proxy Settings >
|
|
||||||
check "Enable proxy". (This is server-level and cannot be set here.)
|
|
||||||
4. Bind the site to HTTPS with an internal certificate.
|
|
||||||
|
|
||||||
THEN: replace POWER_AUTOMATE_TRIGGER_URL below with the real "When an HTTP
|
|
||||||
request is received" URL from your flow. Remember every literal "&" in the URL
|
|
||||||
must be written as "&" inside this file.
|
|
||||||
-->
|
|
||||||
<configuration>
|
|
||||||
<system.webServer>
|
|
||||||
|
|
||||||
<!-- index.html is the entry point -->
|
|
||||||
<defaultDocument>
|
|
||||||
<files>
|
|
||||||
<clear />
|
|
||||||
<add value="index.html" />
|
|
||||||
</files>
|
|
||||||
</defaultDocument>
|
|
||||||
|
|
||||||
<!-- Don't list folder contents -->
|
|
||||||
<directoryBrowse enabled="false" />
|
|
||||||
|
|
||||||
<rewrite>
|
|
||||||
<rules>
|
|
||||||
<!-- Forward same-origin /api/feedback POSTs to the Power Automate flow.
|
|
||||||
The browser sees only /api/feedback; the secret trigger URL stays
|
|
||||||
on the server. Requires ARR proxy enabled (see prerequisites). -->
|
|
||||||
<rule name="Feedback proxy to Power Automate" stopProcessing="true">
|
|
||||||
<match url="^api/feedback/?$" />
|
|
||||||
<action type="Rewrite"
|
|
||||||
url="POWER_AUTOMATE_TRIGGER_URL" />
|
|
||||||
</rule>
|
|
||||||
</rules>
|
|
||||||
</rewrite>
|
|
||||||
|
|
||||||
<!-- Make sure POST is allowed and the JSON body isn't truncated -->
|
|
||||||
<security>
|
|
||||||
<requestFiltering>
|
|
||||||
<verbs>
|
|
||||||
<add verb="POST" allowed="true" />
|
|
||||||
</verbs>
|
|
||||||
<!-- 1 MB cap on a feedback body is plenty -->
|
|
||||||
<requestLimits maxAllowedContentLength="1048576" />
|
|
||||||
</requestFiltering>
|
|
||||||
</security>
|
|
||||||
|
|
||||||
<!-- Sensible static MIME types (most are built in; this is belt-and-braces) -->
|
|
||||||
<staticContent>
|
|
||||||
<remove fileExtension=".json" />
|
|
||||||
<mimeMap fileExtension=".json" mimeType="application/json" />
|
|
||||||
</staticContent>
|
|
||||||
|
|
||||||
</system.webServer>
|
|
||||||
</configuration>
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Work Package Suite</title>
|
<title>Work Package Suite</title>
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="any">
|
||||||
<link rel="stylesheet" href="theme-light.css">
|
<link rel="stylesheet" href="theme-light.css">
|
||||||
<link rel="stylesheet" href="work-package-suite-styles.css">
|
<link rel="stylesheet" href="work-package-suite-styles.css">
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Work Package (IWP) — Prime Controls</title>
|
<title>Work Package (IWP) — Prime Controls</title>
|
||||||
|
<link rel="icon" href="favicon.ico" sizes="any">
|
||||||
<link rel="stylesheet" href="theme-light.css">
|
<link rel="stylesheet" href="theme-light.css">
|
||||||
<link rel="stylesheet" href="wp-creation-styles.css">
|
<link rel="stylesheet" href="wp-creation-styles.css">
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
Reference in New Issue
Block a user