-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Overhaul HTTPS support #74
Comments
I'd be interested to see the documentation for setting up a WebSocket proxy, I'm not sure that I know of a quick or straightforward way to get that working in our dev environments. As I understand it, it's definitely more setup for us than configuring certificate files. However, if we can automate a simple proxy setup, I can make that work for our use case. |
@bdukes Good point, I should make sure proxying WebSockets is easy enough before doing this. What dev server do you use? Or, what is the thing handling HTTPS in you dev setup? Trying to decide what proxy solutions I should look at first. |
@bdukes You only need to set up normal http proxy for a single location For example, nginx is set up like this:
ChatGPT says this is the translation of that location definition to Kestrel (using ws:// upstream, you may ask it for http:// upstream it's almost the same). No idea if it's correct, but seems complex enough to be the real thing: Setting up a reverse proxy location in a Kestrel web server for a .NET application to correspond to a specific NGINX location definition involves several steps. The NGINX configuration you provided is for proxying requests to a WebSocket server. To achieve similar functionality in Kestrel, you would typically use ASP.NET Core middleware to configure the reverse proxy. Here is a general outline of the steps you need to follow: Install the Required NuGet Package: Configure the Startup Class: ConfigureServices Method: Configure Method: Set Up the Reverse Proxy Middleware: Here is a basic example of what the code might look like:
|
Again ChatGPT: Translating the NGINX location configuration to a configuration suitable for IIS (Internet Information Services) involves using URL Rewrite and Application Request Routing (ARR) modules in IIS. These modules allow you to configure reverse proxy behavior similar to what you've defined in NGINX. To achieve a similar setup in IIS, follow these steps: Install URL Rewrite and ARR: Open IIS Manager: URL Rewrite Rule: Go to the site in IIS Manager and open the "URL Rewrite" feature. In the "Add Reverse Proxy Rules" dialog, set the "Inbound Rules" section. To replicate the proxy_set_header directives, you may need to add server variables or custom rewrite rules. Test the Configuration: Remember that IIS's approach to reverse proxying might not be a 1-to-1 match with NGINX's capabilities and syntax. Certain complex behaviors might require additional rules or custom modules. The steps above provide a general guide and might need adjustments based on your specific requirements and the IIS version. |
Finally, YARP. Again ChatGPT. Configuring YARP (Yet Another Reverse Proxy) in a .NET application to match the functionality of the given NGINX configuration involves creating and configuring a YARP proxy in your ASP.NET Core application. YARP allows you to set up sophisticated reverse proxy scenarios with .NET, and it's particularly useful for routing, load balancing, and other proxy-related tasks. Install YARP:
Configure Services: public void ConfigureServices(IServiceCollection services)
{
services.AddReverseProxy()
.LoadFromConfig(Configuration.GetSection("ReverseProxy"));
} Add YARP Configuration: {
"ReverseProxy": {
"Routes": [
{
"RouteId": "elm-watch-route",
"ClusterId": "elm-watch-cluster",
"Match": {
"Path": "/elm-watch/{**catch-all}"
}
}
],
"Clusters": {
"elm-watch-cluster": {
"Destinations": {
"elm-watch-destination": {
"Address": "http://localhost:61879"
}
}
}
}
}
} Configure the Proxy Middleware: public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapReverseProxy();
});
} Run Your Application: |
To set up a Node.js-based web server to proxy WebSocket connections in a manner similar to the NGINX configuration you provided, you can use the const http = require('http');
const httpProxy = require('http-proxy');
// Create a proxy server with custom application logic
const proxy = httpProxy.createProxyServer({});
// Handle WebSocket requests
proxy.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head, {
target: 'http://localhost:61879',
ws: true
});
});
// Create your server and then proxies the request
const server = http.createServer(function (req, res) {
proxy.web(req, res, { target: 'http://localhost:61879' });
});
server.on('upgrade', function (req, socket, head) {
proxy.ws(req, socket, head);
});
server.listen(3000, () => {
console.log('Proxy server listening on port 3000');
}); |
Setting up a simple node.js proxy server would probably be the approach we'd take. Thanks! |
This approach sounds good and will work for me in a use case I have when I run the development environment on my laptop, and here I can remove the code I have to monkey patch the However, I have another use case which involves running the development environment remotely (like Github Codespaces, Gitpod etc). Here hostname on which the site runs changes dynamically - a developer creates a new environment and gets a new hostname with a functioning SSL cert e.g. So it would be nice to be able to override the |
That’s a valid use case. From what I heard on podcasts, remote code spaces are supposed to take over the dev scene :) Here are some ways I can think of solving it:
|
I think the In my experience these remote development environments always provide the hostname in an environment variable in the container or virtual machine in which you run so getting |
The changes described in this issue are now released as 2.0.0-beta.1. With one difference: elm-watch still automatically uses On top of that, if you don’t want to create a proxy you can also achieve HTTPS like so: import * as fs from "node:fs";
import * as https from "node:https";
import * as path from "node:path";
import * as url from "node:url";
import elmWatch from "elm-watch";
const DIRNAME = path.dirname(url.fileURLToPath(import.meta.url));
// Deal with certificates and HTTPS options in whatever way you’d like:
const CERTIFICATE = {
key: fs.readFileSync(path.join(DIRNAME, "certificate", "dev.key")),
cert: fs.readFileSync(path.join(DIRNAME, "certificate", "dev.crt")),
};
elmWatch(process.argv.slice(2), {
createServer: ({ onRequest, onUpgrade }) =>
https.createServer(CERTIFICATE, onRequest).on("upgrade", onUpgrade),
})
.then((exitCode) => {
process.exit(exitCode);
})
.catch((error) => {
console.error("Unexpected elm-watch error:", error);
}); See the updated HTTPS and Server docs for more info. It’ll take a while before 2.0.0 will leave beta (because there are some other minor, potentially-breaking changes I’d like to make and the Node.js world has complicated things for me), but if some of you would like to start trying this out already, you now can. |
We don't have any active projects using elm-watch at this moment, so I don't have an easy opportunity to test, but this looks like it would handle all of our issues. Thanks! |
Yesterday I got some great feedback from @dsimunic on using elm-watch behind a proxy and with HTTPS on Discord. That discussion ended up in the following plan:
Add a way to configure the WebSocket URL. This could be
"webSocketUrl": "wss://example.com:12345/whatever"
in elm-watch.json. It means that the elm-watch client will effectively donew WebSocket("wss://example.com:12345/whatever")
. Fixes Ability to set domain for websocket server #60 and Support different client and server ports #46.If
"webSocketUrl"
is unset:http://
pages, everything will work as before.https://
pages, elm-watch won’t even try to connect. Instead it will show a helpful message, with a link to docs about how to use elm-watch with HTTPS. Which means setting up an HTTPS server yourself, and proxying the WebSocket.Remove HTTPS support in elm-watch. This makes Add ability to specify certificate #47 not needed any more – you instead control all things HTTPS yourself, at the expense of having to proxy the WebSocket for elm-watch.
@chazsconi and @bdukes would this work for you?
There is just one potential downside of this I can think of. By default, elm-watch sets the WebSocket URL using
window.location.hostname
. On a phone you might visithttp://192.168.1.123
(given that you dev server is exposed on the network and your phone is on the same wifi) and then elm-watch tries to connect tows://192.168.1.123:45678/elm-watch
. So testing on a phone just works. Now, if you for some reason use HTTPS – likehttps://localhost
– then you would have to set"webSocketUrl": "wss://localhost/elm-watch"
(since elm-watch no longer does anything onhttps://
pages without config). But then you wouldn’t be able to test on your phone anymore, without temporarily editing elm-watch.json to say"webSocketUrl": "wss://192.168.1.123:45678/whatever"
. My plan is to use my classic way of documenting this and saying “if you need this, please open an issue”. An idea I have already could be to also have an environment variableELM_WATCH_WEBSOCKET_URL
that overrides elm-watch.json. Then you can easily set it temporarily, or even script it to ask the computer for the IP address and put that in.The text was updated successfully, but these errors were encountered: