# Making WLED Addressable via HTTPS

**URL:** <https://wled.discourse.group/t/making-wled-addressable-via-https/5948>\
**Category:** Enhancements\
**Created:** [September 14, 2022, 9:55pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948 "2022-09-14T21:55:58Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![DrBix](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/drbix/32/3588_2.png) [@DrBix](https://wled.discourse.group/u/DrBix)\
**Post date:** [September 14, 2022, 9:55pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/1 "2022-09-14T21:55:58Z")

</div>

My background is a 36+ year Software Developer and Architect and I recently took an interest in WLED. I’ve posted a few times in the reddit /r/wled subreddit. I really love what has been done, but without HTTPS support, then there’s no way I’d ever expose my controller to the outside world and that is something I VERY MUCH WANTED! So I took on a few goals, and I’ll post what I’ve done.

1. **Create a Reverse HTTPS Proxy to the WLED Controller**  
This was an absolute MUST HAVE in order to even remotely consider exposing the controller to the outside world. I have now installed NGINX in a Docker Container on a Raspberry Pi 3b and configured it to act as a HTTPS Reverse Proxy to the WLED Controller. This seemed simple at first but had a few hiccups, notably that, at least on my internet router, WSS (Secure Web Sockets) are very flakey and timeouts occur rather frequently. That being said, the reverse proxy worked perfectly and I will happily share the NGINX configuration file that is working once I trim a little of the unnecessary stuff out of it. Further, this also allowed for multiple WLED controllers to be exposed on different URL Paths. So, since I have two WLED Controllers, I have mapped TWO endpoints in my NGINX Configuration File which allow me to access both of the controllers from a different URL:  
a. [https://myserver.com/wled-bar](https://myserver.com/wled-bar)  
b. [https://myserver.com/wled-test](https://myserver.com/wled-test)

2. **Modify the WLED Firmware to support HTTPS**  
As of now, I’ve completed this step and have tested both the HTTP interface and the HTTPS interface from the web page of the firmware from the mobile app. This required about 20 file changes and the vast majority of those changes were in the HTML and Javascript Files. The issue was that the code was designed to use absolute URLs instead of relative URLs. I modified all of the necessary files to use relative URLs. So if I hit `/settings` URL it will go to `https://myserver.com/wled-bar/settings` and not `https://myserver.com/settings` which would not work.

3. **Update the Mobile App**  
To begin, the mobile app was developed on a very old version of Visual Studio which I did not have access to, so the first thing I did was update it to Visual Studio 2022 and .NET6, which required some refactoring of the code. The mobile app is fairly “thin” in that most of the functionality of the app is supplied by the WLED Controller’s Web Pages. Basically the app is mostly a wrapper. I had never used Xamarin Forms so I had to learn that (pretty simple, actually) and then update the code to use the latest version of Xamarin Forms. Xamarin Forms is actually VERY nice and will likely use it again in the near future for other projects.

4. **Added Security**  
Although “Basic Authentication” is NOT considered secure, it is still acceptable to me if done over HTTPS because everything is still encrypted. Granted, I wouldn’t put this in a SCIF, but for controlling LEDs, I felt confident enough that I’m ok with it. I updated the “Add Device” screen to allow the user to enter the username and password to associate with the device so that you do not always have to enter a username and password to access the WLED Controller.

So, in conclusion, I’m very close to having completed this and it has been a real journey. I’m still fairly new to WLED (about 3 or 4 months or so tops). There are a few issues I still need to resolve but as of now, I can access my two WLED controllers from both a web browser as well as the app from HTTP or HTTPS with or without username & password security via basic authentication.

There are still a few outstanding issues, mostly small things like the WLED Device List Page shows the HTTPS devices showing as offline, but you can still click on the power button to turn them on or click on the device and control it that way.

Let me know of the interest level so I can determine if it’s even worth (somehow) merging the code. I don’t want to step on the original author’s (or anyone else’s) toes. My biggest change would definitely be in the WLED App Code since I restructured it to fit into the Visual Studio 2022 and .NET6 solution structure.

---

<div class="post-metadata">

**Author:** ![divsys](https://avatars.discourse-cdn.com/v4/letter/d/a3d4f5/32.png) [@divsys](https://wled.discourse.group/u/divsys)\
**Post date:** [September 14, 2022, 11:59pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/2 "2022-09-14T23:59:09Z")

</div>

Excellent job!  
Thanks for all your work.

Keep in mind the following is NOT a criticism of your efforts, what you’ve provided is very valuable.

The immediate issue(s) that occur to me:

What does this do to the code size especially on an ESP8266 device that can end up being limited for space.  
How is memory (flash, free heap, and FS) usage affected?  
How much extra processor power are we asking for?

I’m sure there are more factors (affect on fps?) that others will think of but in the mean time, it would be good to know what the various .bin sizes look like for ESP32 and/or ESP8266 devices.

I like the info on reverse proxy usage, I’m doing something similar with CaddyServer for other sites.

Thanks again for all your efforts… 😁

---

<div class="post-metadata">

**Author:** ![DrBix](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/drbix/32/3588_2.png) [@DrBix](https://wled.discourse.group/u/DrBix)\
**Post date:** [September 15, 2022, 12:20am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/3 "2022-09-15T00:20:01Z")

</div>

The immediate issue(s) that occur to me:

What does this do to the code size especially on an ESP8266 device that can end up being limited for space.

> Pretty much none. The only changes in the firmware are largely the Javascript and/or HTML files, which get compressed. After looking at the Javascript, it would not be hard to reduce that size even further.

How is memory (flash, free heap, and FS) usage affected?

> Again, little if any. I added 2 new fields ot the WLEDDevice object, two strings, which only affect the App’s storage, not the flash memory.

How much extra processor power are we asking for?

> Again, none. The processor power is consumed on the mobile device which can easily handle HTTPS traffic, and the HTTPS is proxied to HTTP to the WLED Controller by the Raspberry Pi running NGINX which it can easily handle, so there should be absolutely NO impact on the WLED controller at all.

I’m sure there are more factors (affect on fps?) that others will think of but in the mean time, it would be good to know what the various .bin sizes look like for ESP32 and/or ESP8266 devices.

> The current size of the firmware.bin file is 1,186,064 bytes. The 1.13.3 version is around 1.3MB so it’s less, though I haven’t figured out why the difference in size. As to the impact on FPS, etc., I would think no impact at all. The only thing changed in the firmware was almost 100% changing from absolute URLs to relative URLs, which affects nothing. Nothing I’ve changed should affect the actual control of the LEDs. Pretty sure they use the FastLED library which handles all of that behind the scenes.

I love the questions. Please, keep them coming!

–DrBix

---

<div class="post-metadata">

**Author:** ![Jinx](https://avatars.discourse-cdn.com/v4/letter/j/c6cbf5/32.png) [@Jinx](https://wled.discourse.group/u/Jinx)\
**Post date:** [September 15, 2022, 2:20am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/4 "2022-09-15T02:20:09Z")

</div>

Awesome effort!

I love the idea of having more secure access to WLED instances out of network and would be interested in utilizing this, provided you can explain how to do it on a windows machine vs a pie when complete.

You also may want to check out the WLED Discord if you are not already on there. Lots of helpful people/info there.

---

<div class="post-metadata">

**Author:** ![blazoncek](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/blazoncek/32/1886_2.png) [@blazoncek](https://wled.discourse.group/u/blazoncek)\
**Post date:** [September 15, 2022, 5:59am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/5 "2022-09-15T05:59:25Z")

</div>

Let me get this straight: You did not add HTTPS support for WLED web server, you just updated links used in UI to work with HTTPS. Right? You use reverse proxy (with translation from HTTPS to HTTP) to access WLED device from the ouside world. Right?

---

<div class="post-metadata">

**Author:** ![DrBix](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/drbix/32/3588_2.png) [@DrBix](https://wled.discourse.group/u/DrBix)\
**Post date:** [September 15, 2022, 1:01pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/6 "2022-09-15T13:01:33Z")

</div>

Correct, the ESP32 could not handle HTTPS because of the limited space and it’s just not fast enough. The title of the post was

> Making WLED Addressable via HTTPS

The relative links were absolutely necessary for me to allow for the WLED HTTP Server to be mapped to something other than the root URL (so something like `/presets.json` becomes `presets.json`). It’s still fully functional at the address like: `http://192.168.1.69` but outside of the local network, it can also be accessed at an address like: `https://someserver.com/wled-bar` or `https://someserver.com/wled-gameroom`. These changes were almost all done in the HTML (`.htm`) files and `index.js`. While I have developed in C++ in the past, no changes to those were necessary. I suppose if you didn’t mind having the WLED Controller be your root device, you might not need any changes. You might be able to map it via DNS if you had your own domain so mapping something like `wled-bar.mydomain.com` to your router and somehow redirect just that domain to your WLED Device, not sure though.

The WLED Android App required the most changes, and again, most of those changes were restructuring due to upgrading to the latest .NET Framework, Visual Studio 2022, and the latest version of Xamarin Forms. I made a few changes to the C# code and added two fields to the “Add Device” page to allow for providing the username and password for basic auth so the user wouldn’t have to enter them every time they wanted to access the device from outside of their internal network. Also, apparently the device discovery is crashing in Android 13 so while I don’t have Android 13 yet, I wanted to be prepared when I did so I had to be able to compile the App. The App I compiled in the latest .NET Framework worked in the Android 13 Emulator, but haven’t had the ability to test on an actual device yet.

I’m still working on a few minor issues.

If you wanna take a shot at it yourself, the NGINX Reverse Proxy configuration file looks like this and there are a lot of commented out lines (like the basic auth part) because I was having a few issues with the WebSockets (which still are flakey from time to time but it’s probably my shitty router). I had to run the NGINX Server in a Docker container because the version of NGINX on the Raspberry Pi 3 seemed to have issues with WebSockets so I had to get version 1.23 of NGINX running and just felt like trying out Docker on the Pi and it performs perfectly fine. This all being said, it seemed that the issues I was having with WebSockets was when I was using HTTPS on my internal network. When I VPNed outside of my local network I rarely saw any WebSocket errors. The HTTP address to the internal network worked without issues.

```auto
server {
    listen 80;
    listen [::]:80;
    server_name localhost;

    access_log /var/log/nginx/host.access.log main;

    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
    }

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    # proxy_pass http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    # root html;
    # fastcgi_pass 127.0.0.1:9000;
    # fastcgi_index index.php;
    # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
    # include fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    # deny all;
    #}
}

#
# Support for websockets... hopefully.
#
#upstream 192.168.1.210 {
# # enable sticky session based on IP
# ip_hash;
#
# server 192.168.1.210:80;
#}

server {
  listen 443 http2 ssl;
  listen [::]:443 http2 ssl;

  server_name localhost myserver.com www.myserver.com;

  access_log /var/log/nginx/host.access.log main;

  ssl_certificate /usr/share/nginx/ssl/ *********.crt;
  ssl_certificate_key /usr/share/nginx/ssl/ *********.key;

  location / {
    try_files $uri $uri/ =404;

    root /usr/share/nginx/html;
    index index.html index.htm index.nginx-debian.html;
  }

  location /wled-bar/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://192.168.1.210/;
    proxy_buffering off;
    proxy_read_timeout 90;

# auth_basic "Username and Password Required";
# auth_basic_user_file /etc/nginx/.htpasswd;

    # WebSocket Support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }

  location /wled-bar/ws {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    proxy_pass http://192.168.1.210/ws;
# include proxy_params;
    proxy_buffering off;
    proxy_read_timeout 90;

    # WebSocket Support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

```

---

<div class="post-metadata">

**Author:** ![CajunCoding](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/cajuncoding/32/3459_2.png) [@CajunCoding](https://wled.discourse.group/u/CajunCoding)\
**Post date:** [September 25, 2022, 2:20am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/7 "2022-09-25T02:20:18Z")

</div>

As a software developer myself, this sounds like great work!

I currently use HomeAssistant via SSL/HTTPS as my proxy to WLED… but all your changes make complete sense and I would imagine a very valid feature to merge in!

---

<div class="post-metadata">

**Author:** ![DrBix](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/drbix/32/3588_2.png) [@DrBix](https://wled.discourse.group/u/DrBix)\
**Post date:** [September 26, 2022, 7:48pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/8 "2022-09-26T19:48:42Z")

</div>

Thanks! I’m just wait for someone to review it and merge it.

> <https://github.com/Aircoookie/WLED/pull/2788>
>
> These changes should allow for devices to be referenced from URL mappings to dif…ferent devices as well as via HTTPS from a HTTPS Reverse Proxy.
> 
> So the WLED Controller can still be accessed by the internal IP. In addition, a web server can be setup to reverse proxy to the internal device allowing outside access. This can also include Basic Auth over the connection for added security. While not perfect, Basic Auto over HTTPS is very good, not perfect, but is a simple solution to protecting your WLED Devices.
> 
> I am using a Raspberry Pi 3 with NGINX running in a docker container on the Pi.
> 
> My NGINX Configuration File looks like this (some of it is commented out from debugging but I left it around). I've also removed some info from the config for my own privacy.
> 
> \`\`\`
> server {
> listen 443 http2 ssl;
> listen \[::\]:443 http2 ssl;
> 
> server\_name localhost \[removed for PR\].com www.\[removed for PR\].com;
> 
> access\_log /var/log/nginx/host.access.log main;
> 
> ssl\_certificate /usr/share/nginx/ssl/\[removed for PR\].crt;
> ssl\_certificate\_key /usr/share/nginx/ssl/\[removed for PR\].key;
> 
> 
> location / {
> try\_files $uri $uri/ =404;
> 
> root /usr/share/nginx/html;
> index index.html index.htm index.nginx-debian.html;
> }
> 
> location /wled-bar/ {
> proxy\_set\_header Host $host;
> proxy\_set\_header X-Real-IP $remote\_addr;
> proxy\_set\_header X-Forwarded-For $proxy\_add\_x\_forwarded\_for;
> proxy\_set\_header X-Forwarded-Proto $scheme;
> 
> proxy\_pass http://192.168.1.210/;
> proxy\_buffering off;
> proxy\_read\_timeout 90;
> 
> auth\_basic "Username and Password Required";
> auth\_basic\_user\_file /etc/nginx/conf.d/.htpasswd;
> 
> # WebSocket Support
> proxy\_http\_version 1.1;
> proxy\_set\_header Upgrade $http\_upgrade;
> proxy\_set\_header Connection "upgrade";
> }
> 
> location /wled-bar/ws {
> proxy\_set\_header Host $host;
> proxy\_set\_header X-Real-IP $remote\_addr;
> proxy\_set\_header X-Forwarded-For $proxy\_add\_x\_forwarded\_for;
> proxy\_set\_header X-Forwarded-Proto $scheme;
> 
> proxy\_pass http://192.168.1.210/ws;
> \# include proxy\_params;
> proxy\_buffering off;
> proxy\_read\_timeout 90;
> 
> # WebSocket Support
> proxy\_http\_version 1.1;
> proxy\_set\_header Upgrade $http\_upgrade;
> proxy\_set\_header Connection "upgrade";
> }
> }
> \`\`\`

---

<div class="post-metadata">

**Author:** ![blazoncek](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/blazoncek/32/1886_2.png) [@blazoncek](https://wled.discourse.group/u/blazoncek)\
**Post date:** [September 28, 2022, 6:31am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/9 "2022-09-28T06:31:27Z")

</div>

I did go through it but do not agree with all changes.  
When I have more time and test it I will make official review.

---

<div class="post-metadata">

**Author:** ![DrBix](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/drbix/32/3588_2.png) [@DrBix](https://wled.discourse.group/u/DrBix)\
**Post date:** [September 28, 2022, 6:33pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/10 "2022-09-28T18:33:58Z")

</div>

Thanks. I’ll await for your review.

---

<div class="post-metadata">

**Author:** ![dapuzz](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/dapuzz/32/7415_2.png) [@dapuzz](https://wled.discourse.group/u/dapuzz)\
**Post date:** [March 30, 2024, 5:23pm UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/11 "2024-03-30T17:23:53Z")

</div>

I saw that reverse proxy support has been added in 14.0b3 but there are absolute uri yet in the code.  
In this way, sub-folder forwarding is still not supported.  
Have you got the chance to review the “base url” handling?

Thank you

---

<div class="post-metadata">

**Author:** ![blazoncek](https://yyz2.discourse-cdn.com/free1/user_avatar/wled.discourse.group/blazoncek/32/1886_2.png) [@blazoncek](https://wled.discourse.group/u/blazoncek)\
**Post date:** [April 2, 2024, 7:24am UTC](https://wled.discourse.group/t/making-wled-addressable-via-https/5948/12 "2024-04-02T07:24:10Z")

</div>

fix is in 0.15
