From c6824094c316eb6b88b6f4bebfa9fe928edbda68 Mon Sep 17 00:00:00 2001 From: Luck Date: Wed, 27 Oct 2021 23:37:42 +0100 Subject: [PATCH] Docker --- .github/workflows/build.yml | 49 ++++++++++++++++++++++++++++++++ Dockerfile | 18 ++++++++++++ README.md | 19 ++++++++++--- docker-compose.yml | 26 +++++++++++++++++ docker/nginx.conf | 18 ++++++++++++ docker/reverseproxy-nginx.conf | 29 +++++++++++++++++++ src/App.js | 3 +- src/components/EditorControls.js | 3 +- src/util/constants.js | 4 +++ 9 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100644 docker/nginx.conf create mode 100644 docker/reverseproxy-nginx.conf create mode 100644 src/util/constants.js diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..760659f --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,49 @@ +name: Build Docker Image + +on: + push: + branches: + - 'master' + tags: + - 'v*' + pull_request: + branches: + - 'master' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Log in to the Container registry + uses: docker/login-action@v1 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v3 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + flavor: | + latest=${{ github.ref == 'refs/heads/master' }} + + - name: Build and push Docker image + uses: docker/build-push-action@v2 + with: + context: . + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3f5ecf9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,18 @@ +# Build stage +FROM node:lts as build + +ARG BYTEBIN_URL="data/" +ENV REACT_APP_BYTEBIN_URL="${BYTEBIN_URL}" + +WORKDIR /app +COPY package.json yarn.lock ./ +RUN yarn +COPY . ./ +RUN yarn build + +# Run stage +FROM nginx:alpine +COPY docker/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/build /usr/share/nginx/html +CMD ["nginx", "-g", "daemon off;"] +EXPOSE 80/tcp \ No newline at end of file diff --git a/README.md b/README.md index 4e4e091..c569fad 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@

📋 paste

-**paste is a simple web app for writing & sharing code.** It's my own take on conventional pastebin sites like *pastebin.com* or *hastebin*. +**paste is a simple web app for writing & sharing code.** It's my own take on conventional pastebin sites like _pastebin.com_ or _hastebin_. -The frontend *(this repository)* is written using the React framework. The backend data storage is handled by a separate web service called [bytebin](https://github.com/lucko/bytebin). +The frontend _(this repository)_ is written using the React framework. The backend data storage is handled by a separate web service called [bytebin](https://github.com/lucko/bytebin). The user-interface is quite simple; it supports syntax highlighting, automatic indentation, many supported languages, themes, zooming in/out, linking to specific lines or sections, and more! @@ -10,8 +10,8 @@ The user-interface is quite simple; it supports syntax highlighting, automatic i

- ## Usage + I host a public instance of paste at [paste.lucko.me](https://paste.lucko.me). Please feel free to use it to share code/configs/whatever! However please note that the (very-non-legally worded) [terms of service](https://github.com/lucko/bytebin#public-instances) for my public bytebin instance apply here too. If you come across any content which is illegal or infringes on copyright, please [get in touch](https://lucko.me/contact) and let me know so I can remove it. @@ -19,6 +19,7 @@ However please note that the (very-non-legally worded) [terms of service](https: Uploaded content is retained for 30 days then deleted. ### Host your own + If you want to host your own paste, first you need to compile it: ```bash @@ -32,9 +33,19 @@ yarn start You can then follow the [create-react-app deployment documentation](https://create-react-app.dev/docs/deployment/) for how to host the build output. I personally recommend deploying to the cloud using a service like Netlify instead of hosting on your own webserver. +If you really want to self-host (including the bytebin data storage part), I suggest using Docker: + +```bash +git clone https://github.com/lucko/paste +docker compose up -d +``` + +You should then (hopefully!) be able to access the application at `http://localhost:8080/`. + ## API + paste uses [bytebin](https://github.com/lucko/bytebin) for data storage. As a result, you can use the [bytebin API](https://github.com/lucko/bytebin#api-usage) to submit/read content programatically. -To set the language of a paste, use the `Content-Type` header with value `text/` (e.g. `Content-Type: text/yaml` for a *.yml* file). +To set the language of a paste, use the `Content-Type` header with value `text/` (e.g. `Content-Type: text/yaml` for a _.yml_ file). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b153ba5 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,26 @@ +version: '3.8' + +services: + paste: + image: paste + + bytebin: + image: ghcr.io/lucko/bytebin + volumes: + - data:/opt/bytebin/content + environment: + BYTEBIN_MISC_KEYLENGTH: 5 + + nginx: + image: nginx:alpine + command: ['nginx', '-g', 'daemon off;'] + depends_on: + - paste + - bytebin + ports: + - 8080:80 + volumes: + - ./docker/reverseproxy-nginx.conf:/etc/nginx/conf.d/default.conf:ro + +volumes: + data: {} diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 0000000..0afd2a7 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,18 @@ +# nginx config file for a SPA (single page app) +server { + listen 80 default_server; + + gzip on; + gzip_min_length 1000; + gzip_types text/plain text/xml application/javascript text/css; + + root /usr/share/nginx/html; + + location / { + try_files $uri $uri/index.html /index.html; + } + + location ~ \.(?!html) { + try_files $uri =404; + } +} \ No newline at end of file diff --git a/docker/reverseproxy-nginx.conf b/docker/reverseproxy-nginx.conf new file mode 100644 index 0000000..017ba9c --- /dev/null +++ b/docker/reverseproxy-nginx.conf @@ -0,0 +1,29 @@ +# nginx reverse proxy configuration for paste+bytebin +server { + listen 80 default_server; + + # paste app + location / { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + + proxy_pass http://paste; + } + + # disable bytebin frontend + location = /data/ { + return 404; + } + + # proxy /data endpoint to bytebin + location /data/ { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + + proxy_pass http://bytebin:8080/; + } +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index f366d50..2b041bb 100644 --- a/src/App.js +++ b/src/App.js @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'; import Editor from './components/Editor'; import parseContentType from 'content-type-parser'; import { languageIds } from './util/highlighting'; +import { bytebinUrl } from './util/constants'; function getPasteIdFromUrl() { const path = window.location.pathname; @@ -14,7 +15,7 @@ function getPasteIdFromUrl() { async function loadFromBytebin(id) { try { - const resp = await fetch('https://bytebin.lucko.me/' + id); + const resp = await fetch(bytebinUrl + id); if (resp.ok) { const content = await resp.text(); const type = parseLanguageFromContentType( diff --git a/src/components/EditorControls.js b/src/components/EditorControls.js index d92a0cc..9cda168 100644 --- a/src/components/EditorControls.js +++ b/src/components/EditorControls.js @@ -7,6 +7,7 @@ import copy from 'copy-to-clipboard'; import { MenuButton, Button } from './Menu'; import { languageIds } from '../util/highlighting'; import themes from '../style/themes'; +import { postUrl } from '../util/constants'; export default function EditorControls({ code, @@ -142,7 +143,7 @@ async function saveToBytebin(code, language) { const compressed = gzip(code); const contentType = langaugeToContentType(language); - const resp = await fetch('https://bytebin.lucko.me/post', { + const resp = await fetch(postUrl, { method: 'POST', headers: { 'Content-Type': contentType, diff --git a/src/util/constants.js b/src/util/constants.js new file mode 100644 index 0000000..87dfa5b --- /dev/null +++ b/src/util/constants.js @@ -0,0 +1,4 @@ +export const bytebinUrl = + process.env.REACT_APP_BYTEBIN_URL || 'https://bytebin.lucko.me/'; + +export const postUrl = bytebinUrl + 'post';