> For the complete documentation index, see [llms.txt](https://docs.ipcheck.ing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ipcheck.ing/developer/getting-started/deploy-with-nodejs.md).

# Deploy with Node.js

Running from source is the right choice when you want to customize the build — change branding, add a tool, or set any `VITE_*` variable, which Docker's prebuilt image cannot do.

## Prerequisites

| Requirement    | Notes                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Node.js 24** | The official Docker image builds on `node:24-alpine`. Older majors are untested.                                   |
| **pnpm**       | The repo pins its pnpm version in `package.json` (`packageManager`). Use Corepack so you get exactly that version. |
| **git**        | To clone and to pull upgrades.                                                                                     |

{% tabs %}
{% tab title="Corepack (recommended)" %}
Corepack ships with Node.js and provisions the pinned pnpm version automatically:

```bash
corepack enable
```

No global install, no version drift.
{% endtab %}

{% tab title="npm" %}

```bash
npm install -g pnpm
```

Works everywhere, but you are responsible for keeping pnpm close to the pinned version.
{% endtab %}
{% endtabs %}

## Install and build

{% stepper %}
{% step %}

#### Clone

```bash
git clone https://github.com/jason5ng32/MyIP.git
cd MyIP
```

{% endstep %}

{% step %}

#### Configure the environment

```bash
cp .env.example .env
```

Open `.env` and fill in at least the MaxMind credentials:

{% code title=".env" %}

```bash
BACKEND_PORT="11966"
FRONTEND_PORT="18966"
MAXMIND_ACCOUNT_ID="your-account-id"
MAXMIND_LICENSE_KEY="your-license-key"
MAXMIND_AUTO_UPDATE="true"
ALLOWED_DOMAINS="myip.example.com"
```

{% endcode %}

Every other variable is optional — see [Environment Variables](/developer/reference/environment-variables.md).

{% hint style="warning" %}
Set your `VITE_*` variables **before** you build. Vite reads them at build time and bakes them into the bundle; changing them later requires another `pnpm run build`.
{% endhint %}
{% endstep %}

{% step %}

#### Install dependencies

```bash
pnpm install
```

{% endstep %}

{% step %}

#### Build the frontend

```bash
pnpm run build
```

This produces `dist/`, the static bundle the frontend server serves.
{% endstep %}

{% step %}

#### Start

```bash
pnpm start
```

Open <http://localhost:18966>.
{% endstep %}
{% endstepper %}

## The two processes

`pnpm start` runs both halves of the app in one terminal (via `concurrently`):

| Process  | Script               | Default port              | Role                                                                                                     |
| -------- | -------------------- | ------------------------- | -------------------------------------------------------------------------------------------------------- |
| Frontend | `frontend-server.js` | `18966` (`FRONTEND_PORT`) | Serves `dist/` with tuned cache headers, handles SPA history fallback, and proxies `/api` to the backend |
| Backend  | `backend-server.js`  | `11966` (`BACKEND_PORT`)  | The Express API, plus the MaxMind and CAIDA dataset updaters                                             |

Users only ever talk to the frontend port. The backend does not need to be reachable from outside the host — the frontend proxies `/api` to `http://localhost:<BACKEND_PORT>` for them.

You can also run them separately:

```bash
pnpm run start-frontend
pnpm run start-backend
```

{% hint style="info" %}
`start-backend` launches Node with `--import ./sentry-instrument.js`. That flag must come before Express loads for Sentry's ESM instrumentation to attach. Without `SENTRY_DSN_BACKEND` it is a no-op, so it is safe to keep in every deployment.
{% endhint %}

## Running under pm2

`pnpm start` dies with your shell. For a real deployment, use the pm2 config that ships with the repo — it already carries the correct Node flags.

{% stepper %}
{% step %}

#### Install pm2

```bash
npm install -g pm2
```

{% endstep %}

{% step %}

#### Start both apps

```bash
pm2 start ecosystem.config.cjs
```

This registers two processes: `myip-backend` and `myip-frontend`.
{% endstep %}

{% step %}

#### Survive reboots

```bash
pm2 save
pm2 startup
```

Then run the command pm2 prints.
{% endstep %}
{% endstepper %}

Useful commands:

```bash
pm2 status
pm2 logs myip-backend
pm2 restart ecosystem.config.cjs
pm2 stop myip-frontend
```

{% hint style="info" %}
The MaxMind updater takes a file lock before it downloads, so running the backend under several pm2 instances will not produce two concurrent downloads or a half-written database.
{% endhint %}

## Upgrading

```bash
git pull
pnpm install
pnpm run build
pm2 restart ecosystem.config.cjs
```

Do not skip `pnpm run build` — the running app serves whatever is in `dist/`, not your updated source.

## Where data lives

Datasets are downloaded into the working tree and are excluded from git:

* `common/maxmind-db/` — `GeoLite2-City.mmdb`, `GeoLite2-ASN.mmdb`, plus updater state and lock files
* `common/as-org-db/`, `common/as-rel-db/` — the CAIDA datasets used for ASN organization names and the ASN connectivity graph

They survive `git pull`, so upgrades do not re-download anything.

## Next steps

* [MaxMind Setup](/developer/getting-started/maxmind-setup.md) — including the manual `.mmdb` option, which only works on this deployment path
* [Reverse Proxy & Domains](/developer/getting-started/reverse-proxy-and-domains.md) — TLS and `ALLOWED_DOMAINS`
* [Development Environment](/developer/development/dev-environment.md) — `pnpm dev` with hot reload, if you plan to change code
* [Environment Variables](/developer/reference/environment-variables.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ipcheck.ing/developer/getting-started/deploy-with-nodejs.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
