Add Dockerfile, docker-compose.yml, .dockerignore
Multi-stage Dockerfile: - Stage 1: install deps, build TS, build web UI - Stage 2: minimal production image with sqlite, only prod deps - Exposes port 4738, uses /data volume for SQLite docker-compose.yml for easy local deployment with .env support. .dockerignore to keep the build context lean. README updated with Docker usage. .env.template adds DATA_DIR.
This commit is contained in:
parent
f220301154
commit
31deaf3aa5
5 changed files with 134 additions and 0 deletions
15
.dockerignore
Normal file
15
.dockerignore
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
web/dist/
|
||||||
|
.git/
|
||||||
|
.gitattributes
|
||||||
|
.gitignore
|
||||||
|
*.md
|
||||||
|
test/
|
||||||
|
mailship.db
|
||||||
|
test-mailship.db
|
||||||
|
test-data/
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
*.p8
|
||||||
|
*firebase*
|
||||||
|
|
@ -8,3 +8,4 @@ SEARCH_RELAYS=relay.nostr.band
|
||||||
POSTMARK_API_KEY=
|
POSTMARK_API_KEY=
|
||||||
POSTMARK_SENDER_ADDRESS=
|
POSTMARK_SENDER_ADDRESS=
|
||||||
PORT=4738
|
PORT=4738
|
||||||
|
DATA_DIR=./data
|
||||||
|
|
|
||||||
67
Dockerfile
Normal file
67
Dockerfile
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
FROM node:22-alpine AS build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install build dependencies for native modules
|
||||||
|
RUN apk add --no-cache python3 make g++ git
|
||||||
|
|
||||||
|
# Install pnpm
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
|
COPY remove-pnpm-overrides.js ./
|
||||||
|
|
||||||
|
# Remove pnpm link overrides for production build
|
||||||
|
RUN node remove-pnpm-overrides.js package.json
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source
|
||||||
|
COPY tsconfig.json ./
|
||||||
|
COPY src/ ./src/
|
||||||
|
COPY src/pages/ ./src/pages/
|
||||||
|
COPY src/emails/ ./src/emails/
|
||||||
|
|
||||||
|
# Build TypeScript
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
# Build web UI
|
||||||
|
COPY web/package.json web/pnpm-lock.yaml web/tsconfig.json web/vite.config.js web/index.html ./
|
||||||
|
COPY web/src/ ./web/src/
|
||||||
|
RUN cd web && pnpm install --frozen-lockfile && pnpm run build
|
||||||
|
|
||||||
|
# Production image
|
||||||
|
FROM node:22-alpine AS production
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apk add --no-cache sqlite
|
||||||
|
|
||||||
|
# Install pnpm
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
# Copy production dependencies
|
||||||
|
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
|
||||||
|
COPY remove-pnpm-overrides.js ./
|
||||||
|
RUN node remove-pnpm-overrides.js package.json
|
||||||
|
RUN pnpm install --frozen-lockfile --prod
|
||||||
|
|
||||||
|
# Copy build artifacts
|
||||||
|
COPY --from=build /app/dist/ ./dist/
|
||||||
|
COPY --from=build /app/web/dist/ ./web/dist/
|
||||||
|
COPY --from=build /app/src/pages/ ./dist/pages/
|
||||||
|
COPY --from=build /app/src/emails/ ./dist/emails/
|
||||||
|
|
||||||
|
# Create data directory for SQLite
|
||||||
|
RUN mkdir -p /data
|
||||||
|
|
||||||
|
EXPOSE 4738
|
||||||
|
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
ENV PORT=4738
|
||||||
|
ENV DATA_DIR=/data
|
||||||
|
|
||||||
|
CMD ["node", "dist/index.js"]
|
||||||
28
README.md
28
README.md
|
|
@ -79,6 +79,34 @@ pnpm run build
|
||||||
pnpm run start
|
pnpm run start
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
### Quick start
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp .env.template .env
|
||||||
|
# Fill in your secrets in .env
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build and run manually
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker build -t mailship .
|
||||||
|
docker run -d \
|
||||||
|
-p 4738:4738 \
|
||||||
|
-v mailship-data:/data \
|
||||||
|
--env-file .env \
|
||||||
|
mailship
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pnpm test # Run integration tests
|
||||||
|
pnpm test:server # Start server for manual testing
|
||||||
|
```
|
||||||
|
|
||||||
## Forked from Anchor
|
## Forked from Anchor
|
||||||
|
|
||||||
Mailship is a fork of [Anchor](https://github.com/coracle-social/anchor), stripped of push notification support and adapted for NIP-9a relay push event intake.
|
Mailship is a fork of [Anchor](https://github.com/coracle-social/anchor), stripped of push notification support and adapted for NIP-9a relay push event intake.
|
||||||
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
services:
|
||||||
|
mailship:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "4738:4738"
|
||||||
|
volumes:
|
||||||
|
- mailship-data:/data
|
||||||
|
environment:
|
||||||
|
- MAILSHIP_SECRET=${MAILSHIP_SECRET:?required}
|
||||||
|
- MAILSHIP_NAME=${MAILSHIP_NAME:-Mailship}
|
||||||
|
- MAILSHIP_URL=${MAILSHIP_URL:?required}
|
||||||
|
- BASE_URL=${BASE_URL:?required}
|
||||||
|
- POSTMARK_API_KEY=${POSTMARK_API_KEY:?required}
|
||||||
|
- POSTMARK_SENDER_ADDRESS=${POSTMARK_SENDER_ADDRESS:?required}
|
||||||
|
- DEFAULT_RELAYS=${DEFAULT_RELAYS:-wss://relay.damus.io,wss://relay.primal.net}
|
||||||
|
- INDEXER_RELAYS=${INDEXER_RELAYS:-wss://purplepag.es,wss://relay.damus.io}
|
||||||
|
- SEARCH_RELAYS=${SEARCH_RELAYS:-wss://relay.nostr.band}
|
||||||
|
- PORT=4738
|
||||||
|
- DATA_DIR=/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mailship-data:
|
||||||
Loading…
Reference in a new issue