Using file_server in a handle

1. Caddy version (caddy version):

v2.0.0 (with CloudFlare DNS and WebDAV modules)

a. System environment:

Debian 10. Systemd template. caddy user created from wiki.

I am trying to switch from nginx over to Caddy but have been running into some trouble. I’m using a Caddyfile (more familiar than json formatting) but haven’t been able to understand how to use the handles correctly to mimic the location blocks in nginx.
I have a few folders and symlinks that I’d like to have caddy serve (with different credentials for each handle).
My nginx config looks like this

server {
    listen ipv4:443 ssl http2;
    server_name domain.name.com;
    root /usr/share/nginx/html/folder;
    error_page 400 /.html/error/HTTP400.html;
    error_page 401 /.html/error/HTTP401.html;
    error_page 402 /.html/error/HTTP402.html;
    error_page 403 /.html/error/HTTP403.html;
    error_page 404 /.html/error/HTTP404.html;
    error_page 500 /.html/error/HTTP500.html;
    error_page 501 /.html/error/HTTP501.html;
    error_page 502 /.html/error/HTTP502.html;
    error_page 503 /.html/error/HTTP503.html;
    location /39bm2k-name {
        alias /usr/share/nginx/html/folder/name;
        autoindex on;
        autoindex_localtime on;
        autoindex_exact_size off;
        auth_basic            "closed site";
        auth_basic_user_file  name.htpasswd;
    }
    location /19284dm-name2 {
        alias /usr/share/nginx/html/folder/name2;
        autoindex on;
        autoindex_localtime on;
        autoindex_exact_size off;
        auth_basic            "closed site";
        auth_basic_user_file  name2.htpasswd;
    }
}

I have more location blocks that are in my original nginx config but they are similar to the above.

My attempts at getting this mimicked (at least the permalink serving for the file server) have all failed. I’ve tried handle /39bm2k-name/* as well with no luck.

d. My complete Caddyfile or JSON config:

# default
vods.download {
    handle /39bm2k-name {
        file_server {
            root /storage/caddy/name/
            browse /usr/share/caddy/browse.tpl
            }
        }
        tls {
            dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        }

        log {
            output file /var/log/vods-caddy.log
        }
}

Hello camjac251.

I have never used nginx but are you just looking to have specified folders only accessible by certain users?

If so you could try something like

mydomain.com/* {
        root * /srv/dev-disk-by-label-HomeDrive/users/
        file_server browse
        basicauth {
                admin 64hashXXXXXXXXXXXXXXXXXX
        }
        basicauth /user1/* {
                user1 64hashXXXXXXXXXXXXXXXXXX
        }
        basicauth /user2/* {
                user2 64hashXXXXXXXXXXXXXXXXXX
        }
}

With that admin gets access to everything. user1 and user2 can only access their folders with their given passwords.

That sets the root path and then basicauth /user/* sets the path with that requires a username password login. I don’t know about some of those autoindex things you have in there but Caddy will configure directory listings without and index file if using the browse.

I hope that’s what you’re looing for.

Oh thank you. This is very close to what I’m trying to do. In nginx, it’s a bit different.

Nginx’s locations are like permalinks, so I have https://domain.name.com/39bm2k-name actually list the directory of /usr/share/nginx/html/folder/name. I was thinking using handles would allow for it to work but it hasn’t for me. Maybe rewriting urls? Not sure.

I have the added characters in the beginning to make the permalink harder to guess but the folders are simplified on disk. Actually they are just symlinks that point to an rclone mount.
I’m wondering if maybe it could be possible to emulate them in Caddy. for example I have /usr/share/nginx/html/folder/name which is a normal folder but inside that are two symlinks that point to rclonefolder1inmount rclonefolder2inmount. Could it be possible to add blocks for /39bm2k-name/name and /39bm2k-name/name2 and not have to use symlinks? Or maybe if rclone has a module for caddy, not sure

Maybe something like this would work:

mydomain.duckdns.org {
        root * /srv/dev-disk-by-label-HomeDrive/users/
        handle {
                route {
                        file_server browse
                        redir /user1/ /users/user1 permanent
                }
                basicauth /user1/* {
                        john JDJhJDEwJFZNZmNtVTVCb29vc1BiZkVrTkpvc3VlUC9IdGZ0clFBZHdsVmRQWVNYUDg0TWxYNEoyMVdX
                }
        }
        handle {
                route {
                        file_server browse
                        redir /user2/ /users/user2 permanent
                }
                basicauth /user2/* {
                        jose JDJhJDEwJGQvZHFLSE9ackRUUEJCSERTM0Z2Z3V6RGhTYkwvNGJaY1hPak9mWkRCVFRkLnZKOHN6aUZ5
                }
        }
}

In the web address bar if I put mydomain.duckdns.org/user1 it actually takes me to mydomain.duckdns.org/users/user1 and same for user2.

Unfortunately for me I can’t get the user2 to prompt me for a password. user1 seems to work just fine though. If that’s what you’re looking for then I hope this gets you moving in the right direction. Don’t worry about the hash-passwords I left in the file. This was just for testing.

I don’t know if this is the most efficient way to do it but this works for what I think you want.

mydomain.duckdns.org {
        root * /srv/dev-disk-by-label-HomeDrive/users/allusers
        handle {
                route {
                        file_server browse
                        redir /user1/ /users/allusers/user1 permanent
                }
        }
        handle {
                route {
                        file_server browse
                        redir /user2/ /users/allusers/user2 permanent
                }
        }
        handle {
                route {
                        file_server browse
                        redir /user3/ /users/allusers/user3 permanent
                }
        }
        basicauth /user1/* {
                john JDJhJDEwJFZNZmNtVTVCb29vc1BiZkVrTkpvc3VlUC9IdGZ0clFBZHdsVmRQWVNYUDg0TWxYNEoyMVdX
        }
        basicauth /user2/* {
                jose JDJhJDEwJGQvZHFLSE9ackRUUEJCSERTM0Z2Z3V6RGhTYkwvNGJaY1hPak9mWkRCVFRkLnZKOHN6aUZ5
        }
        basicauth /user3/* {
                jen JDJhJDEwJGRKV2J0VzJVZ05DOEg1WVV3ZlhJeXVEdkpPVWxiSG1sTmJxVndVVXgxS2VHbGx6ZTFuSmNP
        }
}

Now each user can type in DOMAIN FOR SALE and be taken to their folder and prompted for password. I tested it on my system and worked fine.

All the handle and route blocks there are unnecessary frankly. You could have just the one file_server directive outside of route/handle and all of the redirects outside as well and it should do the same thing.

And I don’t think the root along with redirects will have the desired effect. Request paths in Caddy are appended to the root, so you’ll be making requests for:

/srv/dev-disk-by-label-HomeDrive/users/allusers/users/allusers/user1

I don’t think that makes sense.

I’ll be honest, I’m a bit confused as to what is trying to be achieved here. Could you give a few example requests (like GET /some/path) and explain for each of them what the desired effect is? Try to be as thorough as possible with what you expect to happen. That should make it easier to help you write a config to achieve that goal.

The OP says in post 3 that he wants

Nginx’s locations are like permalinks, so I have https://domain.name.com/39bm2k-name actually list the directory of /usr/share/nginx/html/folder/name .

I tried doing the file_server and redirs outside of both handle and route to no avail:

mydomain.duckdns.org {
        root * /srv/dev-disk-by-label-HomeDrive/
        file_server browse
        redir /user1/ /users/allusers/user1 permanent
        redir /user2/ /users/allusers/user2 permanent
        basicauth /user1/* {
                john JDJhJDEwJFZNZmNtVTVCb29vc1BiZkVrTkpvc3VlUC9IdGZ0clFBZHdsVmRQWVNYUDg0TWxYNEoyMVdX
        }
        basicauth /user2/* {
                jose JDJhJDEwJGQvZHFLSE9ackRUUEJCSERTM0Z2Z3V6RGhTYkwvNGJaY1hPak9mWkRCVFRkLnZKOHN6aUZ5
        }
}

With that config though user2 loads to it’s page without a password prompt and user 1 gets a 404. I tried many variations to it also.

I also understand what you’re saying about the root and it makes total sense, however for some reason it wouldn’t work if I used

/srv/dev-disk-by-label-HomeDrive
or
/srv/dev-disk-by-label-HomeDrive/users

The only way I could get it to work was by putting that full path in the config you’re referring to. I’m sure it’s an issue on my part with the way Caddy does its exact path matching.

Could you help him out and help me learn? :grin: :man_student:

I still don’t understand what you’re trying to do. What URL paths do you expect to do what?

I want to hear from @camjac251 what they’re looking for.

I was hoping the nginx config could help explain the situation. I’m thinking that maybe Caddy might not be able to do what nginx is currently. I might just switch back to nginx.

I’m 100% sure Caddy can do it. I just don’t understand your description of the problem.

If I try to do a straight conversion of the nginx config to Caddyfile, it would probably look something like this:

domain.name.com {
	root * /usr/share/nginx/html/folder
	handle_errors {
		rewrite * /.html/error/HTTP{http.error.status_code}.html
		file_server
	}

	redir /39bm2k-name /39bm2k-name/
	handle /39bm2k-name/* {
		root * /usr/share/nginx/html/folder/name
		basicauth {
			Bob <pass>
		}
	}

	redir /19284dm-name2 /19284dm-name2/
	handle /19284dm-name2/* {
		root * /usr/share/nginx/html/folder/name2
		basicauth {
			Bob <pass>
		}
	}

	file_server browse
}

This doesn’t work for me I’m afraid. The main domain domain.name.com works and shows the file list, but both handles show an empty response.

Is it possible to hide folders after the root directive? I want to allow access to two folders out of a dozen with webdav support. I think putting each user was on a subdomain might be better than using handles.
I was hoping to have user1.domain.com/ show only the two directories using file_server and also in the webdav module too. I couldn’t find a way to hide outside of file_server's hide.

Oh, derp, my bad. I forgot to add the strip_prefix part to that config above. Sorry about that.

	redir /39bm2k-name /39bm2k-name/
	handle /39bm2k-name/* {
		uri strip_prefix /39bm2k-name
		root * /usr/share/nginx/html/folder/name
		basicauth {
			Bob <pass>
		}
	}

Nginx implicitly strips the prefix when using location blocks, but not Caddy. If you use Caddy v2.1 beta 1 though, there’s now the handle_path directive which has that same behaviour (same as handle + uri strip_prefix, saves a line).

Yes - there’s the hide option for the file_server directive that lets you specify filenames to exclude from the browse pages. You can also use a path matcher with a respond directive to return a 404 error when requested.

@hidden {
	path /thing1/* /thing2/*
}
respond @hidden 404
1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.