Redesigning LuCI (OpenWrt)?

I came across such a video in the depths of the internet

I know it's a silly question, but..
Is there a chance for LuCI to change like on this presentation? and be more "user friendly".

Greetings :slight_smile:


i don't know but this video is very very well explained and is a good idea :wink:

more idea are welcome :slight_smile:

i has seen this video 1 month ago

I liked this video too.
But I have the impression I don't know if this could be done easily with the complicate structure of OpenWRT Menu.
Very poor documentation exists and a lot of outdated ones.It is difficult to know if a documentation is valid or not.
I'm trying to write a actualized documentation, but must say that it is very difficult to find out what happens in the intricacies of the code. There are so many paths and file extensions involved, without mention in existing docs. @jow sent me a little help, but I still haven't managed to close the cycle of who calls who, when and in what situation. Where beginning is, I know; what is the last step to show on screen, too. But what happens from the first file until the last javascript that appears on browser, is mystery, for me that are not fluent in Lua an LuCI. And debbug both is very hard, not impossible, but very hard.

I don't think it is a menu organization issue. The wireless view itself needs to be reorganized (means all the stuff that happens within the wireless menu node).

1 Like

I would like to help.but for now I'm trying to understand how all works.
After your tips, @jow, I advanced a little. I'm impressed with the amount of paths under /www and /usr that are involved. I'm searching cod with grep.
Now I see .list files. They are very strange for me. No docs quote it.
Can you give me any tip.
I would like to enumerate all files from /usr/share/luci/menu.d/luci-base.json to /www/luci-static/resources/view/system/crontab.js which seems me to be one of the simplest screens.

In general the request routing flow is:

  1. uhttpd (or another web server) invokes /www/cgi-bin/luci, passes request info via env vars & stdin (basic CGI interface)
  2. /www/cgi-bin/luci instantiates the luci.sgi.cgi class (sgi = Server Gateway Interface, a module to translate the server specific env to a common LuCI-internal HTTP request state) and invokes its run() method. There might be others but not relevant for the basic logic flow
  3. luci.sgi.cgi builds an HTTP request object from the provided information, loads luci.dispatcher and invokes luci.dispatcher.httpdispatch(), passing the HTTP request context object as argument
  4. luci.dispatcher.httpdispatch() parses the requested path, determines the preferred browser language and sets them in the global state along with the received HTTP request context, then proceeds in luci.dispatcher.dispatch()
  5. luci.dispatcher.dispatch() does several things:
    • it parses all /usr/share/luci/menu.d/ JSON files, assembles them into a global tree structure (ref menu_json())
      • checks uci and fs dependencies for all nodes (ref check_depends())
      • does some cleanup and post-processing
      • then caches the resulting tree structure on disk in /tmp. In case a fresh cache file is found, it is used instead and the JSON menu file processing is skipped
    • it resolves the requested node by looking up the determined path from the HTTP request context in the assembled menu tree structure (ref resolve_page())
      • if no matching node is found it yields a 404 error
      • if node dependencies are not fulfilled, it yields a 404 error
      • if the node or any of its ancestors require a login (specify a non-empty auth: {} object in their JSON), then...
        • if a session ID can be determined using one of the specified methods then...
          • if the session can be found (ubus call session get '{ "ubus_rpc_session": "the_ID" }', ref check_authentication()) then continue
          • if the session can not be found or is expired, then...
            • if the node or any of its ancestors specified login: true in the auth: { } object then present an HTML login dialog (by rendering /usr/lib/lua/luci/view/sysauth.htm)
            • if no node along the ancestor chain specifies login: true then yield a 403 error
    • it checks the acl dependencies along the ancestor chain
      • if a node along the chain depends on an ACL which is not granted in the active session, then yield a 403 error
      • if a node along the chain depends on an ACL for which the active session only has read but not write permission, then mark the node as readonly
    • does CORS processing if the HTTP request type is OPTIONS and the page (or one of its ancestory had cors: true set
    • does setuid/setgid dropping if configured in the ancestor chain
    • it evaluates the action: { } object of the resolved node
      • depending on the action (ref: Description of the JSON in menu.d and acl.d? - #4 by jow) it either...
        • executes a JavaScript view (type view) in /www/luci-static/resources/view/**.js
          • this is the most common and preferred node action
          • it is implemented by rendering a server side /usr/lib/lua/luci/view/view.htm template which in turn instantiates the /www/luci-static/resources/view/**.js JS class from the rendered HTML code using the L.ui.instantiateView() API.
        • calls a class method (type call) - the method is responsible for producing HTTP output, setting status headers etc. If the mode encounters an exception, then yield a 500 error
        • renders a server side Lua template (type template) in /usr/lib/lua/luci/view/**.htm according to the node action specification - this action type is deprecated/being faded out
        • renders an abstract CBI form (type cbi) in /usr/lib/lua/luci/model/cbi/**.lua - this action type is deprecated/being faded out
        • renders a non-UCI CBI form (type form) in /usr/lib/lua/luci/model/cbi/**.lua - this action type is deprecated/being faded out
        • executes a summary or detail sub-action (type arcombine) depending on whether an ID argument is present as last path segment - this action type is deprecated/being faded out
        • redirects or rewrites the request (types alias and rewrite)

A typical JavaScript based view is composed of several requests though:

  • The main request to access a LuCI URL produces a server-side rendered HTML page frame that includes JS code that...
    • Requests the session-specific menu tree as JSON from the server and renders it locally into an HTML menu
    • Requests various static resources such as luci.js, CSS files etc.
    • For the most common view action type, requests and instantiates the actual view .js file which in turn...
      • produces markup and incrementally renders the content area of the server side rendered page frame
      • optionally makes a number of ubus-rpc API requests to fetch more information from the server, e.g. to load uci config values or system runtime information
      • in the specific example of crontab.js, the file contents are fetched via the JS API which in turn invokes ubus call file read { "path": "..." } via the HTTP-UBUS interface (not strictly part of LuCI) towards rpcd file module

The HTML page frame template is /usr/lib/lua/luci/view/view.htm for JS based views, for other actions (CBI maps, server side Lua templates) it is other *.htm templates including header.htm and footer.htm themselves

The header.htm and footer.htm templates in luci-base are just stubs including the theme specific header.htm and footer.htm


Imho, donot try to Redesigning LuCI, 2 reasons:

  1. LuCI for openwrt has more than 8000 apps, any small changes, might create many compatibility problems.
  2. LuCI, its advantage is the small code size, this makes it could be used in 8MB flash( >70% devices used?).

Please go through this info:

and consider to improve Gargoyle , even JUCI.

Very wise words, do not modify LuCI, this environment does not have to be user-friendly there are after all much nicer user interfaces, see for example Gargoyle.

To me it's just about improving the approach to the user. I know there is a console and advanced users abhor LuCI, the rest think LuCI is difficult, it doesn't change, it's a waste of time for this GUI let's install something else.

@jow may be worth contacting the author of the presentation?


Not sure what insights that would provide me with, apart from the points already raised in the presentation, unless they can offer specific coding help in implementing these improvement suggestions (without pivoting the project away into some entirely new web framework and/or starting a complete replacement death march).

The problem is not a lack of things to do or a lack of improvement ideas, the problem is a lack of manpower to improve the existing system so far.


For this purpose, I suggested contacting the author, maybe he could help in implementing the code.

Diagnostic-Code: smtp; 550 5.1.1 <>:
Recipient address rejected: User unknown in virtual mailbox table

Unfortunately, David was working on a contract and no longer works with us. You might want to consider to reach him privately, but right now, we don't have any manpower left to improve the LuCI. Since we are dealing with issues OpenWrt/Turris OS and upstreaming Turris devices.

One more alternative solution is OUI.

OpenWrt web user interface implemented in vue.js and Ant Design of Vue.
Oui uses json-rpc to communicate with OpenWrt subsystems and support ACL.

and Vue3 + Nginx + Lua is coming... for OUI.


As @pepe suggested presenter may be contacted on his private email. He might be able to contribute to OpenWrt.
Anything which makes Openwrt user-friendly/nob-friendly is always welcome.

I couldn’t find a personal mail from a cursory google search, tried the one in the presentation which bounced. Apart from that I never got contacted and only learned about the presentation here. If the author has capacity to help I would guess he‘d have reached out by now.

1 Like

He does have a LinkedIn. Though his personal sites are down. You could message him on there:

This starts to feel like stalking now :slight_smile:


I have to apologize for turning this subject into an elephant.
I just tried to find some way to pay attention to the lack of updated documentation, after implementing version 0.10 of LuCI.
My goal is to write documentation for anyone intending to incorporate new items into the OpenWRT Menu. I did this in version 0.9 with no problems with the existing documentation.
Now my implementations I made with 0.9 no longer work. I didn't even intend to break the code as I'm trying to do now, with great difficulty since the syntax of Lua and LuCI is strange to me. I don't intend to learn either, just change the menu.

1 Like

Well, I tried, it's a pity it didn't work out.

I had good intentions. :slight_smile:
I hope that LuCI will change for the better (I'm not talking about changing the icons here, although it could also be refreshed).

It<s a topic that came often on Mikrotik .. just like asking that to Cisco. Advanced featured mean advance user. But a step learning curve if no book read on it and networking. CCNA is quite powerfull to show all or training book.