From cc8145d5765e612af8a488d26bfc28e682df024c Mon Sep 17 00:00:00 2001 From: azurejelly <178000437+azurejelly@users.noreply.github.com> Date: Sat, 26 Apr 2025 14:57:04 -0400 Subject: [PATCH] docs(docker): add instructions on how to serve over HTTPS * Added a script to generate a self-signed certificate * Added *.pem, *.key and *.crt files to .gitignore and .dockerignore * Stopped setting PUB_PLAUSIBLE_URL to https://plausible.example.com on Docker Compose builds by default * Modified "Building on Production" to mention that HTTPS is required on most cases * Added a base HTTPS config for nginx --- .dockerignore | 9 +++- .gitignore | 5 +++ Dockerfile | 2 +- README.md | 70 +++++++++++++++++++++++++++++--- docker-compose.yml | 12 ++---- nginx/default-ssl.conf | 30 ++++++++++++++ nginx.conf => nginx/default.conf | 0 nginx/setup-self-signed.sh | 21 ++++++++++ 8 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 nginx/default-ssl.conf rename nginx.conf => nginx/default.conf (100%) create mode 100644 nginx/setup-self-signed.sh diff --git a/.dockerignore b/.dockerignore index fd73510..3d34d9d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,6 +6,7 @@ dist/ .output/ .vercel/ .vscode/ +ssl/ LICENSE README.md @@ -18,4 +19,10 @@ docker-compose.yml .env .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +*.crt +*.key +*.pem + +setup-self-signed.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore index e8d9546..d7d8d3e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,10 @@ node_modules +# SSL +*.crt +*.key +*.pem + # Output .output .vercel diff --git a/Dockerfile b/Dockerfile index d15dfdb..24300e6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,6 +22,6 @@ RUN bun run build FROM nginx:stable-alpine -COPY ./nginx.conf /etc/nginx/conf.d/default.conf +COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf COPY --from=builder /app/build /usr/share/nginx/html diff --git a/README.md b/README.md index 9572037..3313a82 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,11 @@ Make sure you have the following installed: ### Installation ```sh # Clone the repository -git clone https://github.com/VERT-sh/vert.git -cd vert +$ git clone https://github.com/VERT-sh/vert.git +$ cd vert + # Install dependencies -bun i +$ bun i ``` ### Running Locally @@ -54,7 +55,7 @@ To build the project for production, run `bun run build` This will build the site to the `build` folder. You should then use a web server like [nginx](https://nginx.org) to serve the files inside that folder. -If using nginx, you can use the [nginx.conf](./nginx.conf) file as a starting point. Make sure you keep [cross-origin isolation](https://web.dev/articles/cross-origin-isolation-guide) enabled. +If using nginx, you can use the [default-ssl.conf](./nginx/default-ssl.conf) file (or [default.conf](./nginx/default.conf) if you don't need to serve the site over HTTPS) as a starting point. Make sure you keep [cross-origin isolation](https://web.dev/articles/cross-origin-isolation-guide) enabled, which **requires** HTTPS on most cases. ### With Docker @@ -81,7 +82,9 @@ This will do the following: - Continuously restart the container until manually stopped - Map `3000/tcp` (host) to `80/tcp` (container) -We also have a [`docker-compose.yml`](./docker-compose.yml) file available. Use `docker compose up` if you want to start the stack, or `docker compose down` to bring it down. You can pass `--build` to `docker compose up` to rebuild the Docker image (useful if you've changed any of the environment variables) as well as `-d` to start it in detached mode. You can read more about Docker Compose in general [here](https://docs.docker.com/compose/intro/compose-application-model/). +We also have a [`docker-compose.yml`](./docker-compose.yml) file available. Use `docker compose up` if you want to start the stack, or `docker compose down` to bring it down. You can pass `--build` to `docker compose up` to rebuild the Docker image (useful if you've changed any of the environment variables) as well as `-d` to start it in detached mode. Feel free to read more about Docker Compose in general [here](https://docs.docker.com/compose/intro/compose-application-model/). + +#### Pulling instead of building While there's an image you can pull instead of cloning the repo and building the image yourself, you will not be able to update any of the environment variables (e.g. `PUB_PLAUSIBLE_URL`) as they're baked directly into the image and not obtained during runtime. If you're okay with this, you can simply run this command instead: ```shell @@ -92,6 +95,63 @@ $ docker run -d \ ghcr.io/vert-sh/vert:latest ``` +#### Serving the site over HTTPS + +If you're running the container in your local machine and accessing it from `localhost`, this isn't really required. However, any other origin will cause cross-origin +isolation to be disabled unless you serve the site over HTTPS, which in turn will cause image conversions to fail. There are a few options to get around this: +- Using something like Tailscale's [HTTPS feature](https://tailscale.com/kb/1153/enabling-https) +- Using a self-signed certificate (not recommended for public instances and your browser will likely yell at you) +- Using Let's Encrypt or Cloudflare as a TLS proxy with your own domain + +If you want to use a self-signed certificate, there's a little [script](./nginx/setup-self-signed.sh) you can run in order to generate one. Make sure you have `openssl` installed, then run: +```shell +$ cd ./nginx/ +$ ./setup-self-signed.sh +``` + +This will generate the following files inside `./ssl/`: +```shell +$ ls ./ssl +self-signed.crt self-signed.key +``` + +If you don't want to use a self-signed certificate, simply copy your own key and certificate files into `./nginx/ssl/` instead. Make sure to then modify the default SSL config under [./nginx/default-ssl.conf](./nginx/default-ssl.conf) to match the file names: +```conf +server { + ... + + ssl_certificate /etc/ssl/vert/self-signed.crt; + ssl_certificate_key /etc/ssl/vert/self-signed.key; + + ... +} +``` + +Finally, update your Docker Compose configuration: +```yaml +services: + vert: + # ... + ports: + # map to port 443 instead of 80 + - "${PORT:-3000}:443" + volumes: + # map the ssl folder with our certificates to /etc/ssl/vert in read-only mode + - "./nginx/ssl:/etc/ssl/vert:ro" + + # overwrite the default HTTP configuration of the container + - "./nginx/default-ssl.conf:/etc/nginx/conf.d/default.conf" +``` + +For `docker run`, use: +```shell +$ docker run ... \ + -p 3000:443 \ + -v "./nginx/ssl:/etc/ssl/vert" \ + -v "./nginx/default-ssl.conf:/etc/nginx/conf.d/default.conf" \ + ... +``` + ## License This project is licensed under the AGPL-3.0 License, please see the [LICENSE](LICENSE) file for details. diff --git a/docker-compose.yml b/docker-compose.yml index 13afdea..be41cf2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,20 +1,14 @@ services: vert: container_name: vert - image: vert-sh/vert:latest - environment: - - PUB_HOSTNAME=${PUB_HOSTNAME:-vert.sh} - - PUB_PLAUSIBLE_URL=${PUB_PLAUSIBLE_URL:-https://plausible.example.com} - - PUB_ENV=${PUB_ENV:-production} - - PORT=${PORT:-3000} - - PUB_VERTD_URL=${PUB_VERTD_URL:-https://vertd.vert.sh} + image: gchr.io/vert-sh/vert:latest + restart: unless-stopped build: context: . args: PUB_HOSTNAME: ${PUB_HOSTNAME:-vert.sh} - PUB_PLAUSIBLE_URL: ${PUB_PLAUSIBLE_URL:-https://plausible.example.com} + PUB_PLAUSIBLE_URL: ${PUB_PLAUSIBLE_URL:-} PUB_ENV: ${PUB_ENV:-production} PUB_VERTD_URL: ${PUB_VERTD_URL:-https://vertd.vert.sh} - restart: unless-stopped ports: - ${PORT:-3000}:80 diff --git a/nginx/default-ssl.conf b/nginx/default-ssl.conf new file mode 100644 index 0000000..aeca1e0 --- /dev/null +++ b/nginx/default-ssl.conf @@ -0,0 +1,30 @@ +server { + listen 80; + server_name vert; + + # Redirect all HTTP traffic to HTTPS + return 301 https://$host$request_uri; +} + +server { + listen 443 ssl; + server_name vert; + + ssl_certificate /etc/ssl/vert/self-signed.crt; + ssl_certificate_key /etc/ssl/vert/self-signed.key; + + root /usr/share/nginx/html; + index index.html; + + client_max_body_size 10M; + + location / { + try_files $uri $uri/ /index.html; + } + + error_page 404 /index.html; + + add_header Cross-Origin-Embedder-Policy "require-corp"; + add_header Cross-Origin-Opener-Policy "same-origin"; + add_header Cross-Origin-Resource-Policy "cross-origin"; +} \ No newline at end of file diff --git a/nginx.conf b/nginx/default.conf similarity index 100% rename from nginx.conf rename to nginx/default.conf diff --git a/nginx/setup-self-signed.sh b/nginx/setup-self-signed.sh new file mode 100644 index 0000000..6003717 --- /dev/null +++ b/nginx/setup-self-signed.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +OUT_DIR="./ssl" +KEY_OUT="$OUT_DIR/self-signed.key" +CRT_OUT="$OUT_DIR/self-signed.crt" + +if ! which openssl > /dev/null 2>&1; then + echo "Could not find openssl in your PATH. Exiting." + exit 1 +fi + +mkdir -p "$OUT_DIR" + +openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout "$KEY_OUT" \ + -out "$CRT_OUT" + +chmod 600 "$KEY_OUT" \ + "$CRT_OUT" + +echo "Finished generating self-signed certificate." \ No newline at end of file