RIDM Apps App Hosting
Connect a GitHub repository and every push is built, deployed and published at <name>.ridm.ai. Every app gets its own PostgreSQL database, so you can store members, posts and records right away. Host apps built on the Saju (Four Pillars of Destiny) API, or ordinary web apps that don't use the API at all.
Apply in My Apps Deployment guide Plans & pricing Domain Search
Let AI build your app — free ebooks (Korean)
Choose an ebook (Korean)All-in-one fortune app (Korean)Character chat app (Korean)Members-only web app (Korean)
Deploy in four steps
- Apply — pick a plan and an address (subdomain) in My Apps in the console.
- Connect GitHub — install the GitHub App
ridm-apps-builderand pick a repository and branch. It only gets read access to the repository. - Push — every push to the connected branch starts a build; build history and failure logs appear on the app screen.
- Publish — a successful build goes through automatic checks and goes live right away. Paid plan charges don't start until your first deployment is live.
Static sites with only HTML, CSS and JS also go up as a container (Dockerfile). Put the files in public/ and add the Dockerfile below to the repository root. Requirements such as port 3000 and user 1000 are in the deployment guide.
FROM busybox:1.36
COPY --chown=1000:1000 public /www
USER 1000:1000
EXPOSE 3000
CMD ["httpd", "-f", "-p", "3000", "-h", "/www"]
Hosting large 3D and image-heavy static sites
Sites with tens of MB of models (.glb) and textures, such as three.js games, should use nginx:alpine instead of busybox. busybox httpd can't set cache headers and serves .glb and .ktx2 as generic files. Put the two files below in the repository root and the build output (dist/ with Vite) is served as is.
# Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:1.27-alpine
COPY nginx.conf /etc/nginx/nginx.conf
COPY --from=build --chown=1000:1000 /app/dist /usr/share/nginx/html
USER 1000:1000
EXPOSE 3000
ENTRYPOINT ["nginx", "-g", "daemon off;"]
# nginx.conf — runs as user 1000 on a read-only file system: only /tmp is writable.
worker_processes 1;
pid /tmp/nginx.pid;
error_log /dev/stderr warn;
events { worker_connections 1024; }
http {
include /etc/nginx/mime.types;
# 3D types missing from the stock mime.types (.wasm is already there).
types {
model/gltf-binary glb;
model/gltf+json gltf;
image/ktx2 ktx2;
}
default_type application/octet-stream;
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
access_log off;
server_tokens off;
sendfile on;
tcp_nopush on;
# Text formats only. .glb / .ktx2 / images are already compressed.
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 5;
gzip_types text/css application/javascript text/javascript application/json
image/svg+xml model/gltf+json application/wasm text/plain;
# /assets/ = bundler output whose names carry a content hash (Vite default).
map $uri $cache_control {
~^/assets/ "public, max-age=31536000, immutable";
~*\.(?:glb|gltf|bin|ktx2|basis|hdr|webp|avif|png|jpe?g|svg|mp3|ogg|wasm|js|css|woff2?)$ "public, max-age=3600";
default "no-cache";
}
# Errors (404 etc.) are never cached, so a file added later shows up at once.
map $status $cache_header {
~^(200|206|304)$ $cache_control;
default "no-store";
}
server {
listen 3000;
root /usr/share/nginx/html;
add_header Cache-Control $cache_header always;
# Keeps the site out of search results. Delete this line to be indexed.
add_header X-Robots-Tag "noindex, nofollow" always;
location / {
try_files $uri $uri/ =404;
}
}
}
- Caching — files under
/assets/(build output with hashed names) are cached for a year, other models, images and scripts for an hour, andindex.htmlis revalidated every time. Import a model in code likeimport sceneUrl from './models/scene.glb?url'and Vite puts it in/assets/with a hashed name. Files inpublic/keep their names, so they are cached for an hour only. RIDM Apps passes your app'sCache-Control,Content-TypeandX-Robots-Tagthrough unchanged. - Parallel downloads — the
/assets/path allows more simultaneous downloads per visitor. If you have many models and textures, keep them under/assets/. - Compression — HTML, JS, CSS, JSON,
.gltfand.wasmare compressed by the gzip in the config above and by Brotli at the edge..glb,.ktx2and images don't shrink further in transit, so shrink the files themselves: Draco or meshopt for meshes, KTX2 (Basis) or WebP for textures. Example:npx @gltf-transform/cli optimize scene.glb scene.opt.glb --compress meshopt --texture-compress webp(in three.js, hookMeshoptDecoder,DRACOLoaderandKTX2LoaderintoGLTFLoader). - Size — bundles of tens of MB and single files around 15MB upload and serve without trouble. The repository follows GitHub's limits (100MB per file), and builds must finish within 20 minutes. Files stored with Git LFS are not included in the build, so commit them normally.
- Monthly transfer — everything sent to visitors counts toward monthly transfer. First-time visitors download every file (1,000 first visits to a 30MB site is about 30GB), so making files smaller has the biggest effect. Transfer per plan is on the pricing page.
- Search visibility — the config above keeps the site out of search results with
X-Robots-Tag: noindex. Delete that line to let search engines index it.
What's included
- A dedicated PostgreSQL database per app — connection details arrive as environment variables (
DATABASE_URLand others), and connections use TLS with certificate verification. - Encrypted environment variables — saved values are stored encrypted and can't be viewed again. Saving restarts the app with the new values.
- Database backups — create and download a database dump from the app screen (up to 3 times a day).
- Secret blocking — if keys, tokens or passwords show up in the repository, the build stops and nothing is published.
- Your own domain — for a domain bought on RIDM, go to Domains → Connect to app in the console and choose the root,
www, or a subdomain such asplay.example.com(one level; lowercase letters, numbers and hyphens). RIDM creates the DNS records and certificates. - Any stack — all it needs is a
Dockerfileat the repository root and an app that responds on port 3000. A Next.js starter Dockerfile is in the deployment guide.
Plans
- Free plan — starts when someone visits and stops after 15 minutes without requests. The first visit after it stops may take a few seconds. One per partner.
- Paid plans — always on, and the app restarts automatically if it crashes. Charges are deducted monthly from your prepaid credits.
See the pricing page for each plan's price, memory, database size and monthly transfer. If you cancel, the app stops at the end of the period you've already paid for, and for 30 days after that you can download your data or restore the app.
Limits to know
- WebSocket is available on paid plans (120 concurrent per app, 64KB per message). Full limits are in the hosting docs.
- The file system is read-only; store persistent data in the database.
- Outgoing mail ports (SMTP) are blocked. Send email through a mail service with an HTTPS API.
- Up to 3 concurrent database connections per app.
For the full conditions, see the deployment guide and Chapter 3 of the Terms of Service (Korean).
Want to build one from scratch?
Members-only web app with AI (Korean) is a free, hands-on ebook: give your AI coding tool one starting sentence and it walks you through sign-up and sign-in, a members-only notepad, and publishing on RIDM Apps. To build a Saju app, see All-in-one fortune AI (Korean); to start with the Saju API integration, see the developer Get Started guide.
To build without code, assemble an app from Saju and fortune blocks in Baro (block-based app builder) and upload the downloaded deployment bundle to RIDM Apps as is.
For everything from building to servers, databases and domains in one place, see one-stop app development.
Contact: contact@float.do · Operated by FLOAT Co., Ltd.