Skip to content

Commit

Permalink
temp: save progress
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerlepine committed Oct 19, 2024
1 parent 5294447 commit afdba67
Show file tree
Hide file tree
Showing 12 changed files with 395 additions and 10 deletions.
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
docker
.git
10 changes: 0 additions & 10 deletions .env.template
Original file line number Diff line number Diff line change
@@ -1,10 +0,0 @@
MY_SECRET_VALUE="foobar"

# Auth0 - https://auth0.com/docs/quickstart/webapp/nextjs/interactive
# Allowed callback URLs: https://my-app.vercel.app/api/auth/callback, http://localhost:3000/api/auth/callback
# Allowed logout URLs: https://my-app.vercel.app, http://localhost:3000
AUTH0_SECRET='use [openssl rand -hex 32] to generate a 32 bytes value'
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://{yourDomain}'
AUTH0_CLIENT_ID='{yourClientId}'
AUTH0_CLIENT_SECRET='{yourClientSecret}'
43 changes: 43 additions & 0 deletions .github/workflows/manual-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# .github/workflows/manual-deploy.yml
# TODO_PRODUCTION

name: Manually Deploy

on:
push:
branches:
- main

jobs:
#bootstrap:
# run bootstrap.ssh?
# PUBLIC_KEY="your_ssh_public_key_here" DOMAIN="your_domain_here" bash bootstrap.sh

deploy:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Re-deploy, update secrets
env:
# secure: only stored in memory during the remote-ssh session
API_KEY: ${{ secrets.API_KEY }}
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
run: |
ssh user@your-vm-ip << 'EOF'
# Authenticate with GitHub CLI using the passed PAT
echo "$GITHUB_TOKEN" | gh auth login --with-token

# Create the .env file with secrets
{
echo "API_KEY=$API_KEY"
echo "DB_PASSWORD=$DB_PASSWORD"
} > .env

# Run docker-compose with the .env file
docker-compose --env-file .env up -d

# Remove the .env file immediately
rm .env
EOF
11 changes: 11 additions & 0 deletions COMMITS
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(update the changelog each time)
commits:
yarn add sharp
git add yarn.lock
feat: stripe checkout with dummy data
feat: printify order integration
feat: enable e2e checkout functionality (stripe + printify)
feat: passwordless email login

checklist:
https://nextjs.org/docs/app/building-your-application/deploying/production-checklist
62 changes: 62 additions & 0 deletions bootstrap.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/bash

# bootstrap.sh
# script to install/configure software on ubuntu LTS virtual machine
# TODO_PRODUCTION - test this ubuntu LTS

# Check if PUBLIC_KEY is set
if [ -z "$PUBLIC_KEY" ]; then
echo "Error: PUBLIC_KEY environment variable is not set."
exit 1
fi

# Check if DOMAIN is set
if [ -z "$DOMAIN" ]; then
echo "Error: DOMAIN environment variable is not set."
exit 1
fi

# Check if EMAIL is set
if [ -z "$EMAIL" ]; then
echo "Error: EMAIL environment variable is not set."
exit 1
fi

# Update and install necessary packages
apt update && apt upgrade -y
apt install -y software-properties-common

# Install Docker
apt install -y docker.io
systemctl enable docker
systemctl start docker

# Install Docker Compose
DOCKER_COMPOSE_VERSION="v2.16.0" # Change to the desired version
curl -SL "https://github.com/docker/compose/releases/download/$DOCKER_COMPOSE_VERSION/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

# Configure UFW
ufw allow OpenSSH
ufw enable

# Install Certbot and Nginx
apt install -y certbot

# Obtain the SSL certificate using standalone mode
certbot certonly --standalone -d "$DOMAIN" --non-interactive --agree-tos --email "$EMAIL"


# Disable password authentication
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart ssh

# Add SSH public key
mkdir -p ~/.ssh
echo "$PUBLIC_KEY" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

# Restart UFW to apply changes
systemctl restart ufw

echo "Bootstrap script completed successfully."
52 changes: 52 additions & 0 deletions docker/development/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
FROM node:20.16-alpine3.19 AS base

# 1. Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat

WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i; \
else echo "Lockfile not found." && exit 1; \
fi

# 2. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Use the corresponding env file for each environment.
COPY .env.development .env.production
RUN npm run build

# 3. Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static


USER nextjs

EXPOSE 3000

ENV PORT=3000

CMD HOSTNAME="0.0.0.0" node server.js
8 changes: 8 additions & 0 deletions docker/development/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
services:
nextjs-app-local:
build:
context: ../../
dockerfile: docker/development/Dockerfile
image: with-docker-multi-env-development
ports:
- "3001:3000"
53 changes: 53 additions & 0 deletions docker/production/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FROM node:20.16-alpine3.19 AS base

# 1. Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat

WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
elif [ -f package-lock.json ]; then npm ci; \
elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i; \
else echo "Lockfile not found." && exit 1; \
fi


# 2. Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# This will do the trick, use the corresponding env file for each environment.
# TODO_DEPLOYMENT - does docker build need this?
# COPY .env.production.sample .env.production
RUN npm run build

# 3. Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production

RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static


USER nextjs

EXPOSE 3000

ENV PORT=3000

CMD HOSTNAME="0.0.0.0" node server.js
105 changes: 105 additions & 0 deletions docker/production/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# TODO_PRODUCTION

services:
watchtower:
image: containrrr/watchtower
command:
- "--label-enable"
- "--interval"
- "30"
- "--rolling-restart"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
reverse-proxy:
image: traefik:v3.1
command:
- "--log.level=ERROR"
- "--accesslog=true"
- "--providers.docker"
- "--providers.docker.exposedbydefault=false"
- "--entryPoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.tlschallenge=true"
- "--certificatesresolvers.myresolver.acme.email=elliott@zenful.cloud"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--entryPoints.web.forwardedHeaders.insecure"
- "--entryPoints.websecure.forwardedHeaders.insecure"
ports:
- "80:80"
- "443:443"
volumes:
- letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock
nextjs-app:
image: ghcr.io/spencerlepine/nextjs-app:prod
labels:
- "traefik.enable=true"
- "traefik.http.middlewares.nextjs-app-ratelimit.ratelimit.average=20"
- "traefik.http.routers.nextjs-app.rule=Host(`zenful.cloud`) && !Method(`POST`)"
- "traefik.http.routers.nextjs-app.entrypoints=websecure"
- "traefik.http.routers.nextjs-app.tls.certresolver=myresolver"
- "traefik.http.routers.nextjs-app.middlewares=nextjs-app-ratelimit"
# Define separate router for POST methods
- "traefik.http.middlewares.nextjs-app-ratelimit-post.ratelimit.average=1"
- "traefik.http.middlewares.nextjs-app-ratelimit-post.ratelimit.period=1m"
- "traefik.http.routers.nextjs-app-post.rule=Host(`zenful.cloud`) && Method(`POST`)"
- "traefik.http.routers.nextjs-app-post.middlewares=nextjs-app-ratelimit-post"
- "traefik.http.routers.nextjs-app-post.entrypoints=websecure"
- "traefik.http.routers.nextjs-app-post.tls.certresolver=myresolver"
# Proxy
- "traefik.http.routers.proxy.rule=Host(`proxy.dreamsofcode.io`)"
- "traefik.http.routers.proxy.entrypoints=websecure"
- "traefik.http.routers.proxy.tls.certresolver=myresolver"
# Enable watchtower
- "com.centurylinklabs.watchtower.enable=true"
environment:
- POSTGRES_HOST=db
- POSTGRES_USER=postgres
- POSTGRES_DB=nextjs-app
- POSTGRES_PORT=5432
- POSTGRES_SSLMODE=disable
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
deploy:
mode: replicated
replicas: 3
restart: always
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres
restart: always
user: postgres
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=nextjs-app
- POSTGRES_PASSWORD=${DATABASE_PASSWORD}
expose:
- 5432
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 10s
timeout: 5s
retries: 5

dragonfly:
image: 'docker.dragonflydb.io/dragonflydb/dragonfly'
ulimits:
memlock: -1
network_mode: "host"
volumes:
- dragonflydata:/data

volumes:
db-data:
letsencrypt:
dragonflydata:
21 changes: 21 additions & 0 deletions src/app/api/v1/checkout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { NextResponse } from 'next/server';

// export const POST = async (request: NextRequest) => {
export const POST = async () => {
try {
// const cartProducts = await request.json();
// parse cartProducts by ID and SIZE.
// generate prices server size
// + make sure to pass metadata to stripe, (slug, size)

// // source: https://github.com/dayhaysoos/use-shopping-cart/blob/master/use-shopping-cart/utilities/serverless.js
// const line_items = validateCartItems(PRODUCT_INVENTORY, cartProducts)

// TODO_STRIPE - endpoint

return NextResponse.json({ message: 'work in progress' });
} catch (error) {
console.error('Error processing request:', error);
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
}
};
Loading

0 comments on commit afdba67

Please sign in to comment.