diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..5e70f17 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,23 @@ +node_modules +npm-debug.log +.npm +logs +*.log +tmp +.DS_Store +.git +.gitignore +README.md +LICENSE +.dockerignore +dockerfile +.nyc_output +.coverage +.vscode +*.md +*.yml +.env* +dist +*.tar +docker-compose.* +build-image.sh \ No newline at end of file diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..13fc136 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,76 @@ +# Pre-built solution for Sign-up Email Airdrop via Apillon API (backend) + +//TODO: description + +## Environment variables + +For local development and running app you will need to configure some environment variables. List of all supported vars can be found in [`src/config/env.ts`](/src/config/env.ts). + +For local development you should create `.env` file. To run this app in Docker, you can create `.env.deploy` and `.env.sql.deploy` and use provided [`docker-compose.yml`](/docker-compose.yml) + +### .env + +For running locally, create new `.env` file in project root folder (`backend/`) and set at least all the variables (probably with different values) as in `.env.deploy` file described bellow. + +### .env.deploy + +For running a docker image with [`docker-compose.yml`](/docker-compose.yml) you should create `.env.deploy` file like this: + +```sh + +MYSQL_HOST: mysql # DB host (container name or ip/url) +MYSQL_DB: airdrop +MYSQL_USER: root +MYSQL_PASSWORD: Pa55worD?! # set your DB password (same as in .env.sql.deploy) + +APP_URL: 'http://your-custom-url.com' # set URL of your frontend application +ADMIN_WALLET: # your EVM wallet address + +# Apillon configuration +# Create (free) account at https://apillon.io to and setup API key and NFT collection +APILLON_KEY: # Apillon api key +APILLON_SECRET: # Apillon api key secret +COLLECTION_UUID: # Apillon NFT collection UUID + +# Your email server configuration +SMTP_HOST: +SMTP_PORT: '465' +SMTP_USERNAME: +SMTP_PASSWORD: +SMTP_EMAIL_FROM: +SMTP_NAME_FROM: 'NFT Airdrop' + +# API configuration (you can just live it as it is or appropriate fix dockerfile and compose) +API_HOST: 0.0.0.0 +API_PORT: 3000 + +# To Enable hCaptcha, register and get a secret. Remove or use blank if you don't need it. +CAPTCHA_SECRET: + +#Number of hours user have to claim NFT, before they are removed from line and become un eligible to claim +CLAIM_EXPIRES_IN: # default 72 +``` + +### .env.sql.deploy + +For running a mysql docker image with [`docker-compose.yml`](/docker-compose.yml) you should create `.env.sql.deploy` file like this: + +```sh +MYSQL_ROOT_PASSWORD: Pa55worD?! # set your DB password (same as in .env.deploy) +MYSQL_DATABASE: airdrop + +``` +## Deploying with docker + +Build docker image with script [`./build-image.sh`](/build-image.sh) script or by running docker build command, for example: + +```sh +docker build -t ps-signup-email-airdrop . +docker tag ps-signup-email-airdrop ps-signup-email-airdrop:latest +``` + +If you correctly setup .env files, you can run app in docker by running + +```sh +docker compose up -d +``` diff --git a/backend/build-image-beta.sh b/backend/build-image-beta.sh deleted file mode 100755 index e2a7ae8..0000000 --- a/backend/build-image-beta.sh +++ /dev/null @@ -1,4 +0,0 @@ -aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/i0e4n2k8 -docker build -t ment-airdrop:beta.0 . -docker tag ment-airdrop:beta.0 public.ecr.aws/i0e4n2k8/ment-airdrop:beta.0 -docker push public.ecr.aws/i0e4n2k8/ment-airdrop:beta.0 \ No newline at end of file diff --git a/backend/build-image.sh b/backend/build-image.sh index 4ab56c3..10d8ff9 100755 --- a/backend/build-image.sh +++ b/backend/build-image.sh @@ -1,4 +1,5 @@ -aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/i0e4n2k8 -docker build -t ment-airdrop:latest . -docker tag ment-airdrop:latest public.ecr.aws/i0e4n2k8/ment-airdrop:latest -docker push public.ecr.aws/i0e4n2k8/ment-airdrop:latest \ No newline at end of file +set -e + +docker build -t ps-signup-email-airdrop . +docker tag ps-signup-email-airdrop ps-signup-email-airdrop:latest +# docker save -o ps-signup-email-airdrop.tar ps-signup-email-airdrop:latest \ No newline at end of file diff --git a/backend/docker-compose.beta.yml b/backend/docker-compose.beta.yml deleted file mode 100644 index b95068e..0000000 --- a/backend/docker-compose.beta.yml +++ /dev/null @@ -1,47 +0,0 @@ -version: '3.8' - -services: - airdrop_db: - image: mysql - container_name: airdrop_db - env_file: - - .env.sql.deploy - # environment: - # MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} - # MYSQL_DATABASE: ${MYSQL_DATABASE} - ports: - - '3306:3306' - restart: always - volumes: - - mysql-data:/var/lib/mysql - - airdrop_app: - image: public.ecr.aws/i0e4n2k8/ment-airdrop:beta.0 - container_name: airdrop_app - depends_on: - - airdrop_db - env_file: - - .env.deploy - # environment: - # APP_SECRET: ${APP_SECRET} - # APP_URL: ${APP_URL} - # ADMIN_WALLET: ${ADMIN_WALLET} - # APILLON_KEY: ${APILLON_KEY} - # APILLON_SECRET: ${APILLON_SECRET} - # COLLECTION_UUID: ${COLLECTION_UUID} - # SMTP_HOST: ${SMTP_HOST} - # SMTP_PORT: ${SMTP_PORT} - # SMTP_USERNAME: ${SMTP_USERNAME} - # SMTP_PASSWORD: ${SMTP_PASSWORD} - # SMTP_EMAIL_FROM: ${SMTP_EMAIL_FROM} - # SMTP_NAME_FROM: ${SMTP_NAME_FROM} - # API_HOST: ${API_HOST} - # API_PORT: ${API_PORT} - # CAPTCHA_SECRET: ${CAPTCHA_SECRET} - # CLAIM_EXPIRES_IN: ${CLAIM_EXPIRES_IN} - ports: - - '8080:${API_PORT}' - restart: always - -volumes: - mysql-data: diff --git a/backend/docker-compose.proxy.yml b/backend/docker-compose.proxy.yml deleted file mode 100644 index 98764cc..0000000 --- a/backend/docker-compose.proxy.yml +++ /dev/null @@ -1,43 +0,0 @@ -services: - proxy: - image: nginxproxy/nginx-proxy:latest - container_name: nginx-proxy - restart: unless-stopped - ports: - - "80:80" - - "443:443" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - /app/certs:/etc/nginx/certs:ro - # - /etc/nginx/vhost.d - # - /usr/share/nginx/html - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - environment: - - HTTPS_METHOD=noredirect - networks: - - web - - proxy-ssl: - image: nginxproxy/acme-companion - container_name: acme-companion - restart: unless-stopped - volumes_from: - - proxy - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /app/certs:/etc/nginx/certs:rw - - acme:/etc/acme.sh - environment: - - DEFAULT_EMAIL=itkalmia@kalmia.si - networks: - - web - -volumes: - vhost: - html: - acme: - -networks: - web: - name: web diff --git a/backend/docker-compose.yml b/backend/docker-compose.yml index 1906876..fab764a 100644 --- a/backend/docker-compose.yml +++ b/backend/docker-compose.yml @@ -1,36 +1,39 @@ +##### +# This is an example of docker compose file for Apillon pre-built solutions. You are encouraged to change it according to your needs. +##### + version: '3.8' services: airdrop_db: image: mysql container_name: airdrop_db + + ## Enviroment variables can be set in .env files or from build environment + ## Here is how you can use .env file (note: should be separate for each container) env_file: - .env.sql.deploy + + ## If you want to read variables from build environment comment out above section and uncomment below + # environment: + # MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} + # MYSQL_DATABASE: ${MYSQL_DATABASE} + ports: - '3306:3306' restart: always - volumes: - - mysql-data:/var/lib/mysql - networks: - - db airdrop_app: - image: public.ecr.aws/i0e4n2k8/ment-airdrop:latest + image: ps-signup-email-airdrop:latest container_name: airdrop_app depends_on: - airdrop_db + + ## Enviroment variables can be set in .env files or from build environment + ## Here is how you can use .env file (note: should be separate for each container) env_file: - .env.deploy - restart: always - networks: - - web - - db -volumes: - mysql-data: - -networks: - db: - web: - name: web - external: true + ports: + - '8080:3000' + restart: always diff --git a/backend/src/config/env.ts b/backend/src/config/env.ts index 41d529b..d4abb95 100644 --- a/backend/src/config/env.ts +++ b/backend/src/config/env.ts @@ -1,4 +1,4 @@ -import * as dotenv from "dotenv"; +import * as dotenv from 'dotenv'; /** * Environment object interface. */ @@ -28,7 +28,7 @@ export interface IEnv { SMTP_NAME_FROM: string; SMTP_EMAIL_FROM: string; SMTP_EMAIL_FROM_HELLO: string; - APP_URL_BASE: string; + ADMIN_WALLET: string[]; MYSQL_HOST_TEST: string; @@ -58,86 +58,80 @@ export const env = { /** * Application environment info. */ - APP_ENV: process.env["APP_ENV"] || "development", - APP_SECRET: process.env["APP_SECRET"] || "notasecret", - APP_URL: process.env["APP_URL"] || "http://localhost:8000", + APP_ENV: process.env['APP_ENV'] || 'development', + APP_SECRET: process.env['APP_SECRET'] || 'notasecret', + APP_URL: process.env['APP_URL'] || 'http://localhost:8000', /** * Log writing destination. */ - LOG_TARGET: process.env["LOG_TARGET"] || "console", + LOG_TARGET: process.env['LOG_TARGET'] || 'console', /** * HTTP server hostname and port. */ - API_HOST: process.env["API_HOST"] || "127.0.0.1", - API_PORT: parseInt(process.env["API_PORT"]) || 3000, - - /** - * Url base for FE. - */ - APP_URL_BASE: process.env["APP_URL_BASE"], + API_HOST: process.env['API_HOST'] || '127.0.0.1', + API_PORT: parseInt(process.env['API_PORT']) || 3000, /** * Admin */ - ADMIN_WALLET: - process.env["ADMIN_WALLET"]?.toLocaleLowerCase().split(/[,;]/) || [], + ADMIN_WALLET: process.env['ADMIN_WALLET']?.toLocaleLowerCase().split(/[,;]/) || [], /** * Mysql URL. */ - MYSQL_HOST: process.env["MYSQL_HOST"], - MYSQL_PORT: parseInt(process.env["MYSQL_PORT"]) || 3306, - MYSQL_DB: process.env["MYSQL_DB"], - MYSQL_USER: process.env["MYSQL_USER"], - MYSQL_PASSWORD: process.env["MYSQL_PASSWORD"], - MYSQL_POOL: parseInt(process.env["MYSQL_POOL"]), + MYSQL_HOST: process.env['MYSQL_HOST'], + MYSQL_PORT: parseInt(process.env['MYSQL_PORT']) || 3306, + MYSQL_DB: process.env['MYSQL_DB'], + MYSQL_USER: process.env['MYSQL_USER'], + MYSQL_PASSWORD: process.env['MYSQL_PASSWORD'], + MYSQL_POOL: parseInt(process.env['MYSQL_POOL']), /** * Pagination default size limit. */ - PAGE_DEFAULT_LIMIT: parseInt(process.env["PAGE_DEFAULT_LIMIT"]) || 100, + PAGE_DEFAULT_LIMIT: parseInt(process.env['PAGE_DEFAULT_LIMIT']) || 100, /** * Pagination maximum size limit. */ - PAGE_MAX_LIMIT: parseInt(process.env["PAGE_MAX_LIMIT"]), + PAGE_MAX_LIMIT: parseInt(process.env['PAGE_MAX_LIMIT']), /** SMTP */ - SMTP_HOST: process.env["SMTP_HOST"], - SMTP_PORT: parseInt(process.env["SMTP_PORT"]), - SMTP_USERNAME: process.env["SMTP_USERNAME"], - SMTP_PASSWORD: process.env["SMTP_PASSWORD"], - SMTP_NAME_FROM: process.env["SMTP_NAME_FROM"], - SMTP_EMAIL_FROM: process.env["SMTP_EMAIL_FROM"], - SMTP_EMAIL_FROM_HELLO: process.env["SMTP_EMAIL_FROM_HELLO"], + SMTP_HOST: process.env['SMTP_HOST'], + SMTP_PORT: parseInt(process.env['SMTP_PORT']), + SMTP_USERNAME: process.env['SMTP_USERNAME'], + SMTP_PASSWORD: process.env['SMTP_PASSWORD'], + SMTP_NAME_FROM: process.env['SMTP_NAME_FROM'], + SMTP_EMAIL_FROM: process.env['SMTP_EMAIL_FROM'], + SMTP_EMAIL_FROM_HELLO: process.env['SMTP_EMAIL_FROM_HELLO'], /** * Mysql test URL. */ - MYSQL_HOST_TEST: process.env["MYSQL_HOST_TEST"], - MYSQL_PORT_TEST: parseInt(process.env["MYSQL_PORT_TEST"]) || 3306, - MYSQL_DB_TEST: process.env["MYSQL_DB_TEST"], - MYSQL_USER_TEST: process.env["MYSQL_USER_TEST"], - MYSQL_PASSWORD_TEST: process.env["MYSQL_PASSWORD_TEST"], - MYSQL_POOL_TEST: parseInt(process.env["MYSQL_POOL_TEST"]), + MYSQL_HOST_TEST: process.env['MYSQL_HOST_TEST'], + MYSQL_PORT_TEST: parseInt(process.env['MYSQL_PORT_TEST']) || 3306, + MYSQL_DB_TEST: process.env['MYSQL_DB_TEST'], + MYSQL_USER_TEST: process.env['MYSQL_USER_TEST'], + MYSQL_PASSWORD_TEST: process.env['MYSQL_PASSWORD_TEST'], + MYSQL_POOL_TEST: parseInt(process.env['MYSQL_POOL_TEST']), /** * Apillon */ - APILLON_KEY: process.env["APILLON_KEY"], - APILLON_SECRET: process.env["APILLON_SECRET"], - COLLECTION_UUID: process.env["COLLECTION_UUID"], - MAX_SUPPLY: parseInt(process.env["MAX_SUPPLY"]) || 0, + APILLON_KEY: process.env['APILLON_KEY'], + APILLON_SECRET: process.env['APILLON_SECRET'], + COLLECTION_UUID: process.env['COLLECTION_UUID'], + MAX_SUPPLY: parseInt(process.env['MAX_SUPPLY']) || 0, /** * Captcha */ - CAPTCHA_SECRET: process.env["CAPTCHA_SECRET"], + CAPTCHA_SECRET: process.env['CAPTCHA_SECRET'], /** * Number of hours user have to claim NFT, before they are removed from line and become un eligible to claim */ - CLAIM_EXPIRES_IN: parseInt(process.env["CLAIM_EXPIRES_IN"]) || 72, + CLAIM_EXPIRES_IN: parseInt(process.env['CLAIM_EXPIRES_IN']) || 72, }; diff --git a/docker-compose.proxy.yml b/docker-compose.proxy.yml deleted file mode 100644 index aea42f5..0000000 --- a/docker-compose.proxy.yml +++ /dev/null @@ -1,38 +0,0 @@ -services: - proxy: - image: nginxproxy/nginx-proxy:latest - container_name: nginx-proxy - restart: unless-stopped - ports: - - "80:80" - - "443:443" - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - /app/certs:/etc/nginx/certs:ro - # - /etc/nginx/vhost.d - # - /usr/share/nginx/html - - vhost:/etc/nginx/vhost.d - - html:/usr/share/nginx/html - environment: - - HTTPS_METHOD=noredirect - networks: - - web - - proxy-ssl: - image: nginxproxy/acme-companion - container_name: acme-companion - restart: unless-stopped - volumes_from: - - proxy - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /app/certs:/etc/nginx/certs:rw - - acme:/etc/acme.sh - environment: - - DEFAULT_EMAIL=itkalmia@kalmia.si - networks: - - web - -networks: - web: - name: web