Docker
This commit is contained in:
49
.github/workflows/build.yml
vendored
Normal file
49
.github/workflows/build.yml
vendored
Normal file
@@ -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 }}
|
||||||
18
Dockerfile
Normal file
18
Dockerfile
Normal file
@@ -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
|
||||||
19
README.md
19
README.md
@@ -1,8 +1,8 @@
|
|||||||
<h1 align="center">📋 paste</h1>
|
<h1 align="center">📋 paste</h1>
|
||||||
|
|
||||||
**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!
|
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
|
|||||||
<img src="https://i.imgur.com/03rBijj.gif">
|
<img src="https://i.imgur.com/03rBijj.gif">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## 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!
|
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.
|
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.
|
Uploaded content is retained for 30 days then deleted.
|
||||||
|
|
||||||
### Host your own
|
### Host your own
|
||||||
|
|
||||||
If you want to host your own paste, first you need to compile it:
|
If you want to host your own paste, first you need to compile it:
|
||||||
|
|
||||||
```bash
|
```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.
|
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
|
## API
|
||||||
|
|
||||||
paste uses [bytebin](https://github.com/lucko/bytebin) for data storage.
|
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.
|
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/<language>` (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/<language>` (e.g. `Content-Type: text/yaml` for a _.yml_ file).
|
||||||
|
|||||||
26
docker-compose.yml
Normal file
26
docker-compose.yml
Normal file
@@ -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: {}
|
||||||
18
docker/nginx.conf
Normal file
18
docker/nginx.conf
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
docker/reverseproxy-nginx.conf
Normal file
29
docker/reverseproxy-nginx.conf
Normal file
@@ -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/;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import Editor from './components/Editor';
|
import Editor from './components/Editor';
|
||||||
import parseContentType from 'content-type-parser';
|
import parseContentType from 'content-type-parser';
|
||||||
import { languageIds } from './util/highlighting';
|
import { languageIds } from './util/highlighting';
|
||||||
|
import { bytebinUrl } from './util/constants';
|
||||||
|
|
||||||
function getPasteIdFromUrl() {
|
function getPasteIdFromUrl() {
|
||||||
const path = window.location.pathname;
|
const path = window.location.pathname;
|
||||||
@@ -14,7 +15,7 @@ function getPasteIdFromUrl() {
|
|||||||
|
|
||||||
async function loadFromBytebin(id) {
|
async function loadFromBytebin(id) {
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('https://bytebin.lucko.me/' + id);
|
const resp = await fetch(bytebinUrl + id);
|
||||||
if (resp.ok) {
|
if (resp.ok) {
|
||||||
const content = await resp.text();
|
const content = await resp.text();
|
||||||
const type = parseLanguageFromContentType(
|
const type = parseLanguageFromContentType(
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import copy from 'copy-to-clipboard';
|
|||||||
import { MenuButton, Button } from './Menu';
|
import { MenuButton, Button } from './Menu';
|
||||||
import { languageIds } from '../util/highlighting';
|
import { languageIds } from '../util/highlighting';
|
||||||
import themes from '../style/themes';
|
import themes from '../style/themes';
|
||||||
|
import { postUrl } from '../util/constants';
|
||||||
|
|
||||||
export default function EditorControls({
|
export default function EditorControls({
|
||||||
code,
|
code,
|
||||||
@@ -142,7 +143,7 @@ async function saveToBytebin(code, language) {
|
|||||||
const compressed = gzip(code);
|
const compressed = gzip(code);
|
||||||
const contentType = langaugeToContentType(language);
|
const contentType = langaugeToContentType(language);
|
||||||
|
|
||||||
const resp = await fetch('https://bytebin.lucko.me/post', {
|
const resp = await fetch(postUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': contentType,
|
'Content-Type': contentType,
|
||||||
|
|||||||
4
src/util/constants.js
Normal file
4
src/util/constants.js
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const bytebinUrl =
|
||||||
|
process.env.REACT_APP_BYTEBIN_URL || 'https://bytebin.lucko.me/';
|
||||||
|
|
||||||
|
export const postUrl = bytebinUrl + 'post';
|
||||||
Reference in New Issue
Block a user