Skip to content

Commit

Permalink
save progress - docker broken :(
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerlepine committed Oct 25, 2024
1 parent 2b4ee1f commit ea35f30
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 6 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
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
9 changes: 9 additions & 0 deletions COMMITS
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(update the changelog each time)
feat: e2e stripe checkout functionality
feat: printify order integration
feat: passwordless email login
cleanup: retry logic, error handling, logging

checklist:
https://nextjs.org/docs/app/building-your-application/deploying/production-checklist

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ stripe listen --forward-to localhost:3000/api/v1/webhook/checkout
# *open separate terminal*

cp .env.template .env.development
docker-compose -f ./docker/development/docker-compose.yml --env-file .env.development up -d
docker-compose -f ./docker/docker-compose.dev.yml --env-file .env.development up --no-deps --build
# visit http://locahost:3000
```

Expand Down
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."
53 changes: 53 additions & 0 deletions docker/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 . .

# 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 ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/public ./public

USER nextjs

EXPOSE 3000

ENV PORT=3000

CMD npm start
7 changes: 7 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
services:
nextjs-app-local:
build:
context: ../
dockerfile: docker/Dockerfile
ports:
- "3000:3000"
105 changes: 105 additions & 0 deletions docker/docker-compose.prod.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:
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dependencies": {
"fuse.js": "^7.0.0",
"next": "14.2.11",
"printify-sdk-js": "^1.0.1",
"printify-sdk-js": "1.0.2",
"react": "^18",
"react-dom": "^18",
"sharp": "^0.33.5",
Expand Down
26 changes: 26 additions & 0 deletions requests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
curl -X GET https://api.printify.com/v1/shops.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN" [{"id":1234567,"title":"StoreName Etsy","sales_channel":"etsy"}]

curl -X GET https://api.printify.com/v1/catalog/blueprints/1268/print_providers/1/variants.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN"

curl -X GET https://api.printify.com/v1/catalog/blueprints/1268/print_providers.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN"

curl -X GET https://api.printify.com/v1/catalog/blueprints/1268/print_providers/215/variants.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN" {"id":215,"title":"Stickers &
Posters","variants":[ {"id":95743,"title":"3\" x 4\" \/ Kiss-Cut \/ Satin","options":{"size":"3\" x
4\"","shape":"Kiss-Cut","paper":"Satin"},"placeholders":[{"position":"front","height":800,"width":600}]}, {"id":95744,"title":"4\" x 6\" \/ Kiss-Cut \/
Satin","options":{"size":"4\" x 6\"","shape":"Kiss-Cut","paper":"Satin"},"placeholders":[{"position":"front","height":1200,"width":800}]}, {"id":95745,"title":"6\" x 8\" \/
Kiss-Cut \/ Satin","options":{"size":"6\" x 8\"","shape":"Kiss-Cut","paper":"Satin"},"placeholders":[{"position":"front","height":1600,"width":1200}]}, {"id":95746,"title":"8\" x
10\" \/ Kiss-Cut \/ Satin","options":{"size":"8\" x 10\"","shape":"Kiss-Cut","paper":"Satin"},"placeholders":[{"position":"front","height":2000,"width":1600}]} ] }

curl -X GET https://api.printify.com/v1/catalog/blueprints/1268/print_providers/215/shipping.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN" { "handling_time": { "value":
10, "unit": "day" }, "profiles": [ { "variant_ids": [95743, 95744, 95745, 95746], "first_item": { "cost": 469, "currency": "USD" }, "additional_items": { "cost": 9, "currency":
"USD" }, "countries": ["US"] }, { "variant_ids": [95743, 95744, 95745, 95746], "first_item": { "cost": 839, "currency": "USD" }, "additional_items": { "cost": 49, "currency": "USD"
}, "countries": ["CA"] }, { "variant_ids": [95743, 95744, 95745, 95746], "first_item": { "cost": 1049, "currency": "USD" }, "additional_items": { "cost": 59, "currency": "USD" },
"countries": ["REST_OF_THE_WORLD"] } ] }

curl -X https://api.printify.com/v1/shops/{shop_id}/orders.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN"

{ "external_id": "2750e210-39bb-11e9-a503-452618153e4a", "label": "00012", "line_items": [ { "product_id": "5bfd0b66a342bcc9b5563216", "variant_id": 17887, "quantity": 1 } ],
"shipping_method": 1, "is_printify_express": false, "is_economy_shipping": false, "send_shipping_notification": false, "address_to": { "first_name": "John", "last_name": "Smith",
"email": "[email protected]", "phone": "0574 69 21 90", "country": "BE", "region": "", "address1": "ExampleBaan 121", "address2": "45", "city": "Retie", "zip": "2470" } }

curl -X GET https://api.printify.com/v1/shops/{shop_id}/orders/18739212.4/send_to_production.json --header "Authorization: Bearer $PRINTIFY_API_TOKEN"
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2763,10 +2763,10 @@ [email protected]:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==

printify-sdk-js@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/printify-sdk-js/-/printify-sdk-js-1.0.1.tgz#38b6f799050f02dc70b89730f6542ae51211e1cc"
integrity sha512-4eE6tGzkHspT7R7zSWY4eD8AVQE0+qB+rZmRirIcbOQEDtO0A7zr01QlBWNMs1zFdKe2E5jB5nxz8EQoQSe01Q==
[email protected].2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/printify-sdk-js/-/printify-sdk-js-1.0.2.tgz#497432b72021ee693ad241e7f5a2af771548eab6"
integrity sha512-wOS0hdIYqEhuiX782FcKTc4bnS1IEJeiA3WZUXSfrilWZlw3+nO1OXcfR9x0v6e76KplF2/2EHwgGMX9PzPs8Q==

prop-types@^15.7.2, prop-types@^15.8.1:
version "15.8.1"
Expand Down

0 comments on commit ea35f30

Please sign in to comment.