Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
node_modules
dist
.git
.github
.env
.env.*
*.log
.DS_Store
coverage
Dockerfile
README.md
docs
src/**/*.test.ts
**/*.test.ts
37 changes: 37 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS deps
WORKDIR /app

COPY package*.json ./
RUN npm ci

FROM deps AS build
COPY tsconfig.json ./
COPY src ./src
RUN npm run build

FROM node:22-bookworm-slim AS production-deps
WORKDIR /app
ENV NODE_ENV=production

COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force

FROM node:22-bookworm-slim AS runtime
WORKDIR /app

ENV NODE_ENV=production
ENV PORT=3001

COPY --from=production-deps --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/dist ./dist
COPY --chown=node:node package*.json ./

USER node
EXPOSE 3001
STOPSIGNAL SIGTERM

HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 CMD node -e "fetch('http://127.0.0.1:' + (process.env.PORT || '3001') + '/health').then((res) => { if (!res.ok) process.exit(1); }).catch(() => process.exit(1));"

CMD ["node", "dist/index.js"]
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,32 @@ agentpay-backend/
| `npm run dev` | Run with ts-node |
| `npm start` | Run production build |

## Running with Docker

Build a production image from the repository root:

```bash
docker build -t agentpay-backend .
```

Run it locally, publishing the API on `http://localhost:3001`:

```bash
docker run --rm --name agentpay-backend -p 3001:3001 -e PORT=3001 agentpay-backend
```

Check the container health endpoint:

```bash
curl -fsS http://localhost:3001/health
```

The runtime image contains only production dependencies and the compiled
`dist/` output, runs as the non-root `node` user, and uses `SIGTERM` as the
stop signal so the application graceful-shutdown handler can drain in-flight
requests. Pass configuration with `-e NAME=value` or `--env-file`; real `.env`
files are ignored by Docker builds and must not be baked into image layers.

## Documentation

- [Billing units and settlement semantics](docs/billing-units.md) explains
Expand Down