Phalcode / gamevault-backend

Backend for the self-hosted gaming platform for drm-free games
https://gamevau.lt
Other
180 stars 15 forks source link

InternalServerErrorException: EACCES: permission denied, scandir '/files' #222

Closed haldi4803 closed 11 months ago

haldi4803 commented 11 months ago

Describe the bug Container doesn't start up! Reboots.

To Reproduce No File Access in Container

Expected behavior Server Starts Web Interface at least.

Server: Docker Container.

Log


info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.988Z' }
info:    ┏ Mapped {/api/progresses/game/:id, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.989Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.989Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.989Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId/increment, PUT} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.990Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId/increment/:minutes, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:24:13.990Z' }
usermod: no changes
info:    ┏ Starting Nest application... +0ms
info:    ┗ [1] { context: 'NestFactory', timestamp: '2023-11-20T20:25:09.018Z' }
info:    ┏ TypeOrmModule dependencies initialized +112ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.130Z' }
info:    ┏ TypeOrmModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.131Z' }
info:    ┏ HttpModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.132Z' }
info:    ┏ DiscoveryModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.132Z' }
info:    ┏ HealthModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.133Z' }
info:    ┏ AppModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.134Z' }
info:    ┏ FilesModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.134Z' }
info:    ┏ ScheduleModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.135Z' }
info:    ┏ TypeOrmCoreModule dependencies initialized +177ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.312Z' }
info:    ┏ TypeOrmModule dependencies initialized +2ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.314Z' }
info:    ┏ TypeOrmModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.314Z' }
info:    ┏ TypeOrmModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.315Z' }
info:    ┏ TypeOrmModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.315Z' }
info:    ┏ TypeOrmModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.316Z' }
info:    ┏ TypeOrmModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.316Z' }
info:    ┏ TypeOrmModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.317Z' }
info:    ┏ TypeOrmModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.317Z' }
info:    ┏ TypeOrmModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.318Z' }
info:    ┏ PublishersModule dependencies initialized +3ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.321Z' }
info:    ┏ DevelopersModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.322Z' }
info:    ┏ StoresModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.322Z' }
info:    ┏ ProgressModule dependencies initialized +2ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.324Z' }
info:    ┏ BoxartsModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.325Z' }
info:    ┏ DatabaseModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.325Z' }
info:    ┏ TagsModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.326Z' }
info:    ┏ GenresModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.326Z' }
info:    ┏ GamesModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.326Z' }
info:    ┏ AdminModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.327Z' }
info:    ┏ UsersModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.328Z' }
info:    ┏ ImagesModule dependencies initialized +0ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.328Z' }
info:    ┏ RawgModule dependencies initialized +1ms
info:    ┗ [1] { context: 'InstanceLoader', timestamp: '2023-11-20T20:25:09.328Z' }
info:    ┏ ActivityGateway subscribed to the "set-activity" message +43ms
info:    ┃ [1] {
info:    ┃ [2]   context: 'WebSocketsController',
info:    ┃ [3]   timestamp: '2023-11-20T20:25:09.372Z'
info:    ┗ [4] }
info:    ┏ ActivityGateway subscribed to the "get-activities" message +1ms
info:    ┃ [1] {
info:    ┃ [2]   context: 'WebSocketsController',
InternalServerErrorException: EACCES: permission denied, scandir '/files'
    at FilesService.fetch (/app/src/modules/files/files.service.ts:409:13)
    at FilesService.index (/app/src/modules/files/files.service.ts:56:36)
    at FilesService.onApplicationBootstrap (/app/src/modules/files/files.service.ts:47:12)
    at MapIterator.iteratee (/app/node_modules/.pnpm/@nestjs+core@10.2.7_@nestjs+common@10.2.7_@nestjs+platform-express@10.2.7_@nestjs+websockets@_e42nxxlqsjdhvwk77xw4g5hime/node_modules/@nestjs/core/hooks/on-app-bootstrap.hook.js:22:43)
    at MapIterator.next (/app/node_modules/.pnpm/iterare@1.2.1/node_modules/iterare/src/map.ts:9:39)
info:    ┃ [3]   timestamp: '2023-11-20T20:25:09.373Z'
info:    ┗ [4] }
info:    ┏ AdminController {/api/admin}: +2ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.375Z' }
info:    ┏ Mapped {/api/admin/health, GET} route +4ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.379Z' }
info:    ┏ Mapped {/api/admin/database/backup, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.380Z' }
    at IteratorWithOperators.next (/app/node_modules/.pnpm/iterare@1.2.1/node_modules/iterare/src/iterate.ts:19:28)
    at Function.from ()
    at IteratorWithOperators.toArray (/app/node_modules/.pnpm/iterare@1.2.1/node_modules/iterare/src/iterate.ts:227:22)
    at callOperator (/app/node_modules/.pnpm/@nestjs+core@10.2.7_@nestjs+common@10.2.7_@nestjs+platform-express@10.2.7_@nestjs+websockets@_e42nxxlqsjdhvwk77xw4g5hime/node_modules/@nestjs/core/hooks/on-app-bootstrap.hook.js:23:10)
    at callModuleBootstrapHook (/app/node_modules/.pnpm/@nestjs+core@10.2.7_@nestjs+common@10.2.7_@nestjs+platform-express@10.2.7_@nestjs+websockets@_e42nxxlqsjdhvwk77xw4g5hime/node_modules/@nestjs/core/hooks/on-app-bootstrap.hook.js:43:23)
info:    ┏ Mapped {/api/admin/database/restore, POST} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.381Z' }
info:    ┏ HealthController {/api/health}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.381Z' }
info:    ┏ Mapped {/api/health, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.382Z' }
info:    ┏ Mapped {/api/health/admin, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.382Z' }
info:    ┏ DatabaseController {/api/database}: +1ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.383Z' }
info:    ┏ Mapped {/api/database/backup, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.383Z' }
info:    ┏ Mapped {/api/database/restore, POST} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.384Z' }
info:    ┏ GamesController {/api/games}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.384Z' }
info:    ┏ Mapped {/api/games, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.385Z' }
info:    ┏ Mapped {/api/games/random, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.386Z' }
info:    ┏ Mapped {/api/games/:id, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.387Z' }
info:    ┏ Mapped {/api/games/:id/download, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.388Z' }
info:    ┏ Mapped {/api/games/:id, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.388Z' }
info:    ┏ RawgController {/api/rawg}: +1ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.389Z' }
info:    ┏ Mapped {/api/rawg/search, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.389Z' }
info:    ┏ Mapped {/api/rawg/:id/recache, PUT} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.390Z' }
info:    ┏ Mapped {/api/rawg/recache-all, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.390Z' }
info:    ┏ FilesController {/api/files}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.390Z' }
info:    ┏ Mapped {/api/files/reindex, PUT} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.391Z' }
info:    ┏ ImagesController {/api/images}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.391Z' }
info:    ┏ Mapped {/api/images/:id, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.392Z' }
info:    ┏ Mapped {/api/images, POST} route +6ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.398Z' }
info:    ┏ UsersController {/api/users}: +1ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.399Z' }
info:    ┏ Mapped {/api/users, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.399Z' }
info:    ┏ Mapped {/api/users/all, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.400Z' }
info:    ┏ Mapped {/api/users/me, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.400Z' }
info:    ┏ Mapped {/api/users/me, PUT} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.401Z' }
info:    ┏ Mapped {/api/users/me, DELETE} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.401Z' }
info:    ┏ Mapped {/api/users/:id, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.402Z' }
info:    ┏ Mapped {/api/users/:id, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.402Z' }
info:    ┏ Mapped {/api/users/:id, DELETE} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.403Z' }
info:    ┏ Mapped {/api/users/:id/recover, POST} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.403Z' }
info:    ┏ Mapped {/api/users/register, POST} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.403Z' }
info:    ┏ TagsController {/api/tags}: +1ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.404Z' }
info:    ┏ Mapped {/api/tags, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.404Z' }
info:    ┏ GenresController {/api/genres}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.404Z' }
info:    ┏ Mapped {/api/genres, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.405Z' }
info:    ┏ ProgressController {/api/progresses}: +0ms
info:    ┗ [1] { context: 'RoutesResolver', timestamp: '2023-11-20T20:25:09.405Z' }
info:    ┏ Mapped {/api/progresses/ignorefile, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.405Z' }
info:    ┏ Mapped {/api/progresses, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.406Z' }
info:    ┏ Mapped {/api/progresses/:id, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.406Z' }
info:    ┏ Mapped {/api/progresses/:id, DELETE} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.407Z' }
info:    ┏ Mapped {/api/progresses/user/:id, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.407Z' }
info:    ┏ Mapped {/api/progresses/game/:id, GET} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.407Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId, GET} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.408Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.408Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId/increment, PUT} route +1ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.409Z' }
info:    ┏ Mapped {/api/progresses/user/:userId/game/:gameId/increment/:minutes, PUT} route +0ms
info:    ┗ [1] { context: 'RouterExplorer', timestamp: '2023-11-20T20:25:09.409Z' }
usermod: no changes
Alfagun74 commented 11 months ago

The GameVault Server runs with a non-root user (1000:1000), but this user doesn't have the necessary permissions to access the mapped files volume or the images volume in the container.

To resolve this, consider the following recommended solutions:

  1. Grant specific permissions to the mapped folders on your host machine:

    chown -R 1000:1000 /the/folder/you/map/on/your/host/
  2. Run the GameVault Server as a user with the required permissions. For instance, you can use root by setting the PUID (User ID) and PGID (Group ID) environment variables to 0.

  3. If security allows, you can make the folder accessible to all users on Linux, although this is not advised due to potential security risks:

    chmod -R 777 /the/folder/you/map/on/your/host/

Choose the option that aligns with your security and permission requirements.

haldi4803 commented 11 months ago

Or, use the environment variable to set PUID PGID to an existing user...

But that's not the issue here. The docker container should not infinitely reboot simply because he has no permissions for the folder. Right?

Alfagun74 commented 11 months ago

The container has no reason to live and dies due to permission checks upon startup. As for the infinite reboot, if you set your restart policy to restart-always, it's on you.

Alfagun74 commented 11 months ago

Did you fix the permissions and get it running?

haldi4803 commented 11 months ago

Yes.

Alfagun74 commented 11 months ago

Awesome