diff --git a/README.md b/README.md index 0dc7466..f234b4e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ This is a template for building a webapp using the following tech stack: - [Vue Router](https://router.vuejs.org/guide/) - frontend router for Vue - [TailwindCSS](https://tailwindcss.com/docs/configuration) - CSS framework - [Axios](https://axios-http.com/docs/intro) - library for making API requests from the frontend - - [Parcel](/https://parceljs.org/docs/) - bundler used for frontend module resolution and asset optimization + - [Parcel](https://parceljs.org/docs/) - bundler used for frontend module resolution and asset optimization - [npm](https://docs.npmjs.com/cli/v7/configuring-npm/package-json) - node package manager for JavaScript packages - **Backend**: - [FastAPI](https://fastapi.tiangolo.com/) - Python-framework for backend APIs @@ -35,6 +35,11 @@ docker-compose -f production.docker-compose.yml up -d --force-recreate --build - This starts two containers, called `backend` and `frontend`, and exposes the deployed web application on port `8000`. You can open a browser and navigate to [http:localhost:8000/](http:localhost:8000/) to try it out. +To stop the containers, run the following as root: +```sh +docker-compose -f production.docker-compose.yml down +``` + ### Production Frontend Container The `frontend` production Docker image is built according to `production.frontend.Dockerfile`. @@ -74,7 +79,25 @@ This prevents repetition when writing your endpoint code and allows you to acces ## Development Configuration -> **TODO:** implement +The development configuration can be deployed using the `development.docker-compose.yml` file, by running (as root): + +```sh +docker-compose -f development.docker-compose.yml up -d --build --force-recreate --remove-orphans +``` + +This starts three containers, called `backend`, `parcel` and `frontend`, and exposes the deployed web application on port `8000`. +You can open a browser and navigate to [http:localhost:8000/](http:localhost:8000/) to try it out. + +To stop the containers, run the following as root: +```sh +docker-compose -f development.docker-compose.yml down +``` + +The development containers work very similarly to the production containers, with the exception that hot reloading of configuration +and sourcecode files is enabled. + +This means that when you modify the frontend or backend sourcecode while the development container is running, the changes are detected +and applied automatically, restarting the containers is usually not required. # Customization @@ -132,5 +155,6 @@ Depending on the configuration you wish to customize, please refer to each compo # TODOs / Roadmap -1. Add a development Docker configuration +1. Add sqlite/postgres containers 2. Minify CSS in prod +3. Add testing tools diff --git a/development.Caddyfile b/development.Caddyfile new file mode 100644 index 0000000..7baee06 --- /dev/null +++ b/development.Caddyfile @@ -0,0 +1,38 @@ +:3000 { + + encode zstd gzip + + @staticfiles { + method GET + path /static/* + } + handle @staticfiles { + file_server { + root /app/public/ + } + } + + handle_path /api/* { + reverse_proxy * backend:3001 + } + + @robots { + method GET + path /robots.txt + path /sitemap.xml + } + handle @robots { + file_server { + root /app/robots/ + } + } + + handle * { + reverse_proxy * parcel:1234 + } + + log { + output stderr + format console + } +} diff --git a/development.backend.Dockerfile b/development.backend.Dockerfile new file mode 100644 index 0000000..802c5c4 --- /dev/null +++ b/development.backend.Dockerfile @@ -0,0 +1,25 @@ +# syntax=docker/dockerfile:1 + +FROM python:3 + +# Create non-root user +ARG CUSTOM_UID +ARG CUSTOM_GID +ENV CUSTOM_USERNAME=backend +ENV CUSTOM_GROUPNAME=backend +RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \ + useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \ + mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app + +# Copy source files +WORKDIR /app +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} requirements.txt /app/ +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} backend /app/backend/ + +# Install dependencies +RUN pip install -r requirements.txt + +# Run ASGI server +EXPOSE 3001/tcp +USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} +ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001", "--access-log", "--use-colors", "--log-level", "debug", "--reload"] diff --git a/development.docker-compose.yml b/development.docker-compose.yml new file mode 100644 index 0000000..5757627 --- /dev/null +++ b/development.docker-compose.yml @@ -0,0 +1,54 @@ +--- + +version: "3" + +services: + frontend: + container_name: frontend + restart: unless-stopped + build: + context: . + dockerfile: ./development.frontend.Dockerfile + args: + CUSTOM_UID: 1000 + CUSTOM_GID: 1000 + environment: + TZ: Europe/Berlin + ports: + - "8000:3000" + volumes: + - ./public/:/app/public/:ro + - ./robots/:/app/robots/:ro + - ./Caddyfile:/app/Caddyfile:ro + parcel: + container_name: parcel + restart: unless-stopped + build: + context: . + dockerfile: ./development.parcel.Dockerfile + args: + CUSTOM_UID: 1000 + CUSTOM_GID: 1000 + volumes: + - ./frontend/:/app/frontend/:ro + - ./postcss.config.js:/app/postcss.config.js:ro + - ./.postcssrc:/app/.postcssrc:ro + - ./tailwind.config.js:/app/tailwind.config.js:ro + expose: + - "1234" + backend: + container_name: backend + restart: unless-stopped + build: + context: . + dockerfile: ./development.backend.Dockerfile + args: + CUSTOM_UID: 1000 + CUSTOM_GID: 1000 + expose: + - "3001" + volumes: + - ./backend/:/app/backend/:ro + - ./requirements.txt:/app/requirements.txt:ro + +... diff --git a/development.frontend.Dockerfile b/development.frontend.Dockerfile new file mode 100644 index 0000000..05e2ccd --- /dev/null +++ b/development.frontend.Dockerfile @@ -0,0 +1,33 @@ +# syntax=docker/dockerfile:1 + +FROM debian:latest + +# Install Caddy +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update && apt install -y curl && \ + apt install -y debian-keyring debian-archive-keyring apt-transport-https && \ + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \ + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list && \ + apt update && apt install -y caddy && \ + rm -rf /var/lib/apt/lists/* + +# Create non-root user +ARG CUSTOM_UID +ARG CUSTOM_GID +ENV CUSTOM_USERNAME=webserver +ENV CUSTOM_GROUPNAME=webserver +RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \ + useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \ + mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app + +# Copy source files +WORKDIR /app +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} development.Caddyfile /app/ +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} public /app/public/ +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/ + +# Install dependencies +USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} + +# Run Caddy in development mode +ENTRYPOINT ["caddy", "run", "--config", "/app/development.Caddyfile", "--adapter", "caddyfile", "--watch"] diff --git a/development.parcel.Dockerfile b/development.parcel.Dockerfile new file mode 100644 index 0000000..f5ddba1 --- /dev/null +++ b/development.parcel.Dockerfile @@ -0,0 +1,34 @@ +# syntax=docker/dockerfile:1 + +FROM debian:latest + +# Install packages +ENV DEBIAN_FRONTEND=noninteractive +RUN apt update && apt install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_19.x | bash - && apt-get install -y nodejs && \ + apt install -y debian-keyring debian-archive-keyring apt-transport-https && \ + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \ + curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list && \ + apt update && apt install -y caddy && \ + rm -rf /var/lib/apt/lists/* + +# Create non-root user +ARG CUSTOM_UID +ARG CUSTOM_GID +ENV CUSTOM_USERNAME=webserver +ENV CUSTOM_GROUPNAME=webserver +RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \ + useradd --uid ${CUSTOM_UID:-1000} --gid ${CUSTOM_GID:-1000} --create-home --shell /bin/bash ${CUSTOM_USERNAME} && \ + mkdir /app && chown ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} /app + +# Copy source files +WORKDIR /app +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js /app/ +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} frontend /app/frontend/ + +# Install dependencies +USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} +RUN npm install + +# Run the parcel file watcher +ENTRYPOINT ["npx", "parcel", "frontend/src/html/index.html"] diff --git a/frontend/src/js/components/ExampleComponent.vue b/frontend/src/js/components/ExampleComponent.vue index 93195b0..5e44d6c 100644 --- a/frontend/src/js/components/ExampleComponent.vue +++ b/frontend/src/js/components/ExampleComponent.vue @@ -1,6 +1,26 @@ + + - Hello World! - If you're seeing this text, Vue.js is working correctly! + Hello! + If you're seeing this text, Vue.js is working correctly. + The backend API responded with: {{ hello }} diff --git a/Caddyfile b/production.Caddyfile similarity index 100% rename from Caddyfile rename to production.Caddyfile diff --git a/production.backend.Dockerfile b/production.backend.Dockerfile index 99da56e..b5a6a21 100644 --- a/production.backend.Dockerfile +++ b/production.backend.Dockerfile @@ -22,4 +22,4 @@ RUN pip install -r requirements.txt # Run ASGI server EXPOSE 3001/tcp USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} -ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001"] +ENTRYPOINT ["uvicorn", "backend.main:app", "--root-path", "/api", "--host", "0.0.0.0", "--port", "3001", "--access-log"] diff --git a/production.frontend.Dockerfile b/production.frontend.Dockerfile index 1ff2118..c97520b 100644 --- a/production.frontend.Dockerfile +++ b/production.frontend.Dockerfile @@ -23,7 +23,7 @@ RUN groupadd --gid ${CUSTOM_GID:-1000} ${CUSTOM_GROUPNAME} && \ # Copy source files WORKDIR /app -COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js Caddyfile /app/ +COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} package.json package-lock.json .postcssrc postcss.config.js tailwind.config.js production.Caddyfile /app/ COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} frontend /app/frontend/ COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} public /app/public/ COPY --chown=${CUSTOM_USERNAME}:${CUSTOM_GROUPNAME} robots /app/robots/ @@ -33,4 +33,4 @@ USER ${CUSTOM_UID:-1000}:${CUSTOM_GID:-1000} RUN npm install RUN npx parcel build frontend/src/html/index.html -ENTRYPOINT ["caddy", "run", "--config", "/app/Caddyfile"] +ENTRYPOINT ["caddy", "run", "--config", "/app/production.Caddyfile"]
If you're seeing this text, Vue.js is working correctly!
If you're seeing this text, Vue.js is working correctly.
The backend API responded with: {{ hello }}