# Docker Compose

> Run the panel, PostgreSQL and Prometheus together with the shipped compose file.

Source: https://joinnasnet.com/en/guides/nasnet-linux/install/docker-compose/
Last updated: 2026-08-14

---

## Overview

The repository ships a `docker-compose.yml` that brings up three services: the
app (`nasnet_panel_backend`), **PostgreSQL 16** (`nasnet_panel_db`) and
**Prometheus** (`nasnet_panel_prometheus`). This is the recommended path when you
already have Docker on the host and prefer to edit the configuration yourself
rather than answer a wizard.

## Before you start

- Docker Engine and the Docker Compose plugin installed.
- Your `JWT_SECRET_KEY` and `ADMIN_PASSWORD_HASH` generated, as covered in
  [Installation](/en/guides/nasnet-linux/install/).
- Port `9761` reachable, or a different value ready for `APP_PORT`.

## Steps

1. Clone the repository and create your config file.

   ```bash
   git clone https://github.com/nasnet-community/nasnet-panel-linux.git
   cd nasnet-panel-linux
   cp .env.example .env
   ```

2. Edit `.env` and set at minimum `ADMIN_USERNAME`, `ADMIN_PASSWORD_HASH`,
   `JWT_SECRET_KEY`, `APP_BASE_URL` and `DB_PASSWORD`.

3. Start the stack and watch it come up.

   ```bash
   docker compose up -d
   docker compose logs -f app
   ```

4. When the `app` container reports healthy, open your `APP_BASE_URL` and sign
   in. Compose health-checks the app against `http://localhost:${APP_PORT}/health/ready`.

### Using SQLite instead of PostgreSQL

For a small single-server setup you can drop the database container. Set this in
`.env`:

```dotenv
DB_DRIVER=sqlite
DB_PATH=/app/data/nasnet_panel.db
```

Then start with the override file, which removes the PostgreSQL dependency and
mounts a SQLite volume:

```bash
docker compose -f docker-compose.yml -f docker-compose.sqlite.yml up -d
```

### Publishing proxy ports

The compose file publishes only `${APP_PORT:-9761}` by default. Add the ports
your Xray inbounds listen on to the `app` service's `ports` list, because the file
carries a commented example for `443`.

## Reference

| Item | Value |
| ---- | ----- |
| App container | `nasnet_panel_backend` |
| Database container | `nasnet_panel_db` (`postgres:16-alpine`) |
| Prometheus container | `nasnet_panel_prometheus` (`prom/prometheus:v3.2.1`) |
| Panel port | `${APP_PORT:-9761}` |
| Prometheus port | `${PROMETHEUS_PORT:-9090}` |
| Health check | `/health/ready` |
| Named volumes | `postgres_data`, `acme_data`, `prometheus_data`, `xray_config`, `backups_data` |

The `app` service also gets `NET_ADMIN` and `NET_BIND_SERVICE` capabilities so
Xray can bind privileged ports and manage interfaces.

## Troubleshooting

**The app container restarts before Postgres is ready.** Compose already gates
`app` on the database's `pg_isready` health check, so a loop here usually means
`DB_PASSWORD` in `.env` does not match what the Postgres container was first
initialised with. The password is baked into `postgres_data` on first start, so
either restore the original password or remove the volume (destructive).

## Related

- [Guided installer](/en/guides/nasnet-linux/install/installer-script/)
- [First run and admin sign-in](/en/guides/nasnet-linux/first-run/)
- [Backup](/en/guides/nasnet-linux/backup/)
