Skip to the article
Aniq-UI

Dashboard 2Put it online

Put it online

Publish the dashboard and its API on a server with Docker, or the dashboard on Vercel or any Node.js host.

For the Full Stack package

Before you deploy

Before going live. Every seed (yarn seed, yarn seed:prod and the first Docker start) creates sample admins whose passwords are printed in the guides. Change their passwords or delete them, and set your own JWT_SECRET, before the dashboard is reachable by anyone else.

  • Run the API with NODE_ENV=production, your own JWT_SECRET, and CORS_ORIGIN and FRONTEND_URL set to the dashboard's public address. A production API refuses to start without the first two.
  • Behind a reverse proxy (Nginx, Caddy, a load balancer), set TRUST_PROXY=1, so the sign-in limit counts visitors instead of the proxy.
  • Leave DEMO_MODE and NEXT_PUBLIC_DEMO_MODE off, unless the deployment is a public demo.

Before you deploy

Built without an API address, the dashboard runs on its mock API: the sample accounts are in the app's code and are checked in the browser, so anyone can read them and sign in, and every change stays in the visitor's browser. Point it at your API before real users or real data reach it.

The built-in mock API

Leave NEXT_PUBLIC_DEMO_MODE off unless the deployment is a public demo.

Both apps on one server with Docker

The docker-compose.yml that runs the template locally also runs it on a server. Give each app its own domain behind a web server that adds HTTPS, such as Caddy or Nginx, forwarding the dashboard's domain to port 3030 and the API's to port 8000.

  1. Name the two addresses

    Create .env in the dashboard-2-full-stack folder, beside docker-compose.yml. The dashboard compiles the API's address into its JavaScript, and the API allows the dashboard's address in CORS_ORIGIN and FRONTEND_URL, both from these two lines.

    dashboard-2-full-stack/.env
    DASHBOARD_URL=https://admin.your-domain.com
    API_URL=https://api.your-domain.com
  2. Add your keys

    The API also reads back-end/.env when it exists, for the AI provider keys, R2 and the MCP key. Create it from .env.example and add TRUST_PROXY=1 behind your web server. The compose file sets the database, the port and NODE_ENV=production itself, and the API generates a JWT_SECRET into the data volume when you give none.

    Terminalin dashboard-2-full-stack
    cp back-end/.env.example back-end/.env
  3. Start it in the background

    Terminalin dashboard-2-full-stack
    docker compose up --build -d

    Expected result: https://api.your-domain.com/api/health answers "status":"ok", and the dashboard's domain opens the sign-in page.

The services restart with the server. The database lives in the dashboard-2-data volume. After you change DASHBOARD_URL, API_URL or a port, run docker compose up --build -d again: the dashboard has to be built with the new address.

The API on its own

back-end has its own Dockerfile, so any host that builds from a Dockerfile can run the API alone. The container keeps its SQLite database in /data: mount a volume there, or the data is lost with the container. On a new volume it creates the database with the sample data once.

Terminalin back-end
docker build -t dashboard-api .
docker run -d --restart unless-stopped -p 8000:8000 -v dashboard-data:/data -e CORS_ORIGIN=https://admin.your-domain.com -e FRONTEND_URL=https://admin.your-domain.com dashboard-api

The image already runs with NODE_ENV=production and its SQLite file in /data. Pass only the values you need, each with -e, such as -e GOOGLE_API_KEY=.... The usual way to run the API is still docker compose up --build at the package root, which starts it with the dashboard.

On a Node.js host without Docker, the build command is yarn build, the start command yarn start:prod, and yarn seed:prod runs once to create the tables. A SQLite file needs a persistent disk there; on a host without one, use MySQL.

The dashboard on Vercel

  1. Put the dashboard in a private Git repository

    Push the dashboard's folder (front-end in the Full Stack, dashboard-2-front-end in the Admin Dashboard package) to a private repository on GitHub, GitLab or Bitbucket. Your licence does not allow sharing the source code publicly.

  2. Import it in Vercel

    Add a new project from that repository. Vercel detects Next.js; keep the default build settings. In the Full Stack repository, set the project's root directory to front-end.

  3. Add the environment variables

    Add ENABLE_EXPERIMENTAL_COREPACK with the value 1, so Vercel installs with the Yarn version package.json pins. Then NEXT_PUBLIC_API_BASE_URL (your API with /api), NEXT_PUBLIC_WEBSOCKET_BASE_URL (the same address without /api) and NEXT_PUBLIC_BASE_URL (the dashboard's own address). WEATHER_API_KEY is optional.

  4. Deploy

    Start the deployment, then add your domain in the project's Domains settings, and add that address to the API's CORS_ORIGIN and FRONTEND_URL.

    Expected result: Your domain opens the sign-in page.

After you change a NEXT_PUBLIC_* variable, deploy again: the running app keeps the values it was built with.

The dashboard on a Node.js server

With your settings in the dashboard's .env, install, build and start:

Terminal
corepack enable
yarn install
yarn build
yarn start

It answers on port 3030, or on PORT when the host sets one. Put a web server in front of it for your domain and HTTPS, and keep yarn start running with a process manager or a system service.

The dashboard as a Docker image

The dashboard's Dockerfile builds a standalone server on port 3030, run as a user without admin rights. The API's address is a build argument:

Terminal
docker build -t dashboard-2 --build-arg NEXT_PUBLIC_API_BASE_URL=https://api.your-domain.com/api --build-arg NEXT_PUBLIC_WEBSOCKET_BASE_URL=https://api.your-domain.com --build-arg NEXT_PUBLIC_BASE_URL=https://admin.your-domain.com .
docker run -d --restart unless-stopped -p 3030:3030 dashboard-2

WEATHER_API_KEY is read when the container runs: add -e WEATHER_API_KEY=... to docker run.

After it is online

  • Sign in at your dashboard's address, with /en and /ar, and check both languages.
  • Every page tells search engines not to index it, through an X-Robots-Tag: noindex, nofollow header set in next.config.js, because a signed-in dashboard does not belong in search results.

Stuck on a step?

Find a fix before you start over.

Troubleshooting

Cookie Preferences

We use cookies to enhance your browsing experience, analyze site traffic, and personalize content. By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising.