Deploy a React App to Production in a Minute
Take a React app from your machine to a live HTTPS URL on managed cloud hosting: a tiny production Dockerfile, one deploy in Cloud Studio, and automatic TLS, subdomain, logs, and monitoring. Start on the free $5 trial credit, no card needed.
You built a React app and it runs on your laptop. Now you want it on a real address, over HTTPS, that anyone can open. A React app is just static files after npm run build, so the whole job is: wrap those files in a tiny container, hand it to the platform, and let it serve them with a certificate and a subdomain. This guide does exactly that, and once the first setup is in place every later change is a single git push.
What you'll need
- A React app in a Git repository (Vite or Create React App, either is fine)
- Docker installed locally, to build and test the image before shipping it
- An alawadi.cloud account: sign in with Google, no card, and claim the free trial credit inside the portal
Step 1: Build the static bundle
Building a React app turns your components into plain HTML, CSS, and JavaScript. With Vite the output lands in dist/; with Create React App it lands in build/. Run it once locally to be sure it succeeds:
npm ci
npm run build # Vite writes to dist/, CRA writes to build/Everything under that folder is your whole site. There is no Node process to keep alive in production, just files to serve, which is why this deploy is so light.
Step 2: Write a production Dockerfile
The platform routes traffic to port 8080 and rejects containers that run as root, so the runtime image serves the built files on 8080 as a non-root user. Create a Dockerfile at the repo root:
# Build stage: produce the static bundle
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build # Vite writes the static site to /app/dist
# Runtime stage: serve the static files on port 8080 as a non-root user
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN npm install -g serve
COPY --from=build /app/dist ./dist
# node:alpine ships a non-root "node" user; the platform rejects root containers
USER node
EXPOSE 8080
CMD ["serve", "-s", "dist", "-l", "8080"]serve -s serves the folder as a single-page app, so client-side routes like /dashboard fall back to index.html instead of 404ing. Test the whole thing locally before you deploy:
docker build -t my-react-app .
docker run --rm -p 8080:8080 my-react-app
# open http://localhost:8080If it works here, it works on the platform, because it is the exact same image.
Step 3: Deploy through Cloud Studio
Open Cloud Studio in the portal, pick Application as what you want to deploy, give it a name, and choose public access. Cloud Studio creates the project and boots your app right away on a public *.alawadi.cloud subdomain with TLS already in place, running a placeholder image until your real image arrives in the next step.
Step 4: Ship your image and turn on auto-deploy
You push your image to a private registry on the platform, and every push to main becomes a deploy:
- From Registries, create a private Docker registry and link it to your project.
- On the registry page, connect your Git repository through the two GitHub OIDC forms: one lets the repo push images, the other lets it trigger deploys. No static secrets are stored in GitHub.
- Click Copy workflow to get a ready
deploy.ymlwith every value filled in, and save it under.github/workflows/in your repo.
The full walkthrough of this exact flow is in the 5-minute deploy guide and the end-to-end launch checklist. From here, git push builds the image, pushes it, and your new version is live in about a minute.
What the platform gives you for free
Once the app is running, you did not have to configure any of this:
- A TLS certificate on your
*.alawadi.cloudsubdomain, managed and renewed automatically. - Live logs and metrics in the dashboard, with one-click restart.
- Your own custom domain: add it on the app's page, point the DNS record the portal shows you, and the certificate is handled for you.
- Alert policies and autoscaling when you need them.
Environment variables
React reads environment variables at build time, not at runtime. Vite exposes variables prefixed with VITE_ (Create React App uses REACT_APP_), and their values are baked into the bundle when npm run build runs. So set them before the build step, not on the running container. Keep anything secret on your backend API instead, because whatever is compiled into a static bundle is visible to every visitor who opens the page.
Talking to a backend
If your React app calls an API, deploy that API as a second container in the same project, and add a managed PostgreSQL database from the Databases tab. Linking the database injects its connection string into your API automatically, so no password is ever copied by hand. The full app-plus-database path is covered in the launch guide.
What it costs, and how to start
Billing is pay-as-you-go against a USD-credit ledger, and every service is its own clear line item with optional USD, SYP, AED, or JOD display. Build an estimate with the pricing calculator, then claim the $5 trial credit inside the portal with no card. Prepaid vouchers priced in SYP are the only live top-up rail; card and cryptocurrency top-ups are not currently available.
FAQ
Do I need to write an nginx config or run a server?
No. The serve command in the runtime image handles static files and single-page routing. You never touch a web-server config.
Does "in a minute" mean the very first time?
The first setup, writing the Dockerfile and connecting the repository, is a few minutes of one-time work. After that, each deploy is a single git push and your new version is live in about a minute.
Vite or Create React App?
Both work. The only difference is the output folder: dist for Vite, build for CRA. Adjust the COPY line in the Dockerfile to match.
Questions? Open a support ticket in the portal, or email [email protected].
The company behind alawadi.cloud
The company building an Arabic-first cloud platform, from the physical servers up to the developer experience.