diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4eb0c30 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,21 @@ +node_modules +npm-debug.log +.git +.gitignore +.env +.env.local +.env.*.local +.DS_Store +*.log +coverage +.nyc_output +.vscode +.idea +*.swp +*.swo +*~ +build +.repos +repos +*.md +!README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3438872 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,74 @@ +# Dockerfile for gitrepublic-web +# Builds a Node.js application with SvelteKit + +FROM node:20-alpine AS builder + +# Install git and required utilities +# - git: for git operations and git-http-backend +# - zip: for creating ZIP archives (download endpoint) +# - util-linux: for whereis command (used to find git-http-backend) +RUN apk add --no-cache git zip util-linux + +# Set working directory +WORKDIR /app + +# Copy package files +COPY package.json package-lock.json* ./ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build the application +RUN npm run build + +# Production stage +FROM node:20-alpine + +# Install git and required utilities +# - git: for git operations and git-http-backend +# - zip: for creating ZIP archives (download endpoint) +# - util-linux: for whereis command (used to find git-http-backend) +RUN apk add --no-cache git zip util-linux + +# Create app directory +WORKDIR /app + +# Copy package files +COPY package.json package-lock.json* ./ + +# Install production dependencies only +RUN npm ci --only=production + +# Copy built application from builder +COPY --from=builder /app/build ./build +COPY --from=builder /app/package.json ./ + +# Create directory for git repositories +RUN mkdir -p /repos && chmod 755 /repos + +# Create non-root user for security +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 && \ + chown -R nodejs:nodejs /app /repos + +# Switch to non-root user +USER nodejs + +# Expose port +EXPOSE 6543 + +# Set environment variables with defaults +ENV NODE_ENV=production +ENV GIT_REPO_ROOT=/repos +ENV GIT_DOMAIN=localhost:6543 +ENV PORT=6543 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD node -e "require('http').get('http://localhost:6543', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" + +# Start the application +CMD ["node", "build"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..90ce344 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,40 @@ +services: + gitrepublic: + build: + context: . + dockerfile: Dockerfile + container_name: gitrepublic-web + # For localhost: expose port directly + ports: + - "${PORT:-6543}:6543" + # For production behind reverse proxy: comment out ports above and use expose instead + # expose: + # - "6543" # Internal only, accessed via reverse proxy + environment: + - NODE_ENV=production + - GIT_REPO_ROOT=/repos + - GIT_DOMAIN=${GIT_DOMAIN:-localhost:6543} # Set to your domain for production + - NOSTR_RELAYS=${NOSTR_RELAYS:-wss://relay.damus.io,wss://nostr.wine,wss://nos.lol} + - NOSTRGIT_SECRET_KEY=${NOSTRGIT_SECRET_KEY:-} + - PORT=6543 + volumes: + # Persist git repositories + - ./repos:/repos + # Optional: mount config file if needed + # - ./config:/app/config:ro + restart: unless-stopped + healthcheck: + test: ["CMD", "node", "-e", "require('http').get('http://localhost:6543', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"] + interval: 30s + timeout: 3s + retries: 3 + start_period: 10s + # Resource limits (adjust as needed) + deploy: + resources: + limits: + cpus: '2' + memory: 2G + reservations: + cpus: '1' + memory: 1G