uHTTPd is Downloading My PHP Script Instead of Executing it

I changed the port of LuCI to 81 so it can still be accessed, so I can replace the server at port 80 with my own code. However, no matter what I do, uHTTPd is making Chrome download the file instead of actually executing the PHP script.

Here is my uhttpd config file:

config uhttpd 'main'
        list listen_http '0.0.0.0:81'
        list listen_http '[::]:81'
        list listen_https '0.0.0.0:443'
        list listen_https '[::]:443'
        option redirect_https '1'
        option home '/www'
        option rfc1918_filter '1'
        option max_requests '3'
        option max_connections '100'
        option cert '/etc/uhttpd.crt'
        option key '/etc/uhttpd.key'
        option cgi_prefix '/cgi-bin'
        list lua_prefix '/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
        option script_timeout '60'
        option network_timeout '30'
        option http_keepalive '20'
        option tcp_keepalive '1'
        option ubus_prefix '/ubus'

config uhttpd 'dremjs'
        list listen_http '0.0.0.0:80'
        list listen_http '[::]:80'
        list interpreter '.php=/usr/bin/php-cgi'
        list index_page 'index.php index.html'
        option index_file 'index.php index.html'
        option home '/dremjs'

config cert 'defaults'
        option days '730'
        option key_type 'rsa'
        option bits '2048'
        option ec_curve 'P-256'
        option country 'ZZ'
        option state 'Somewhere'
        option location 'Unknown'
        option commonname 'OpenWrt'

And my php.ini:

[PHP]
zend.ze1_compatibility_mode = Off

; Language Options

engine = On
;short_open_tag = Off
precision    =  12
y2k_compliance = On
output_buffering = Off
;output_handler =
zlib.output_compression = Off
;zlib.output_compression_level = -1
;zlib.output_handler =
implicit_flush = Off
unserialize_callback_func =
serialize_precision = 100

;open_basedir =
disable_functions =
disable_classes =

; Colors for Syntax Highlighting mode.  Anything that's acceptable in
; <span style="color: ???????"> would work.
;highlight.string  = #DD0000
;highlight.comment = #FF9900
;highlight.keyword = #007700
;highlight.bg      = #FFFFFF
;highlight.default = #0000BB
;highlight.html    = #000000

;ignore_user_abort = On
;realpath_cache_size = 16k
;realpath_cache_ttl = 120

; Miscellaneous

expose_php = On

; Resource Limits

max_execution_time = 30 ; Maximum execution time of each script, in seconds.
max_input_time = 60     ; Maximum amount of time each script may spend parsing request data.
;max_input_nesting_level = 64
memory_limit = 8M       ; Maximum amount of memory a script may consume.

; Error handling and logging

; Error Level Constants:
; E_ALL             - All errors and warnings (includes E_STRICT as of PHP 6.0.0)
; E_ERROR           - fatal run-time errors
; E_RECOVERABLE_ERROR  - almost fatal run-time errors
; E_WARNING         - run-time warnings (non-fatal errors)
; E_PARSE           - compile-time parse errors
; E_NOTICE          - run-time notices (these are warnings which often result
;                     from a bug in your code, but it's possible that it was
;                     intentional (e.g., using an uninitialized variable and
;                     relying on the fact it's automatically initialized to an
;                     empty string)
; E_STRICT                      - run-time notices, enable to have PHP suggest changes
;                     to your code which will ensure the best interoperability
;                     and forward compatibility of your code
; E_CORE_ERROR      - fatal errors that occur during PHP's initial startup
; E_CORE_WARNING    - warnings (non-fatal errors) that occur during PHP's
;                     initial startup
; E_COMPILE_ERROR   - fatal compile-time errors
; E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
; E_USER_ERROR      - user-generated error message
; E_USER_WARNING    - user-generated warning message
; E_USER_NOTICE     - user-generated notice message
; E_DEPRECATED      - warn about code that will not work in future versions
;                     of PHP
; E_USER_DEPRECATED - user-generated deprecation warnings
;
; Common Values:
;   E_ALL & ~E_NOTICE  (Show all errors, except for notices and coding standards warnings.)
;   E_ALL & ~E_NOTICE | E_STRICT  (Show all errors, except for notices)
;   E_COMPILE_ERROR|E_RECOVERABLE_ERROR|E_ERROR|E_CORE_ERROR  (Show only errors)
;   E_ALL | E_STRICT  (Show all errors, warnings and notices including coding standards.)
; Default Value: E_ALL & ~E_NOTICE
error_reporting  =  E_ALL & ~E_NOTICE & ~E_STRICT

display_errors = On
display_startup_errors = Off
log_errors = Off
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
;report_zend_debug = 0
track_errors = Off
;html_errors = Off
;docref_root = "/phpmanual/"
;docref_ext = .html
;error_prepend_string = "<font color=#ff0000>"
;error_append_string = "</font>"
; Log errors to specified file.
;error_log = /var/log/php_errors.log
; Log errors to syslog.
;error_log = syslog

; Data Handling

;arg_separator.output = "&amp;"
;arg_separator.input = ";&"
variables_order = "EGPCS"
request_order = "GP"
register_globals = Off
register_long_arrays = Off
register_argc_argv = On
auto_globals_jit = On
post_max_size = 8M
;magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
;default_charset = "iso-8859-1"
;always_populate_raw_post_data = On

; Paths and Directories

; UNIX: "/path1:/path2"
;include_path = ".:/php/includes"
doc_root =
extension=gd.so
extension=sockets.so
user_dir =
extension_dir = "/usr/lib/php/"
enable_dl = On
;cgi.force_redirect = 1
;cgi.nph = 1
;cgi.redirect_status_env = ;
cgi.fix_pathinfo=0
;fastcgi.impersonate = 1;
;fastcgi.logging = 0
;cgi.rfc2616_headers = 0

; File Uploads

file_uploads = On
upload_tmp_dir = "/tmp"
upload_max_filesize = 2M
max_file_uploads = 20

; Fopen wrappers

allow_url_fopen = On
allow_url_include = Off
;from="john@doe.com"
;user_agent="PHP"
default_socket_timeout = 60
;auto_detect_line_endings = Off

Not sure where to go from here. Any ideas?

Edit: added the rest of php.ini. Whoops.

remove this

This didn't work.

list index_page > option index_page

That didn't work either.

uci show uhttpd
ls -lah /dremjs
opkg list-installed | grep php

Assuming you were asking me to tell you the output of these commands:

uci show uhttpd

uhttpd.main=uhttpd
uhttpd.main.listen_http='0.0.0.0:81' '[::]:81'
uhttpd.main.listen_https='0.0.0.0:443' '[::]:443'
uhttpd.main.redirect_https='1'
uhttpd.main.home='/www'
uhttpd.main.rfc1918_filter='1'
uhttpd.main.max_requests='3'
uhttpd.main.max_connections='100'
uhttpd.main.cert='/etc/uhttpd.crt'
uhttpd.main.key='/etc/uhttpd.key'
uhttpd.main.cgi_prefix='/cgi-bin'
uhttpd.main.lua_prefix='/cgi-bin/luci=/usr/lib/lua/luci/sgi/uhttpd.lua'
uhttpd.main.script_timeout='60'
uhttpd.main.network_timeout='30'
uhttpd.main.http_keepalive='20'
uhttpd.main.tcp_keepalive='1'
uhttpd.main.ubus_prefix='/ubus'
uhttpd.dremjs=uhttpd
uhttpd.dremjs.listen_http='0.0.0.0:80' '[::]:80'
uhttpd.dremjs.interpreter='.php=/usr/bin/php-cgi'
uhttpd.dremjs.index_page='index.php index.html'
uhttpd.dremjs.home='/dremjs'
uhttpd.defaults=cert
uhttpd.defaults.days='730'
uhttpd.defaults.key_type='rsa'
uhttpd.defaults.bits='2048'
uhttpd.defaults.ec_curve='P-256'
uhttpd.defaults.country='ZZ'
uhttpd.defaults.state='Somewhere'
uhttpd.defaults.location='Unknown'
uhttpd.defaults.commonname='OpenWrt'

ls -lah /dremjs (note: the PHP is in a subdirectory)

drwxr-xr-x    6 root     root        2.1K Apr  9 06:00 .
drwxr-xr-x    1 root     root         416 Apr  9 05:58 ..
-rw-r--r--    1 root     root         270 Mar 19 18:06 .gitignore
-rw-r--r--    1 root     root         384 Mar 19 18:06 404.html
-rw-r--r--    1 root     root       20.9K Mar 19 18:06 404.png
-rw-r--r--    1 root     root        2.7M Mar 19 18:06 DremJS-Background.png
-rw-r--r--    1 root     root       34.3K Mar 19 18:06 LICENSE
-rw-r--r--    1 root     root         210 Mar 19 18:06 README-teminal.txt
-rw-r--r--    1 root     root        1.4K Mar 19 18:06 README.md
-rw-r--r--    1 root     root        5.5K Apr  3 04:51 agenda-wm.js
-rw-r--r--    1 root     root        2.0M Mar 19 18:06 ambient.mp3
drwxr-xr-x    6 root     root         432 Apr  9 06:00 apps
-rw-r--r--    1 root     root         168 Mar 19 18:06 background.png
drwxr-xr-x    2 root     root         304 Apr  9 06:00 css
-rw-r--r--    1 root     root       16.1K Mar 19 18:06 error.ico
-rw-r--r--    1 root     root        1.1K Mar 19 18:06 favicon.ico
-rw-r--r--    1 root     root      117.6K Mar 19 18:06 goodbye.gif
-rw-r--r--    1 root     root        4.6K Apr  4 01:10 index.html
-rw-r--r--    1 root     root        1.1K Mar 19 18:06 license-terminal.txt
-rw-r--r--    1 root     root       17.7K Mar 19 18:06 load.gif
drwxr-xr-x    2 root     root         240 Apr  9 06:00 modules
-rw-r--r--    1 root     root         597 Mar 19 18:06 shutdown.html
-rw-r--r--    1 root     root       94.4K Mar 19 18:06 shutdown.mp3
-rw-r--r--    1 root     root         998 Mar 19 18:06 shutdown.png
-rw-r--r--    1 root     root         820 Mar 19 18:06 shuttingdown.html
-rw-r--r--    1 root     root      927.6K Mar 19 18:06 spin.gif
drwxr-xr-x    2 root     root         448 Apr  9 06:00 terminal
-rw-r--r--    1 root     root        2.9K Apr  3 04:03 terminal.html
-rw-r--r--    1 root     root      401.9K Mar 29 06:06 termlogo-dark.png
-rw-r--r--    1 root     root      394.1K Mar 29 06:07 termlogo-lite.png

opkg list-installed | grep php

php7 - 7.4.4-1
php7-cgi - 7.4.4-1
php7-mod-gd - 7.4.4-1
php7-mod-sockets - 7.4.5-1

you have no index.php to interpret

Ah, ok, I didn't think to try to make a PHP script in the server's root - it works there. However, it still doesn't execute PHP in a subdirectory. My PHP is located at /dremjs/apps/ServerStatus/index.php and it still downloads there.

Have you restarted uhttpd after making changes to the config?

Yes. I also restarted the router for good measure (although it wouldn't do anything).

You haven't said what hardware you are using.
A couple of years ago I was running uhttpd with php on an 8/32 device (Nanostation M2). As my php changed from a trivial test page to something useful I started to get this problem.
Cutting a long story short, it was caused by php running out of free ram. 32MB was just not enough.
Could this be your issue?

I don't think that's it. Plus, if that were the case, it probably wouldn't download the PHP file.


As for the hardware I'm using, I have a Luxul XWR-3150

I thought it worth checking as I had a very similar problem.
It must be a config issue somewhere then.

I migrated to much better hardware and used lighttpd instead of uhttpd as it was very much faster under load and with multiple users.

I would recommend something other than uhttpd if you want this for anything more than an admin type page.

However I can dig out a previously working uhttpd config for comparison if you like.

ls -lah /dremjs/apps/ServerStatus/i*

I'm using uHTTPd because I tried Lighttpd and it didn't work. That'd be nice if you could dig up that config!

-rw-r--r--    1 root     root        2.6K Apr  4 00:58 /dremjs/apps/ServerStatus/index.php

I just flashed a gl-inet ar300m with today's snapshot, installed luci and therefore uhttpd, php.

The config file from nearly 3 years ago without any changes works fine. I don't recall the reason for all the entries, but it works here with php in nested directories.

config uhttpd 'main'
	list listen_http '0.0.0.0:80'
	#list listen_http '[::]:80'
	list interpreter '.php=/usr/bin/php-cgi'
	option home '/www'
	option rfc1918_filter '1'
	option max_requests '3'
	option max_connections '100'
	option cgi_prefix '/cgi-bin'
	option script_timeout '60'
	option network_timeout '30'
	option http_keepalive '20'
	option tcp_keepalive '1'
	option ubus_prefix '/ubus'

config uhttpd 'secondary'
	list listen_http '0.0.0.0:4280'
	list interpreter ".php=/usr/bin/php-cgi"
	option redirect_https '0'
	option home '/site'
	option rfc1918_filter '1'
	option max_requests '3'
	option max_connections '100'
	option script_timeout '60'
	option network_timeout '30'
	option http_keepalive '20'
	option tcp_keepalive '1'
	option ubus_prefix '/ubus'

I don't know if anything from my config will make it work for you, but as I say, it works here.

Here are some working config files for lighttpd....

/etc/lighttpd/lighttpd.conf

server.modules = (
"mod_openssl"
)

server.document-root        = "/www"
server.upload-dirs          = ( "/tmp" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "http"
server.groupname            = "www-data"
server.stream-response-body = 2

index-file.names            = ( "index.php", "index.html",
                                "index.htm", "default.htm",
                                "index.lighttpd.html" )

static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

$SERVER["socket"] == ":443" {
  ssl.engine = "enable" 
  ssl.pemfile = "/etc/lighttpd/certs/server.pem" 
}


### Options that are useful but not always necessary:
#server.chroot               = "/"
server.port                 = 4280
#server.bind                 = "localhost"
#server.tag                  = "lighttpd"
#server.errorlog-use-syslog  = "enable"
#server.network-backend      = "write"

### Use IPv6 if available
#include_shell "/usr/share/lighttpd/use-ipv6.pl"

#dir-listing.encoding        = "utf-8"
#server.dir-listing          = "enable"

include       "/etc/lighttpd/mime.conf"
include_shell "cat /etc/lighttpd/conf.d/*.conf"

and /etc/lighttpd/conf.d/30-cgi.conf

#######################################################################
##
##  CGI modules
## --------------- 
##
## See http://redmine.lighttpd.net/projects/lighttpd/wiki/docs_modcgi
##
server.modules += ( "mod_cgi" )

##
## Plain old CGI handling
##
## For PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini.
##
cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
                               ".cgi" => "/usr/bin/perl",
                               ".rb"  => "/usr/bin/ruby",
                               ".erb" => "/usr/bin/eruby",
                               ".py"  => "/usr/bin/python",
                               ".php" => "/usr/bin/php-cgi"
                             )

##
## to get the old cgi-bin behavior of apache
##
## Note: make sure that mod_alias is loaded if you uncomment the
##       next line. (see modules.conf)
##
#alias.url += ( "/cgi-bin" => server_root + "/cgi-bin" )
#$HTTP["url"] =~ "^/cgi-bin" {
#   cgi.assign = ( "" => "" )
#}

##
#######################################################################

This config didn't seem to work. I'd try the lighttpd config, but I don't really want to deal with setting up up right now. I'll probably try it in a few hours when I'm not so bogged down with school work.
(10 seconds later)
I did it anyway. It just says "validation failed". I'll try to see if something might have been set incorrectly on my part.