Search code examples
perlmojolicious

serve static directory from mojolicious other than /public


I have looked at a variety of places to find the best way to serve a directory of static files from within a app and this is as close as I've been able to get:

package ExampleServer;
use Mojo::Base 'Mojolicious';
use Mojolicious::Static;

# This method will run once at server start
sub startup {
    my $self = shift;

    $ENV{MOJO_REVERSE_PROXY} = 1;

    # TODO: generalize
    my $static_path = '/www/example/docroot/.well-known/acme-challenge/';

    # Router
    my $r = $self->routes;

    # Normal route to controller
    $r->get('/')->to('example#welcome');

    # serve static directory
    $r->get('/.well-known/acme-challenge/*filename' => sub {
        my $self = shift;
        my $filename = $self->stash('filename');
        my $fqfn = $static_path . $filename;
        $self->app->log->debug($fqfn);
        my $static = Mojolicious::Static->new( paths => [ $static_path ] );

        $static->serve($self, $fqfn);
        $self->rendered;
    });
}

1;

This is pulling out the filename correctly and it only effects the URL's I want it to, but it serves empty files regardless of whether they exist in that directory or not. What am I missing?


Solution

  • Possibly simplest way is use plugin RenderFile:

    package ExampleServer;
    use Mojo::Base 'Mojolicious';
    use Mojolicious::Static;
    
    # This method will run once at server start
    sub startup {
       my $self = shift;
    
       $self->plugin('RenderFile');
    
       $ENV{MOJO_REVERSE_PROXY} = 1;
    
       # TODO: generalize
       my $static_path = '/www/example/docroot/.well-known/acme-challenge/';
    
       # Router
       my $r = $self->routes;
    
       # Normal route to controller
       $r->get('/')->to('example#welcome');
    
       # serve static directory
       $r->get('/.well-known/acme-challenge/*filename' => sub {
           my $self = shift;
           my $filename = $self->stash('filename');
           my $fqfn = $static_path . $filename;
           $self->app->log->debug($fqfn);
           $self->render_file(filepath=> $fqfn, format => 'txt', content_disposition => 'inline' );
       });
    }
    

    Or you can get inspiration from source.