Compare commits
19 Commits
1b8bd7b94f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0dedc0d8e0 | |||
| d1569094e7 | |||
| 2703e60881 | |||
| 51935bbb09 | |||
| 3f9cab66f5 | |||
| 9e5f377768 | |||
| 571e449581 | |||
| 74db5b8b61 | |||
| 707aaeae15 | |||
| 6fde39d6a4 | |||
| ee64902a06 | |||
| 7cce873fc6 | |||
| bcf6088f3a | |||
| 7ad6fcd4d0 | |||
| 7b05b5ec4c | |||
| bfec74b10e | |||
| 56652719aa | |||
| 0ee1a88875 | |||
| 21de7b0121 |
7
.dockerignore
Normal file
7
.dockerignore
Normal file
@@ -0,0 +1,7 @@
|
||||
.git
|
||||
.gitignore
|
||||
.dockerignore
|
||||
node_modules
|
||||
screenshots
|
||||
test
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
{
|
||||
"title": "Romm",
|
||||
"version": "0.1.0",
|
||||
"healthCheckPath": "/",
|
||||
"version": "0.2.0",
|
||||
"upstreamVersion":"4.6.1",
|
||||
"author":"Kevin Whitaker <kevin@eyecreate.org>",
|
||||
"description":"A beautiful, powerful, self-hosted rom manager and player.",
|
||||
"healthCheckPath": "/api/heartbeat",
|
||||
"httpPort": 3000,
|
||||
"memoryLimit": 2097152000,
|
||||
"addons": {
|
||||
"localstorage": {},
|
||||
"postgresql": {},
|
||||
"oidc": {
|
||||
"loginRedirectUri": "/api/oauth/openid",
|
||||
"logoutRedirectUri": "/",
|
||||
"logoutRedirectUri": "/login",
|
||||
"tokenSignatureAlgorithm": "RS256"
|
||||
}
|
||||
},
|
||||
"redis": { "noPassword": true },
|
||||
"turn":{}
|
||||
},
|
||||
"manifestVersion": 2
|
||||
"website":"https://romm.app/",
|
||||
"icon":"file://logo.png",
|
||||
"manifestVersion": 2,
|
||||
"postInstallMessage":"Before setting up the first admin user, please check /app/data/env.sh for some API keys for metadata sources and fill in any you want to use. Put any ROMs in the /app/data/library/roms folder. Please see https://docs.romm.app/latest/Getting-Started/Folder-Structure/ for details on folder structure. RESTART AFTER ANY API KEY CHANGES!"
|
||||
}
|
||||
|
||||
131
Dockerfile
131
Dockerfile
@@ -1,9 +1,46 @@
|
||||
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
||||
ARG VERSION=4.6.1
|
||||
|
||||
RUN mkdir -p /app/code
|
||||
WORKDIR /app/code
|
||||
ARG VERSION=4.5.0
|
||||
ARG ALPINE_VERSION=3.22
|
||||
ARG NODE_VERSION=20.19
|
||||
|
||||
# FRONTEND BUILD
|
||||
FROM node:${NODE_VERSION}-trixie AS frontend-build
|
||||
ARG VERSION
|
||||
WORKDIR /front
|
||||
RUN wget "https://github.com/rommapp/romm/archive/refs/tags/${VERSION}.tar.gz" && \
|
||||
tar xfz ${VERSION}.tar.gz --strip-components=2 -C /front romm-${VERSION}/frontend && rm ${VERSION}.tar.gz
|
||||
RUN npm ci --ignore-scripts --no-audit --no-fund
|
||||
RUN npm run build
|
||||
|
||||
# FETCH EMULATORJS AND RUFFLE
|
||||
FROM alpine:${ALPINE_VERSION} AS emulator-stage
|
||||
|
||||
RUN apk add --no-cache \
|
||||
7zip \
|
||||
wget \
|
||||
ca-certificates
|
||||
|
||||
ARG EMULATORJS_VERSION=4.2.3
|
||||
ARG EMULATORJS_SHA256=07d451bc06fa3ad04ab30d9b94eb63ac34ad0babee52d60357b002bde8f3850b
|
||||
|
||||
RUN wget "https://github.com/EmulatorJS/EmulatorJS/releases/download/v${EMULATORJS_VERSION}/${EMULATORJS_VERSION}.7z" && \
|
||||
echo "${EMULATORJS_SHA256} ${EMULATORJS_VERSION}.7z" | sha256sum -c - && \
|
||||
7z x -y "${EMULATORJS_VERSION}.7z" -o/emulatorjs && \
|
||||
rm -f "${EMULATORJS_VERSION}.7z"
|
||||
|
||||
ARG RUFFLE_VERSION=nightly-2025-08-14
|
||||
ARG RUFFLE_FILE=ruffle-nightly-2025_08_14-web-selfhosted.zip
|
||||
ARG RUFFLE_SHA256=178870c5e7dd825a8df35920dfc5328d83e53f3c4d5d95f70b1ea9cd13494151
|
||||
|
||||
RUN wget "https://github.com/ruffle-rs/ruffle/releases/download/${RUFFLE_VERSION}/${RUFFLE_FILE}" && \
|
||||
echo "${RUFFLE_SHA256} ${RUFFLE_FILE}" | sha256sum -c - && \
|
||||
unzip -o "${RUFFLE_FILE}" -d /ruffle && \
|
||||
rm -f "${RUFFLE_FILE}"
|
||||
|
||||
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c as cloudron-builder
|
||||
|
||||
ARG NJS_VERSION=0.9.4
|
||||
ARG MODZIP_VERSION=1.3.0
|
||||
# Prevent interactive prompts during installation
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
@@ -31,21 +68,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
liblzma-dev \
|
||||
libncurses5-dev \
|
||||
libncursesw5-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
nginx \
|
||||
nginx-dev \
|
||||
libpcre3-dev \
|
||||
libssl-dev \
|
||||
libxml2-dev \
|
||||
libxslt-dev
|
||||
|
||||
# Clone release
|
||||
RUN wget https://github.com/rommapp/romm/archive/refs/tags/$VERSION.tar.gz && \
|
||||
tar xfz $VERSION.tar.gz --strip-components=1 -C /app/code && rm $VERSION.tar.gz
|
||||
WORKDIR /
|
||||
RUN git clone -b ${NJS_VERSION} https://github.com/nginx/njs.git
|
||||
RUN git clone -b ${MODZIP_VERSION} https://github.com/evanmiller/mod_zip.git
|
||||
|
||||
# Install nvm
|
||||
ENV NVM_DIR="/root/.nvm"
|
||||
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash \
|
||||
&& . "$NVM_DIR/nvm.sh" \
|
||||
&& nvm install 18.20.8 \
|
||||
&& nvm use 18.20.8 \
|
||||
&& nvm alias default 18.20.8
|
||||
ENV PATH="$NVM_DIR/versions/node/v18.20.8/bin:$PATH"
|
||||
WORKDIR /usr/share/nginx/src
|
||||
RUN ./configure --add-dynamic-module=/njs/nginx --add-dynamic-module=/mod_zip --with-compat --builddir=. && make modules
|
||||
|
||||
# Build and install RAHasher (optional for RA hashes)
|
||||
RUN git clone --recursive --branch 1.8.1 --depth 1 https://github.com/RetroAchievements/RALibretro.git /tmp/RALibretro
|
||||
@@ -55,23 +90,65 @@ RUN sed -i '22a #include <ctime>' ./src/Util.h \
|
||||
./src/libchdr/deps/zlib-1.3.1/gzlib.c \
|
||||
./src/libchdr/deps/zlib-1.3.1/gzread.c \
|
||||
./src/libchdr/deps/zlib-1.3.1/gzwrite.c \
|
||||
&& make HAVE_CHD=1 -f ./Makefile.RAHasher \
|
||||
&& cp ./bin64/RAHasher /usr/bin/RAHasher
|
||||
RUN rm -rf /tmp/RALibretro
|
||||
&& make HAVE_CHD=1 -f ./Makefile.RAHasher
|
||||
|
||||
# Install frontend dependencies
|
||||
WORKDIR /app/code/frontend
|
||||
RUN npm install
|
||||
RUN ln -s /tmp/vite-temp /app/code/frontend/node_modules/.vite-temp
|
||||
# Main image starts here
|
||||
FROM cloudron/base:5.0.0@sha256:04fd70dbd8ad6149c19de39e35718e024417c3e01dc9c6637eaf4a41ec4e596c
|
||||
|
||||
RUN mkdir -p /app/code
|
||||
WORKDIR /app/code
|
||||
ARG WEBSERVER_FOLDER=/app/code/frontend
|
||||
|
||||
ARG UV_VERSION=0.8.24
|
||||
ARG VERSION
|
||||
|
||||
# Prevent interactive prompts during installation
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
libpq-dev \
|
||||
libmariadb-dev \
|
||||
curl \
|
||||
ca-certificates \
|
||||
7zip \
|
||||
tzdata \
|
||||
nginx \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Clone release backend code
|
||||
RUN wget "https://github.com/rommapp/romm/archive/refs/tags/${VERSION}.tar.gz" && \
|
||||
tar xfz ${VERSION}.tar.gz --strip-components=1 -C /app/code romm-${VERSION}/backend romm-${VERSION}/pyproject.toml romm-${VERSION}/uv.lock && rm ${VERSION}.tar.gz
|
||||
|
||||
# Install RAHasher into image
|
||||
COPY --from=cloudron-builder /tmp/RALibretro/bin64/RAHasher /usr/bin/RAHasher
|
||||
|
||||
# Install frontend into image
|
||||
WORKDIR ${WEBSERVER_FOLDER}
|
||||
COPY --from=frontend-build /front/dist ${WEBSERVER_FOLDER}
|
||||
COPY --from=frontend-build /front/assets ${WEBSERVER_FOLDER}/assets
|
||||
COPY ./decode.js /etc/nginx/js/decode.js
|
||||
COPY ./nginx.conf /etc/nginx/nginx.conf
|
||||
COPY ./default.conf /etc/nginx/conf.d/default.conf
|
||||
COPY --from=cloudron-builder /usr/share/nginx/src/ngx_http_js_module.so /usr/lib/nginx/modules/
|
||||
COPY --from=cloudron-builder /usr/share/nginx/src/ngx_http_zip_module.so /usr/lib/nginx/modules/
|
||||
RUN mkdir -p assets/romm && ln -s /app/data/assets ${WEBSERVER_FOLDER}/assets/romm/assets && ln -s /app/data/resources ${WEBSERVER_FOLDER}/assets/romm/resources
|
||||
|
||||
# Copy emulator to web folder
|
||||
COPY --from=emulator-stage /emulatorjs ${WEBSERVER_FOLDER}/assets/emulatorjs
|
||||
COPY --from=emulator-stage /ruffle ${WEBSERVER_FOLDER}/assets/ruffle
|
||||
|
||||
WORKDIR /app/code/
|
||||
# Install uv for the non-root user
|
||||
COPY --from=ghcr.io/astral-sh/uv:0.7.19 /uv /uvx /usr/local/bin/
|
||||
COPY --from=ghcr.io/astral-sh/uv:$UV_VERSION /uv /uvx /usr/local/bin/
|
||||
|
||||
# Install Python
|
||||
RUN uv python install 3.13
|
||||
RUN mkdir /app/code/uv && uv python install -i /app/code/uv 3.13
|
||||
|
||||
# Install Python dependencies
|
||||
ENV UV_PYTHON_INSTALL_DIR=/app/code/uv
|
||||
RUN uv sync --all-extras
|
||||
|
||||
# add supervisor configs
|
||||
@@ -81,6 +158,8 @@ RUN ln -sf /run/supervisord.log /var/log/supervisor/supervisord.log
|
||||
ENV PATH="/app/code/.venv/bin:${PATH}"
|
||||
|
||||
COPY start.sh /app/pkg/
|
||||
COPY env.sh.template /app/pkg/
|
||||
COPY config.yml.template /app/pkg/
|
||||
|
||||
CMD [ "/app/pkg/start.sh" ]
|
||||
|
||||
|
||||
171
config.yml.template
Normal file
171
config.yml.template
Normal file
@@ -0,0 +1,171 @@
|
||||
# Only uncomment the lines you want to use/modify, or add new ones where needed
|
||||
|
||||
# exclude:
|
||||
# # Exclude platforms to be scanned
|
||||
# platforms:
|
||||
# - excluded_folder_a
|
||||
# - excluded_folder_b
|
||||
|
||||
# # Exclude roms or parts of roms to be scanned
|
||||
# roms:
|
||||
# # Single file games section.
|
||||
# # Will not apply to files that are in sub-folders (multi-disc roms, games with updates, DLC, patches, etc.)
|
||||
# single_file:
|
||||
# # Exclude all files with certain extensions to be scanned
|
||||
# extensions:
|
||||
# - xml
|
||||
# - txt
|
||||
|
||||
# # Exclude matched file names to be scanned
|
||||
# # Supports unix filename pattern matching
|
||||
# names:
|
||||
# - 'info.txt'
|
||||
# - '._*'
|
||||
# - '*.nfo'
|
||||
|
||||
# # Multi files games section
|
||||
# # Will apply to files that are in sub-folders (multi-disc roms, games with updates, DLC, patches, etc.)
|
||||
# multi_file:
|
||||
# # Exclude matched 'folder' names to be scanned (RomM identifies folders as multi file games)
|
||||
# # Common ES-DE media folders are listed below
|
||||
# names:
|
||||
# - 3dboxes
|
||||
# - backcovers
|
||||
# - covers
|
||||
# - fanart
|
||||
# - manuals
|
||||
# - marquees
|
||||
# - miximages
|
||||
# - physicalmedia
|
||||
# - screenshots
|
||||
# - titlescreens
|
||||
# - videos
|
||||
# - downloaded_media
|
||||
# - media
|
||||
|
||||
# # Exclude files within sub-folders.
|
||||
# parts:
|
||||
# # Exclude matched file names to be scanned from multi file roms
|
||||
# # Keep in mind that RomM doesn't scan folders inside multi files games,
|
||||
# # so there is no need to exclude folders from inside of multi files games.
|
||||
# names:
|
||||
# - 'data.xml'
|
||||
# - '._*' # Supports unix filename pattern matching
|
||||
|
||||
# # Exclude all files with certain extensions to be scanned from multi file roms
|
||||
# extensions:
|
||||
# - xml
|
||||
# - txt
|
||||
|
||||
# system:
|
||||
# # Asociate different platform names to your current file system platform names
|
||||
# # [your custom platform folder name]: [RomM platform name]
|
||||
# # In this example if you have a 'gc' folder, RomM will treat it like the 'ngc' folder
|
||||
# platforms:
|
||||
# gc: ngc
|
||||
# ps1: psx
|
||||
|
||||
# # Asociate one platform to it's main version (IGDB only)
|
||||
# versions:
|
||||
# naomi: arcade
|
||||
|
||||
# The folder name where your roms are located
|
||||
# filesystem:
|
||||
# roms_folder: 'roms' # For example if your folder structure is /home/user/library/roms_folder
|
||||
# skip_hash_calculation: false # Skip file hash calculations on low power devices (eg. Raspberry PI)
|
||||
|
||||
# scan:
|
||||
# # Metadata priority during scans
|
||||
# priority:
|
||||
# # Below are the default priority values used
|
||||
# metadata: # Top-level metadata source priority
|
||||
# - "igdb" # IGDB (highest priority)
|
||||
# - "moby" # MobyGames
|
||||
# - "ss" # Screenscraper
|
||||
# - "ra" # RetroAchievements
|
||||
# - "launchbox" # Launchbox
|
||||
# - "gamelist" # ES-DE gamelist.xml
|
||||
# - "hasheous" # Hasheous
|
||||
# - "flashpoint" # Flashpoint Project
|
||||
# - "hltb" # HowLongToBeat (lowest priority)
|
||||
# artwork: # Cover art and screenshots
|
||||
# - "igdb" # IGDB
|
||||
# - "moby" # MobyGames
|
||||
# - "ss" # Screenscraper
|
||||
# - "ra" # RetroAchievements
|
||||
# - "launchbox" # Launchbox
|
||||
# - "gamelist" # ES-DE gamelist.xml
|
||||
# - "hasheous" # Hasheous
|
||||
# - "flashpoint" # Flashpoint Project
|
||||
# - "hltb" # HowLongToBeat
|
||||
# region: # Used by IGDB and ScreenScraper for regional variants
|
||||
# - "us"
|
||||
# - "wor"
|
||||
# - "ss"
|
||||
# - "eu"
|
||||
# - "jp"
|
||||
# language: # Used by ScreenScraper for descriptions
|
||||
# - "en"
|
||||
# - "fr"
|
||||
# # Media assets to download
|
||||
# # Only used by Screenscraper and ES-DE gamelist.xml
|
||||
# media:
|
||||
# # Used as alternative cover art
|
||||
# - box2d # Normal cover art (always enabled)
|
||||
# - box3d # 3D box art
|
||||
# - miximage # Mixed image of multiple media
|
||||
# - physical # Disc, cartridge, etc.
|
||||
# # Added to the screenshots carousel
|
||||
# - screenshot # Screenshot (enabled by default)
|
||||
# - title_screen # Title screen
|
||||
# - fanart # User uploaded artwork
|
||||
# # Bezel displayed around the emulatorjs window
|
||||
# - bezel
|
||||
# # Manual in PDF format
|
||||
# - manual # Manual (enabled by default)
|
||||
# # Gameplay video
|
||||
# - video # Video (warning: large file size)
|
||||
# # Media used for batocera gamelist.xml export
|
||||
# - box2d_back # Back cover art
|
||||
# - logo # Transparent logo
|
||||
# # Other media assets (might be used in the future)
|
||||
# - marquee # Custom marquee
|
||||
|
||||
# EmulatorJS per-core options
|
||||
# emulatorjs:
|
||||
# debug: true # Available options will be logged to the browser console
|
||||
# cache_limit: null # Cache limit per ROM (in bytes)
|
||||
# disable_batch_bootup: false
|
||||
# disable_auto_unload: false
|
||||
# settings:
|
||||
# parallel_n64: # Use the exact core name
|
||||
# vsync: disabled
|
||||
# snes9x:
|
||||
# snes9x_region: ntsc
|
||||
# default: # These settings apply to all cores
|
||||
# fps: show
|
||||
# netplay:
|
||||
# enabled: true
|
||||
# ice_servers:
|
||||
# - urls: "stun:stun.relay.metered.ca:80"
|
||||
# - urls: "turn:global.relay.metered.ca:80"
|
||||
# username: "<username>"
|
||||
# credential: "<password>"
|
||||
# controls: # https://emulatorjs.org/docs4devs/control-mapping/
|
||||
# snes9x:
|
||||
# 0: # Player 1
|
||||
# 0: # A MAPPING FOR EACH BUTTON MUST BE SET!
|
||||
# value: x # Mapping for keyboard
|
||||
# value2: BUTTON_2 # Mapping for connected controller
|
||||
# 1: # Player 2
|
||||
# 2: # Player 3
|
||||
# 3: # Player 4
|
||||
|
||||
emulatorjs:
|
||||
netplay:
|
||||
enabled: true
|
||||
ice_servers:
|
||||
- urls: "stun:$CLOUDRON_STUN_SERVER:$CLOUDRON_STUN_PORT"
|
||||
- urls: "turn:$CLOUDRON_TURN_SERVER:$CLOUDRON_TURN_PORT"
|
||||
username: "$turn_username"
|
||||
credential: "$turn_password"
|
||||
19
decode.js
Normal file
19
decode.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// Decode a Base64 encoded string received as a query parameter named 'value',
|
||||
// and return the decoded value in the response body.
|
||||
function decodeBase64(r) {
|
||||
var encodedValue = r.args.value;
|
||||
|
||||
if (!encodedValue) {
|
||||
r.return(400, "Missing 'value' query parameter");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var decodedValue = atob(encodedValue);
|
||||
r.return(200, decodedValue);
|
||||
} catch (e) {
|
||||
r.return(400, "Invalid Base64 encoding");
|
||||
}
|
||||
}
|
||||
|
||||
export default { decodeBase64 };
|
||||
73
default.conf
Normal file
73
default.conf
Normal file
@@ -0,0 +1,73 @@
|
||||
# Helper to get scheme regardless if we are behind a proxy or not
|
||||
map $http_x_forwarded_proto $forwardscheme {
|
||||
default $scheme;
|
||||
https https;
|
||||
}
|
||||
|
||||
# COEP and COOP headers for cross-origin isolation, which are set only for the
|
||||
# EmulatorJS player path, to enable SharedArrayBuffer support, which is needed
|
||||
# for multi-threaded cores.
|
||||
map $request_uri $coep_header {
|
||||
default "";
|
||||
~^/rom/.*/ejs$ "require-corp";
|
||||
}
|
||||
map $request_uri $coop_header {
|
||||
default "";
|
||||
~^/rom/.*/ejs$ "same-origin";
|
||||
}
|
||||
|
||||
server {
|
||||
root /app/code/frontend;
|
||||
listen 3000;
|
||||
listen [::]:3000;
|
||||
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $forwardscheme;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
proxy_redirect off;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
add_header Access-Control-Allow-Methods *;
|
||||
add_header Access-Control-Allow-Headers *;
|
||||
add_header Cross-Origin-Embedder-Policy $coep_header;
|
||||
add_header Cross-Origin-Opener-Policy $coop_header;
|
||||
}
|
||||
|
||||
# Static files
|
||||
location /assets {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# OpenAPI for swagger and redoc
|
||||
location /openapi.json {
|
||||
proxy_pass http://backend_server;
|
||||
}
|
||||
|
||||
# Backend api calls
|
||||
location /api {
|
||||
proxy_pass http://backend_server;
|
||||
proxy_request_buffering off;
|
||||
proxy_buffering off;
|
||||
}
|
||||
location ~ ^/(ws|netplay) {
|
||||
proxy_pass http://backend_server;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
|
||||
# Internally redirect download requests
|
||||
location /library/ {
|
||||
internal;
|
||||
alias "/app/data/library/";
|
||||
}
|
||||
|
||||
# Internal decoding endpoint, used to decode base64 encoded data
|
||||
location /decode {
|
||||
internal;
|
||||
js_content decode.decodeBase64;
|
||||
}
|
||||
}
|
||||
13
env.sh.template
Normal file
13
env.sh.template
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -eu
|
||||
|
||||
export IGDB_CLIENT_ID=
|
||||
export IGDB_CLIENT_SECRET=
|
||||
export MOBYGAMES_API_KEY=
|
||||
export STEAMGRIDDB_API_KEY=
|
||||
export RETROACHIEVEMENTS_API_KEY=
|
||||
export SCREENSCRAPER_USER=
|
||||
export SCREENSCRAPER_PASSWORD=
|
||||
export HASHEOUS_API_ENABLED=true
|
||||
export OIDC_ENABLED=true
|
||||
BIN
logo.png
BIN
logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 13 KiB |
88
nginx.conf
Normal file
88
nginx.conf
Normal file
@@ -0,0 +1,88 @@
|
||||
load_module modules/ngx_http_js_module.so;
|
||||
load_module modules/ngx_http_zip_module.so;
|
||||
|
||||
worker_processes auto;
|
||||
pid /tmp/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
client_body_temp_path /tmp/client_body 1 2;
|
||||
fastcgi_temp_path /tmp/fastcgi 1 2;
|
||||
proxy_temp_path /tmp/proxy;
|
||||
uwsgi_temp_path /tmp/uwsgi;
|
||||
scgi_temp_path /tmp/scgi;
|
||||
|
||||
sendfile on;
|
||||
client_body_buffer_size 128k;
|
||||
client_max_body_size 0;
|
||||
client_header_buffer_size 1k;
|
||||
large_client_header_buffers 4 16k;
|
||||
send_timeout 600s;
|
||||
keepalive_timeout 600s;
|
||||
client_body_timeout 600s;
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
|
||||
ssl_prefer_server_ciphers on;
|
||||
|
||||
js_import /etc/nginx/js/decode.js;
|
||||
|
||||
map $time_iso8601 $date {
|
||||
~([^+]+)T $1;
|
||||
}
|
||||
map $time_iso8601 $time {
|
||||
~T([0-9:]+)\+ $1;
|
||||
}
|
||||
|
||||
# Map to extract the browser name (e.g., Chrome, Firefox, etc.)
|
||||
map $http_user_agent $browser {
|
||||
default "Unknown";
|
||||
"~Chrome/" "Chrome";
|
||||
"~Firefox/" "Firefox";
|
||||
"~Safari/" "Safari";
|
||||
"~Edge/" "Edge";
|
||||
"~Opera/" "Opera";
|
||||
}
|
||||
|
||||
# Map to extract the OS (e.g., Windows, MacOS, Linux)
|
||||
map $http_user_agent $os {
|
||||
default "Unknown";
|
||||
"~Windows NT" "Windows";
|
||||
"~Macintosh" "macOS";
|
||||
"~Linux" "Linux";
|
||||
"~Android" "Android";
|
||||
"~iPhone" "iOS";
|
||||
}
|
||||
|
||||
#INFO: [nginx][2023-11-14 09:20:29] 127.0.0.1 - -"GET / HTTP/1.1" 500 177 "-" "Mozilla/5.0 (X11; Linux x86_64)"rt=0.000 uct="-" uht="-" urt="-"
|
||||
log_format romm_logs 'INFO: [RomM][nginx][$date $time] '
|
||||
'$remote_addr | $http_x_forwarded_for | '
|
||||
'$request_method $request_uri $status | $body_bytes_sent | '
|
||||
'$browser $os | $request_time';
|
||||
|
||||
access_log /dev/stdout romm_logs;
|
||||
error_log /dev/stderr;
|
||||
|
||||
gzip on;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
gzip_comp_level 6;
|
||||
gzip_buffers 16 8k;
|
||||
gzip_min_length 1024;
|
||||
gzip_http_version 1.1;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
upstream backend_server {
|
||||
server 127.0.0.1:5000;
|
||||
}
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
64
start.sh
64
start.sh
@@ -2,10 +2,32 @@
|
||||
set -eu
|
||||
|
||||
mkdir -p /app/data/library /app/data/config /app/data/assets /app/data/resources
|
||||
mkdir -p /tmp/vite-temp
|
||||
mkdir -p /tmp/vite-temp /tmp/vite /tmp/cache
|
||||
|
||||
CONFIG_TEMPLATE_FILE="/app/pkg/config.yml.template"
|
||||
CONFIG_FILE="/app/data/config/config.yml"
|
||||
|
||||
# Check if config file exists in /app/data/config
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
echo "config.yml already exists in $CONFIG_FILE"
|
||||
else
|
||||
# Copy the template to the target location
|
||||
echo "Copying $CONFIG_TEMPLATE_FILE to $CONFIG_FILE"
|
||||
cp "$CONFIG_TEMPLATE_FILE" "$CONFIG_FILE"
|
||||
|
||||
# Add in TURN
|
||||
readonly time=$(date +%s)
|
||||
readonly expiry=512640 # one year in seconds
|
||||
export turn_username=$(( $time + $expiry ))
|
||||
export turn_password=$(echo -n $turn_username | openssl dgst -binary -sha1 -hmac ${CLOUDRON_TURN_SECRET} | openssl base64)
|
||||
|
||||
envsubst < $CONFIG_TEMPLATE_FILE > $CONFIG_FILE
|
||||
|
||||
echo "Successfully created $CONFIG_FILE from template"
|
||||
fi
|
||||
|
||||
# ensure that data directory is owned by 'cloudron' user
|
||||
chown -R cloudron:cloudron /app/data /tmp/vite-temp /root/.local/share/uv/python
|
||||
chown -R cloudron:cloudron /app/data /tmp/vite-temp /tmp/vite /tmp/cache
|
||||
|
||||
cd /app/data
|
||||
|
||||
@@ -15,18 +37,40 @@ export DB_PORT=${CLOUDRON_POSTGRESQL_PORT}
|
||||
export DB_NAME=${CLOUDRON_POSTGRESQL_DATABASE}
|
||||
export DB_USER=${CLOUDRON_POSTGRESQL_USERNAME}
|
||||
export DB_PASSWD=${CLOUDRON_POSTGRESQL_PASSWORD}
|
||||
export ROMM_AUTH_SECRET_KEY=$(/usr/bin/openssl rand -hex 32)
|
||||
export IGDB_CLIENT_ID=
|
||||
export IGDB_CLIENT_SECRET=
|
||||
export MOBYGAMES_API_KEY=
|
||||
export STEAMGRIDDB_API_KEY=
|
||||
export OIDC_ENABLED=true
|
||||
export OIDC_PROVIDER=${CLOUDRON_OIDC_PROVIDER_NAME}
|
||||
export OIDC_CLIENT_ID=${CLOUDRON_OIDC_CLIENT_ID}
|
||||
export OIDC_CLIENT_SECRET=${CLOUDRON_OIDC_CLIENT_SECRET}
|
||||
export OIDC_REDIRECT_URI="/api/oauth/openid"
|
||||
export OIDC_SERVER_APPLICATION_URL=${CLOUDRON_OIDC_AUTH_ENDPOINT}
|
||||
export OIDC_REDIRECT_URI="${CLOUDRON_APP_ORIGIN}/api/oauth/openid"
|
||||
export OIDC_SERVER_APPLICATION_URL=${CLOUDRON_OIDC_ISSUER}
|
||||
export UV_PYTHON_INSTALL_DIR=/app/code/uv
|
||||
export DEV_HTTPS=false
|
||||
export __VITE_ADDITIONAL_SERVER_ALLOWED_HOSTS=${CLOUDRON_APP_DOMAIN}
|
||||
export XDG_CACHE_HOME=/tmp/cache
|
||||
export REDIS_HOST=${CLOUDRON_REDIS_HOST}
|
||||
export REDIS_PORT=${CLOUDRON_REDIS_PORT}
|
||||
export ROMM_BASE_PATH=/app/data
|
||||
export ROMM_TMP_PATH=/tmp
|
||||
|
||||
ENV_TEMPLATE_FILE="/app/pkg/env.sh.template"
|
||||
ENV_FILE="/app/data/env.sh"
|
||||
|
||||
# Check if env.sh exists in /app/data
|
||||
if [ -f "$ENV_FILE" ]; then
|
||||
echo "env.sh already exists in $ENV_FILE"
|
||||
else
|
||||
# Copy the template to the target location
|
||||
echo "Copying $ENV_TEMPLATE_FILE to $ENV_FILE"
|
||||
cp "$ENV_TEMPLATE_FILE" "$ENV_FILE"
|
||||
chmod +x "$ENV_FILE"
|
||||
|
||||
# Generate a new secret key using openssl
|
||||
SECRET_KEY=$(openssl rand -hex 32 2>/dev/null)
|
||||
echo "export ROMM_AUTH_SECRET_KEY=$SECRET_KEY" >> "$ENV_FILE"
|
||||
|
||||
echo "Successfully created $ENV_FILE from template"
|
||||
fi
|
||||
|
||||
source /app/data/env.sh
|
||||
|
||||
echo "==> Starting supervisor"
|
||||
exec /usr/bin/supervisord --configuration /etc/supervisor/supervisord.conf --nodaemon -i Romm
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[program:backend]
|
||||
priority=5
|
||||
directory=/app/code/frontend
|
||||
environment=HOME=/app/code
|
||||
command=npm run dev
|
||||
user=cloudron
|
||||
[program:frontend]
|
||||
priority=50
|
||||
directory=/tmp
|
||||
command=/usr/sbin/nginx -g "daemon off;"
|
||||
user=root
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
|
||||
15
supervisor/rq.conf
Normal file
15
supervisor/rq.conf
Normal file
@@ -0,0 +1,15 @@
|
||||
[program:rq]
|
||||
priority=10
|
||||
process_name="%(program_name)s_%(process_num)02d"
|
||||
numprocs=2
|
||||
directory=/app/code/backend
|
||||
environment=HOME=/app/code
|
||||
environment=PYTHONPATH="/app/code/backend:${PYTHONPATH-}"
|
||||
command=uv run rq worker --path /app/code/backend --pid /tmp/rq_worker_%(process_num)02d.pid --url "redis://%(ENV_REDIS_HOST)s:%(ENV_REDIS_PORT)s/0" high default low
|
||||
user=cloudron
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
12
supervisor/rqscheduler.conf
Normal file
12
supervisor/rqscheduler.conf
Normal file
@@ -0,0 +1,12 @@
|
||||
[program:rqscheduler]
|
||||
priority=10
|
||||
directory=/app/code/backend
|
||||
environment=HOME=/app/code
|
||||
command=uv run rqscheduler --host %(ENV_REDIS_HOST)s --port %(ENV_REDIS_PORT)s --db 0 --path /app/code.backend --pid /tmp/rq_scheduler.pid
|
||||
user=cloudron
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
12
supervisor/watcher.conf
Normal file
12
supervisor/watcher.conf
Normal file
@@ -0,0 +1,12 @@
|
||||
[program:watcher]
|
||||
priority=20
|
||||
directory=/app/code/backend
|
||||
environment=HOME=/app/code
|
||||
command=uv run watchfiles --target-type command 'python watcher.py' /app/data/library
|
||||
user=cloudron
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
Reference in New Issue
Block a user