I've got a monorepo of Axum as server and a Vite app as frontend. Vite bundles some resources in ui/dist directory like this:
img/
fonts/
assets/
index.html
I'm trying to serve this directory with ServeDir like:
let serve_dir = ServeDir::new("ui/dist");
let rest_routes = rest_api::get_router(app_state);
let app = Router::new()
.route("/", get_service(serve_dir))
.nest("/api", rest_routes);
But except index.html I get 404s from anything under subdirectories like img, fonts.
I'm confused because ServeDir docs point out it should work with subdirectories .
Individual subdirs start working if I add:
let serve_assets = ServeDir::new("ui/dist/assets");
and
let app = Router::new()
.route("/", get_service(serve_dir))
.nest("/api", rest_routes)
.nest_service("/assets", serve_assets);
When I add a capture everything goes 404 including index.html:
.route("/{anything_goes}", get_service(serve_dir))
I checked this Axum example in Github, but I'm not sure it fits my use case with index.html at the root and subdirectory resources.
Do I have to add every subdirectory as a different service and use nest_service?
The line where you add the service isn't correct:
.route("/", get_service(serve_dir))
The service will only get called for serving the root path.
I was encountering something related today and the path I took was just making it a fallback service.
let app = Router::new()
.fallback_service(ServeDir::new("_site"))
I actually first tried nesting the service on the root first, but axum panicked with the message Nesting at the root is no longer supported. Use fallback_service instead.
1 Like
You're right. This is the solution. A bit weird to use fallback_service to serve an app's main assets but it worked. Thanks!
You can avoid using Router all together by passing a MethodRouter like get_service directly to axum::serve.
let listener = TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, get_service(ServeDir::new("_site")).await?;
MOCKBA
September 5, 2025, 12:19am
5
I guess it was a security concern, for example when you publish .war, some directories are excluded from servicing. I also met the problem writing own web server in Rust. Why should it service sub directories?
Digging deeper I found this and this .
It seems the issue is conflict with an existing fallback implementation rather than security related.
The first link mentions axum::routing::Router::merge can also be used instead. Didn't try that one.
system
Closed
December 4, 2025, 12:21pm
7
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.