From ce2255b6b759edb2defb2d6ec8d6cddb2999581a Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Sun, 26 Jun 2022 19:30:46 +0300 Subject: [PATCH] Simplify dev docker setup --- .env.example | 25 +++++++------ backend/src/api/auth.ts | 6 ++-- backend/src/api/start.ts | 2 +- backend/src/env.ts | 14 ++++---- dashboard/src/api.ts | 2 +- dashboard/src/auth.ts | 4 +-- dashboard/src/init-vue.ts | 2 +- docker-compose-dev.sh | 2 +- docker/development/README.md | 5 ++- docker/development/devenv/Dockerfile | 4 +-- docker/development/docker-compose.yml | 35 ++++-------------- docker/development/nginx/Dockerfile | 9 ++--- docker/development/nginx/default.conf | 52 +++++++++++---------------- 13 files changed, 65 insertions(+), 97 deletions(-) diff --git a/.env.example b/.env.example index 8d8052b9..88f8f5b5 100644 --- a/.env.example +++ b/.env.example @@ -1,36 +1,39 @@ -KEY=32_character_encryption_key +# 32 character encryption key +KEY= +# Values from the Discord developer portal CLIENT_ID= CLIENT_SECRET= BOT_TOKEN= -OAUTH_CALLBACK_URL= -DASHBOARD_DOMAIN= -API_DOMAIN= +DASHBOARD_URL=https://localhost:3300 +API_URL=https://localhost:3300/api + +# When using the Docker-based development environment, this is only used internally. The API will be available at localhost:DOCKER_DEV_WEB_PORT/api. API_PORT=3000 +# Only required if relevant feature is used +#PHISHERMAN_API_KEY= + # # DOCKER (DEVELOPMENT) # -DOCKER_WEB_PORT=443 +DOCKER_DEV_WEB_PORT=3300 # The MySQL database running in the container is exposed to the host on this port, # allowing access with database tools such as DBeaver -DOCKER_MYSQL_PORT=3001 +DOCKER_DEV_MYSQL_PORT=3001 # Password for the Zeppelin database user -DOCKER_MYSQL_PASSWORD= +DOCKER_DEV_MYSQL_PASSWORD= # Password for the MySQL root user -DOCKER_MYSQL_ROOT_PASSWORD= +DOCKER_DEV_MYSQL_ROOT_PASSWORD= # The development environment container has an SSH server that you can connect to. # This is the port that server is exposed to the host on. DOCKER_DEV_SSH_PORT=3002 DOCKER_DEV_SSH_PASSWORD=password -# Only required if relevant feature is used -#PHISHERMAN_API_KEY= - # # PRODUCTION # diff --git a/backend/src/api/auth.ts b/backend/src/api/auth.ts index 09029bda..ca947d8c 100644 --- a/backend/src/api/auth.ts +++ b/backend/src/api/auth.ts @@ -88,7 +88,7 @@ export function initAuth(app: express.Express) { tokenURL: "https://discord.com/api/oauth2/token", clientID: env.CLIENT_ID, clientSecret: env.CLIENT_SECRET, - callbackURL: env.OAUTH_CALLBACK_URL, + callbackURL: `${env.API_URL}/auth/oauth-callback`, scope: ["identify"], }, async (accessToken, refreshToken, profile, cb) => { @@ -117,9 +117,9 @@ export function initAuth(app: express.Express) { passport.authenticate("oauth2", { failureRedirect: "/", session: false }), (req: Request, res: Response) => { if (req.user && req.user.apiKey) { - res.redirect(`https://${env.DASHBOARD_DOMAIN}/login-callback/?apiKey=${req.user.apiKey}`); + res.redirect(`${env.DASHBOARD_URL}/login-callback/?apiKey=${req.user.apiKey}`); } else { - res.redirect(`https://${env.DASHBOARD_DOMAIN}/login-callback/?error=noAccess`); + res.redirect(`${env.DASHBOARD_URL}/login-callback/?error=noAccess`); } }, ); diff --git a/backend/src/api/start.ts b/backend/src/api/start.ts index 27d982ab..59a20da6 100644 --- a/backend/src/api/start.ts +++ b/backend/src/api/start.ts @@ -14,7 +14,7 @@ const app = express(); app.use( cors({ - origin: `https://${env.DASHBOARD_DOMAIN}`, + origin: env.DASHBOARD_URL, }), ); app.use( diff --git a/backend/src/env.ts b/backend/src/env.ts index b0eb3d9e..e786dd3c 100644 --- a/backend/src/env.ts +++ b/backend/src/env.ts @@ -11,17 +11,15 @@ const envType = z.object({ CLIENT_SECRET: z.string().length(32), BOT_TOKEN: z.string().min(50), - OAUTH_CALLBACK_URL: z.string().url(), - DASHBOARD_DOMAIN: z.string(), - API_DOMAIN: z.string(), + DASHBOARD_URL: z.string().url(), + API_URL: z.string().url(), + API_PORT: z.preprocess((v) => Number(v), z.number().min(1).max(65535)).default(3000), STAFF: z.preprocess((v) => String(v).split(","), z.array(z.string())).optional(), PHISHERMAN_API_KEY: z.string().optional(), - API_PORT: z.preprocess((v) => Number(v), z.number().min(1).max(65535)), - - DOCKER_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development + DOCKER_DEV_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development DB_HOST: z.string().optional().default("mysql"), DB_PORT: z @@ -42,6 +40,6 @@ if (fs.existsSync(envPath)) { export const env = envType.parse(toValidate); -if (env.DOCKER_MYSQL_PASSWORD && !env.DB_PASSWORD) { - env.DB_PASSWORD = env.DOCKER_MYSQL_PASSWORD; +if (env.DOCKER_DEV_MYSQL_PASSWORD && !env.DB_PASSWORD) { + env.DB_PASSWORD = env.DOCKER_DEV_MYSQL_PASSWORD; } diff --git a/dashboard/src/api.ts b/dashboard/src/api.ts index 6b75d1f8..f6cfd5e5 100644 --- a/dashboard/src/api.ts +++ b/dashboard/src/api.ts @@ -1,5 +1,5 @@ import { RootStore } from "./store"; -const apiUrl = `https://${process.env.API_DOMAIN}`; +const apiUrl = process.env.API_URL; type QueryParamObject = { [key: string]: string | null }; diff --git a/dashboard/src/auth.ts b/dashboard/src/auth.ts index e8c085d7..bb5c1b9e 100644 --- a/dashboard/src/auth.ts +++ b/dashboard/src/auth.ts @@ -11,7 +11,7 @@ const isAuthenticated = async () => { export const authGuard: NavigationGuard = async (to, from, next) => { if (await isAuthenticated()) return next(); - window.location.href = `https://${process.env.API_DOMAIN}/auth/login`; + window.location.href = `${process.env.API_URL}/auth/login`; }; export const loginCallbackGuard: NavigationGuard = async (to, from, next) => { @@ -25,5 +25,5 @@ export const loginCallbackGuard: NavigationGuard = async (to, from, next) => { export const authRedirectGuard: NavigationGuard = async (to, form, next) => { if (await isAuthenticated()) return next("/dashboard"); - window.location.href = `https://${process.env.API_DOMAIN}/auth/login`; + window.location.href = `${process.env.API_URL}/auth/login`; }; diff --git a/dashboard/src/init-vue.ts b/dashboard/src/init-vue.ts index 25b30969..614b5609 100644 --- a/dashboard/src/init-vue.ts +++ b/dashboard/src/init-vue.ts @@ -20,7 +20,7 @@ Vue.mixin({ return { get env() { return Object.freeze({ - API_URL: `https://${process.env.API_DOMAIN}`, + API_URL: process.env.API_URL, }); }, }; diff --git a/docker-compose-dev.sh b/docker-compose-dev.sh index 14af4e94..cd039f74 100755 --- a/docker-compose-dev.sh +++ b/docker-compose-dev.sh @@ -1,3 +1,3 @@ #!/bin/bash -DOCKER_UID="$(id -u)" DOCKER_GID="$(id -g)" docker-compose --env-file ./.env -f ./docker/development/docker-compose.yml "$@" +DOCKER_UID="$(id -u)" DOCKER_STAY_RUNNING=1 docker-compose --env-file ./.env -f ./docker/development/docker-compose.yml "$@" diff --git a/docker/development/README.md b/docker/development/README.md index 2605b108..ebbebf94 100644 --- a/docker/development/README.md +++ b/docker/development/README.md @@ -7,7 +7,7 @@ ## Connecting with VSCode 1. Install the `Remote - SSH` plugin 2. Run `Remote-SSH: Connect to Host...` - * As the address, use `ubuntu@127.0.0.1:3002` where `3002` matches `DOCKER_DEV_SSH_PORT` in `.env` + * As the address, use `ubuntu@127.0.0.1:3002` (where `3002` matches `DOCKER_DEV_SSH_PORT` in `.env`) * Use the password specified in `.env` as `DOCKER_DEV_SSH_PASSWORD` 3. Once connected, click `Open folder...` and select `/home/ubuntu/zeppelin` @@ -25,3 +25,6 @@ These commands are run inside the dev container. You should be able to just open 1. `cd ~/zeppelin/dashboard` 2. `npm ci` 3. `npm run watch-build` + +## Opening the dashboard +Browse to https://localhost:3300 to view the dashboard diff --git a/docker/development/devenv/Dockerfile b/docker/development/devenv/Dockerfile index ac278942..30963fee 100644 --- a/docker/development/devenv/Dockerfile +++ b/docker/development/devenv/Dockerfile @@ -1,6 +1,6 @@ FROM ubuntu:20.04 -ARG DOCKER_UID +ARG DOCKER_UID=1000 ARG DOCKER_DEV_SSH_PASSWORD ENV DEBIAN_FRONTEND=noninteractive @@ -13,7 +13,7 @@ RUN apt-get install -y sudo git curl # Set up SSH access RUN apt-get install -y openssh-server iptables RUN mkdir /var/run/sshd -RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u "${DOCKER_UID}" ubuntu +RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u $DOCKER_UID ubuntu RUN echo "ubuntu:${DOCKER_DEV_SSH_PASSWORD}" | chpasswd # Set up proper permissions for volumes diff --git a/docker/development/docker-compose.yml b/docker/development/docker-compose.yml index 10c3caf1..7fcdd28a 100644 --- a/docker/development/docker-compose.yml +++ b/docker/development/docker-compose.yml @@ -9,54 +9,33 @@ services: build: context: ./nginx args: - API_DOMAIN: ${API_DOMAIN:?Missing API_DOMAIN} + DOCKER_DEV_WEB_PORT: ${DOCKER_DEV_WEB_PORT:?Missing DOCKER_DEV_WEB_PORT} API_PORT: ${API_PORT:?Missing API_PORT} - DASHBOARD_DOMAIN: ${DASHBOARD_DOMAIN:?Missing DASHBOARD_DOMAIN} ports: - - ${DOCKER_WEB_PORT:?Missing DOCKER_WEB_PORT}:443 + - "${DOCKER_DEV_WEB_PORT:?Missing DOCKER_DEV_WEB_PORT}:443" volumes: - ../../:/zeppelin mysql: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD: ${DOCKER_MYSQL_ROOT_PASSWORD?:Missing DOCKER_MYSQL_ROOT_PASSWORD} + MYSQL_ROOT_PASSWORD: ${DOCKER_DEV_MYSQL_ROOT_PASSWORD?:Missing DOCKER_DEV_MYSQL_ROOT_PASSWORD} MYSQL_DATABASE: zeppelin MYSQL_USER: zeppelin - MYSQL_PASSWORD: ${DOCKER_MYSQL_PASSWORD?:Missing DOCKER_MYSQL_PASSWORD} + MYSQL_PASSWORD: ${DOCKER_DEV_MYSQL_PASSWORD?:Missing DOCKER_DEV_MYSQL_PASSWORD} ports: - - ${DOCKER_MYSQL_PORT:?Missing DOCKER_MYSQL_PORT}:3306 + - ${DOCKER_DEV_MYSQL_PORT:?Missing DOCKER_DEV_MYSQL_PORT}:3306 volumes: - mysql-data:/var/lib/mysql command: --authentication-policy=mysql_native_password -# -# backend: -# image: node:16 -# user: "${UID:?Missing UID}:${GID:?Missing GID}" -# working_dir: /zeppelin/backend -# restart: always -# depends_on: -# - mysql -# volumes: -# - ./:/zeppelin -# command: sh -c "npm run migrate-dev && npm run watch" -# -# dashboard: -# image: node:16 -# user: "${UID:?Missing UID}:${GID:?Missing GID}" -# working_dir: /zeppelin/dashboard -# restart: always -# volumes: -# - ./:/zeppelin -# command: sh -c "npm run watch-build" devenv: build: context: ./devenv args: - DOCKER_UID: ${DOCKER_UID:?Missing DOCKER_UID} - DOCKER_GID: ${DOCKER_GID:?Missing DOCKER_GID} DOCKER_DEV_SSH_PASSWORD: ${DOCKER_DEV_SSH_PASSWORD:?Missing DOCKER_DEV_SSH_PASSWORD} + DOCKER_UID: ${DOCKER_UID:?Missing DOCKER_UID} + DOCKER_STAY_RUNNING: ${DOCKER_STAY_RUNNING} ports: - "${DOCKER_DEV_SSH_PORT:?Missing DOCKER_DEV_SSH_PORT}:22" volumes: diff --git a/docker/development/nginx/Dockerfile b/docker/development/nginx/Dockerfile index 2f63ba2f..6df4e140 100644 --- a/docker/development/nginx/Dockerfile +++ b/docker/development/nginx/Dockerfile @@ -1,14 +1,11 @@ FROM nginx -ARG API_DOMAIN -ARG DASHBOARD_DOMAIN ARG API_PORT +ARG DOCKER_DEV_API_PORT +ARG DOCKER_DEV_DASHBOARD_PORT RUN apt-get update && apt-get install -y openssl -RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/api-cert.key -out /etc/ssl/certs/api-cert.pem -days 3650 -subj '/CN=*.${API_DOMAIN}' -nodes -RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/dashboard-cert.key -out /etc/ssl/certs/dashboard-cert.pem -days 3650 -subj '/CN=*.${DASHBOARD_DOMAIN}' -nodes +RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/localhost-cert.key -out /etc/ssl/certs/localhost-cert.pem -days 3650 -subj '/CN=localhost' -nodes COPY ./default.conf /etc/nginx/conf.d/default.conf -RUN sed -ir "s/_API_DOMAIN_/$(echo ${API_DOMAIN} | sed 's/\./\\./g')/g" /etc/nginx/conf.d/default.conf -RUN sed -ir "s/_DASHBOARD_DOMAIN_/$(echo ${DASHBOARD_DOMAIN} | sed 's/\./\\./g')/g" /etc/nginx/conf.d/default.conf RUN sed -ir "s/_API_PORT_/${API_PORT}/g" /etc/nginx/conf.d/default.conf diff --git a/docker/development/nginx/default.conf b/docker/development/nginx/default.conf index 3ff41fe0..9dc3db69 100644 --- a/docker/development/nginx/default.conf +++ b/docker/development/nginx/default.conf @@ -1,36 +1,7 @@ server { listen 443 ssl http2; listen [::]:443 ssl http2; - server_name _API_DOMAIN_; - - - location / { - # Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable - set $backend_upstream "http://devenv:_API_PORT_"; - # Using a variable in proxy_pass also requires resolver to be set. - # This is the address of the internal docker compose DNS server. - resolver 127.0.0.11; - - proxy_pass $backend_upstream; - - client_max_body_size 200M; - } - - ssl_certificate /etc/ssl/certs/api-cert.pem; - ssl_certificate_key /etc/ssl/private/api-cert.key; - - ssl_session_timeout 1d; - ssl_session_cache shared:MozSSL:10m; - ssl_session_tickets off; - - ssl_protocols TLSv1.3; - ssl_prefer_server_ciphers off; -} - -server { - listen 443 ssl http2; - listen [::]:443 ssl http2; - server_name _DASHBOARD_DOMAIN_; + server_name localhost; root /zeppelin/dashboard/dist; @@ -39,8 +10,25 @@ server { try_files $uri $uri/ /index.html; } - ssl_certificate /etc/ssl/certs/dashboard-cert.pem; - ssl_certificate_key /etc/ssl/private/dashboard-cert.key; + # Using a variable here stops nginx from crashing if the dev container is restarted or becomes otherwise unavailable + set $backend_upstream "http://devenv:_API_PORT_"; + + location /api { + # Remove /api/ from the beginning when passing the path to the API process + rewrite /api(/.*)$ $1 break; + + # Using a variable in proxy_pass also requires resolver to be set. + # This is the address of the internal docker compose DNS server. + resolver 127.0.0.11; + + proxy_pass $backend_upstream$uri$is_args$args; + proxy_redirect off; + + client_max_body_size 200M; + } + + ssl_certificate /etc/ssl/certs/localhost-cert.pem; + ssl_certificate_key /etc/ssl/private/localhost-cert.key; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m;