Luci and nginx php co-exist


I am trying to use nginx with nextclould. I installed nginx-all-modules and nginx-ssl. I could not get uci to work with nginx so I disabled uci for nginx.
I created nginx.conf in /etc/nginx and luci.conf/luci.locations, nextcloud.conf in /etc/nginx/conf.d/.

The problem is if I have only nextcloud.conf in conf.d directory, I can open However, once I put luci.conf together, I can only open for luci. Nextcloud webpage is unable to open(404).

I attached all configuration below. How to make opens luci and opens nextcloud?


config main global
	option uci_enable 'false'

config server '_lan'
	list listen '443 ssl default_server'
	list listen '[::]:443 ssl default_server'
	option server_name '_lan'
	list include 'restrict_locally'
	list include 'conf.d/*.locations'
	option uci_manage_ssl 'self-signed'
	option ssl_certificate '/etc/nginx/conf.d/_lan.crt'
	option ssl_certificate_key '/etc/nginx/conf.d/_lan.key'
	option ssl_session_cache 'shared:SSL:32k'
	option ssl_session_timeout '64m'
	option access_log 'off; # logd openwrt'

config server '_redirect2ssl'
	list listen '80'
	list listen '[::]:80'
	option server_name '_redirect2ssl'
	option return '302 https://$host$request_uri'


worker_processes auto;

user root;

events {use epoll;}

http {
	access_log off;
	log_format openwrt
		'$request_method $scheme://$host$request_uri => $status'
		' (${body_bytes_sent}B in ${request_time}s) <- $http_referer';

	include mime.types;
	default_type application/octet-stream;
	sendfile on;

	client_max_body_size 128M;
	large_client_header_buffers 2 1k;

	gzip on;
	gzip_vary on;
	gzip_proxied any;

	include conf.d/*.conf;


server { #see uci show 'nginx._lan'
	listen 443 ssl default_server;
	listen [::]:443 ssl default_server;
	server_name luci;
	include restrict_locally;
	include conf.d/luci.locations;
	ssl_certificate /etc/nginx/conf.d/_lan.crt;
	ssl_certificate_key /etc/nginx/conf.d/_lan.key;
	ssl_session_cache shared:SSL:32k;
	ssl_session_timeout 64m;
	access_log off; # logd openwrt;
	root /www;
server { #see uci show 'nginx._redirect2ssl'
	listen 80;
	listen [::]:80;
	server_name _redirect2ssl;
	return 302 https://$host$request_uri;


location /cgi-bin/luci {
		index  index.html;
		include uwsgi_params;
		uwsgi_param SERVER_ADDR $server_addr;
		uwsgi_modifier1 9;
		uwsgi_pass unix:////var/run/luci-webui.socket;
location ~ /cgi-bin/cgi-(backup|download|upload|exec) {
		include uwsgi_params;
		uwsgi_param SERVER_ADDR $server_addr;
		uwsgi_modifier1 9;
		uwsgi_pass unix:////var/run/luci-cgi_io.socket;

location /luci-static {
		error_log stderr crit;

location /ubus {
        ubus_socket_path /var/run/ubus/ubus.sock;
        ubus_parallel_req 2;


upstream php-handler {
    #server unix:/var/run/php/php7.4-fpm.sock;

# Set the `immutable` cache control options only for assets with a cache busting `v` argument
map $arg_v $asset_immutable {
    "" "";
    default "immutable";

server {
    listen 80;
    listen [::]:80;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # Enforce HTTPS just for `/nextcloud`
    location /nextcloud {
        return 301 https://$server_name$request_uri;

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

    # Path to the root of the domain
    root /www;

    # Use Mozilla's guidelines for SSL/TLS settings
	include restrict_locally;
    ssl_certificate     /etc/nginx/conf.d/_lan.crt;
    ssl_certificate_key /etc/nginx/conf.d/_lan.key;
	ssl_session_cache shared:SSL:32k;
	ssl_session_timeout 64m;
	access_log off; # logd openwrt;

    # Prevent nginx HTTP Server Detection
    server_tokens off;

    # HSTS settings
    # WARNING: Only add the preload option once you read about
    # the consequences in This option
    # will add the domain to a hardcoded list that is shipped
    # in all major browsers and getting removed from this list
    # could take several months.
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload" always;

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;

    location ^~ /.well-known {
        # The rules in this block are an adaptation of the rules
        # in the Nextcloud `.htaccess` that concern `/.well-known`.

        location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav/; }
        location = /.well-known/caldav  { return 301 /nextcloud/remote.php/dav/; }

        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
        location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

        # Let Nextcloud's API for `/.well-known` URIs handle all other
        # requests by passing them to the front-end controller.
        return 301 /nextcloud/index.php$request_uri;

    location ^~ /nextcloud {
        # set max upload size and increase upload timeout:
        client_max_body_size 512M;
        client_body_timeout 300s;
        fastcgi_buffers 64 4K;

        # Enable gzip but do not remove ETag headers
        gzip on;
        gzip_vary on;
        gzip_comp_level 4;
        gzip_min_length 256;
        gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
        gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/ application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;

        # Pagespeed is not supported by Nextcloud, so if your server is built
        # with the `ngx_pagespeed` module, uncomment this line to disable it.
        #pagespeed off;

        # The settings allows you to optimize the HTTP2 bandwitdth.
        # See
        # for tunning hints
        client_body_buffer_size 512k;

        # HTTP response headers borrowed from Nextcloud `.htaccess`
        add_header Referrer-Policy                   "no-referrer"       always;
        add_header X-Content-Type-Options            "nosniff"           always;
        add_header X-Download-Options                "noopen"            always;
        add_header X-Frame-Options                   "SAMEORIGIN"        always;
        add_header X-Permitted-Cross-Domain-Policies "none"              always;
        add_header X-Robots-Tag                      "noindex, nofollow" always;
        add_header X-XSS-Protection                  "1; mode=block"     always;

        # Remove X-Powered-By, which is an information leak
        fastcgi_hide_header X-Powered-By;

        # Specify how to handle directories -- specifying `/nextcloud/index.php$request_uri`
        # here as the fallback means that Nginx always exhibits the desired behaviour
        # when a client requests a path that corresponds to a directory that exists
        # on the server. In particular, if that directory contains an index.php file,
        # that file is correctly served; if it doesn't, then the request is passed to
        # the front-end controller. This consistent behaviour means that we don't need
        # to specify custom rules for certain paths (e.g. images and other assets,
        # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
        # `try_files $uri $uri/ /nextcloud/index.php$request_uri`
        # always provides the desired behaviour.
        index index.php index.html /nextcloud/index.php$request_uri;

        # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
        location = /nextcloud {
            if ( $http_user_agent ~ ^DavClnt ) {
                return 302 /nextcloud/remote.php/webdav/$is_args$args;

        # Rules borrowed from `.htaccess` to hide certain paths from clients
        location ~ ^/nextcloud/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)    { return 404; }
        location ~ ^/nextcloud/(?:\.|autotest|occ|issue|indie|db_|console)                  { return 404; }

        # Ensure this block, which passes PHP files to the PHP process, is above the blocks
        # which handle static assets (as seen below). If this block is not declared first,
        # then Nginx will encounter an infinite rewriting loop when it prepends
        # `/nextcloud/index.php` to the URI, resulting in a HTTP 500 error response.
        location ~ \.php(?:$|/) {
            # Required for legacy support
            rewrite ^/nextcloud/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /nextcloud/index.php$request_uri;

            fastcgi_split_path_info ^(.+?\.php)(/.*)$;
            set $path_info $fastcgi_path_info;

            try_files $fastcgi_script_name =404;

            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param PATH_INFO $path_info;
            fastcgi_param HTTPS on;

            fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
            fastcgi_param front_controller_active true;     # Enable pretty urls
            fastcgi_pass php-handler;

            fastcgi_intercept_errors on;
            fastcgi_request_buffering off;

            fastcgi_max_temp_file_size 0;

        location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
            try_files $uri /nextcloud/index.php$request_uri;
            add_header Cache-Control "public, max-age=15778463, $asset_immutable";
            access_log off;     # Optional: Don't log access to assets

            location ~ \.wasm$ {
                default_type application/wasm;

        location ~ \.woff2?$ {
            try_files $uri /nextcloud/index.php$request_uri;
            expires 7d;         # Cache-Control policy borrowed from `.htaccess`
            access_log off;     # Optional: Don't log access to assets

        # Rule borrowed from `.htaccess`
        location /nextcloud/remote {
            return 301 /nextcloud/remote.php$request_uri;

        location /nextcloud {
            try_files $uri $uri/ /nextcloud/index.php$request_uri;

The problem is if I have only nextcloud.conf in conf.d directory, I can open However, once I put luci.conf together, I can only open for luci. Nextcloud webpage is unable to open(404).

From what i see once you put evrithing thogheter to acsess your nextcloud you need to visit

Becuse, when Nginx receives a request, it looks for the best matching server block to handle the request based on the server_name directive and the URI.

Also why use https on a local network, do you have any specific reasson for that?

While https may be overkill, it’s a means to harden security. Https prevents people on a local network from snooping packets in an attempt to get their password. Whatever the OP’s use-case is for it, idk, but it’s never a bad idea to make luci accessible via https only, even with a self-signed cert.

I don't have special purpose for using http or https. However I plan to use https for nextcloud for external access in the future. I have tried several ways but no success:

  1. tried to comment out the server name.
  2. use

I am not sure what is wrong with this configuration.

If that cannot be solved, I may separate http and https i.e. use http for luci and https for nextcloud