inital commit
This commit is contained in:
parent
f50224d8bb
commit
52a2ae9a31
7
Dockerfile
Normal file
7
Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM debian:bookworm-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
curl \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
62
README.md
62
README.md
@ -0,0 +1,62 @@
|
||||
# Document Scanner Application
|
||||
|
||||
A simple document scanning application with Go backend and HTML/JavaScript frontend.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
scanner/
|
||||
├── backend/ # Go backend
|
||||
│ └── main.go # Main Go server file
|
||||
└── frontend/ # Frontend
|
||||
└── index.html # Main HTML file
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Go 1.16+ installed
|
||||
|
||||
### Backend Setup
|
||||
|
||||
1. Navigate to the backend directory:
|
||||
```
|
||||
cd backend
|
||||
```
|
||||
|
||||
2. Run the Go server:
|
||||
```
|
||||
go run main.go
|
||||
```
|
||||
|
||||
The server will start on port 8080.
|
||||
|
||||
### Frontend Setup
|
||||
|
||||
1. Simply open the `frontend/index.html` file in a web browser.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
The backend provides the following endpoints:
|
||||
|
||||
- `POST /scan/start`: Starts a new scanning session
|
||||
- `POST /scan/abort`: Aborts the current scanning session
|
||||
- `GET /documents`: Returns documents from the current session
|
||||
|
||||
## Usage
|
||||
|
||||
1. Open the frontend in your browser
|
||||
2. Click "Start Scanning" to begin scanning documents
|
||||
3. The documents will appear in the grid below as they are scanned
|
||||
4. Click "Abort Scanning" to stop the process at any time
|
||||
5. Click "Refresh Documents" to manually refresh the document list
|
||||
|
||||
## Notes
|
||||
|
||||
This is a simplified simulation of document scanning. In a real-world application, you would need to:
|
||||
|
||||
1. Integrate with actual scanning hardware
|
||||
2. Implement proper error handling
|
||||
3. Add authentication and security
|
||||
4. Add persistent storage for documents
|
||||
17
backend/Dockerfile
Normal file
17
backend/Dockerfile
Normal file
@ -0,0 +1,17 @@
|
||||
FROM golang:1.22-bookworm
|
||||
|
||||
# Install scanimage (part of sane-utils)
|
||||
RUN apt-get update && apt-get install -y sane-utils iputils-ping && apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Add non-root user
|
||||
RUN useradd -m backend
|
||||
|
||||
USER backend
|
||||
|
||||
WORKDIR /home/backend
|
||||
|
||||
COPY --chown=backend:backend . .
|
||||
|
||||
RUN go build -o main
|
||||
|
||||
CMD ["./main"]
|
||||
3
backend/go.mod
Normal file
3
backend/go.mod
Normal file
@ -0,0 +1,3 @@
|
||||
module github.com/scanner/backend
|
||||
|
||||
go 1.20
|
||||
88
backend/handlers/scan_handlers.go
Normal file
88
backend/handlers/scan_handlers.go
Normal file
@ -0,0 +1,88 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/scanner/backend/middleware"
|
||||
"github.com/scanner/backend/services"
|
||||
)
|
||||
|
||||
// ScanHandler manages scan-related HTTP endpoints
|
||||
type ScanHandler struct {
|
||||
scannerService *services.ScannerService
|
||||
}
|
||||
|
||||
// NewScanHandler creates a new scan handler
|
||||
func NewScanHandler(scannerService *services.ScannerService) *ScanHandler {
|
||||
return &ScanHandler{
|
||||
scannerService: scannerService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetScanStatus handles requests to get the current scan status
|
||||
func (h *ScanHandler) GetScanStatus(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.ApplyCors(w, r)
|
||||
|
||||
status := h.scannerService.IsScanning()
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]bool{"isScanning": status})
|
||||
}
|
||||
|
||||
// StartScan handles requests to start a new scan
|
||||
func (h *ScanHandler) StartScan(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.ApplyCors(w, r)
|
||||
|
||||
success, _ := h.scannerService.StartScan()
|
||||
if !success {
|
||||
http.Error(w, "Scan already in progress", http.StatusConflict)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
||||
}
|
||||
|
||||
// AbortScan handles requests to abort an ongoing scan
|
||||
func (h *ScanHandler) AbortScan(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.ApplyCors(w, r)
|
||||
|
||||
success, _ := h.scannerService.AbortScan()
|
||||
if !success {
|
||||
http.Error(w, "No scan in progress", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]bool{"success": true})
|
||||
}
|
||||
|
||||
// GetDocuments handles requests to retrieve all scanned documents
|
||||
func (h *ScanHandler) GetDocuments(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
middleware.ApplyCors(w, r)
|
||||
|
||||
documents := h.scannerService.GetDocuments()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(documents)
|
||||
}
|
||||
35
backend/main.go
Normal file
35
backend/main.go
Normal file
@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/scanner/backend/handlers"
|
||||
"github.com/scanner/backend/middleware"
|
||||
"github.com/scanner/backend/services"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize services
|
||||
scannerService := services.NewScannerService()
|
||||
|
||||
// Initialize handlers
|
||||
scanHandler := handlers.NewScanHandler(scannerService)
|
||||
|
||||
// Set up routes with middleware
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// Register API routes
|
||||
mux.HandleFunc("/scan/start", scanHandler.StartScan)
|
||||
mux.HandleFunc("/scan/abort", scanHandler.AbortScan)
|
||||
mux.HandleFunc("/scan/status", scanHandler.GetScanStatus)
|
||||
mux.HandleFunc("/documents", scanHandler.GetDocuments)
|
||||
|
||||
fileServer := http.FileServer(http.Dir("/home/backend/var/documents"))
|
||||
mux.Handle("/files/", http.StripPrefix("/files", fileServer))
|
||||
|
||||
handler := middleware.CorsMiddleware(mux)
|
||||
|
||||
log.Println("Server starting on port 80...")
|
||||
log.Fatal(http.ListenAndServe(":80", handler))
|
||||
}
|
||||
32
backend/middleware/cors.go
Normal file
32
backend/middleware/cors.go
Normal file
@ -0,0 +1,32 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// CorsMiddleware adds CORS headers to responses
|
||||
func CorsMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
|
||||
// ApplyCors adds CORS headers to a response
|
||||
func ApplyCors(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}
|
||||
7
backend/models/document.go
Normal file
7
backend/models/document.go
Normal file
@ -0,0 +1,7 @@
|
||||
package models
|
||||
|
||||
// Document represents a scanned document
|
||||
type Document struct {
|
||||
Filename string `json:"filename"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
10
backend/models/scanner_state.go
Normal file
10
backend/models/scanner_state.go
Normal file
@ -0,0 +1,10 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ScannerState struct {
|
||||
IsScanning bool `json:"isScanning"`
|
||||
Mu sync.Mutex `json:"-"`
|
||||
}
|
||||
51
backend/services/sane.go
Normal file
51
backend/services/sane.go
Normal file
@ -0,0 +1,51 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func scanImage(args ...string) (string, error) {
|
||||
cmd := exec.Command("scanimage", args...)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
var stdout bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error scanning: %v", stderr.String())
|
||||
}
|
||||
|
||||
return stdout.String(), nil
|
||||
}
|
||||
|
||||
func status() (string, error) {
|
||||
result, err := scanImage("--status")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error getting status: %v", err)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func listDevices() ([]string, error) {
|
||||
result, err := scanImage("--list-devices")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing devices: %v", err)
|
||||
}
|
||||
|
||||
return strings.Split(result, "\n"), nil
|
||||
}
|
||||
|
||||
func startScan(outputFile string) (string, error) {
|
||||
result, err := scanImage("-d", "escl:https://printer:443", "--format", "png", "--output-file", outputFile)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error scanning: %v", err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
119
backend/services/scanner_service.go
Normal file
119
backend/services/scanner_service.go
Normal file
@ -0,0 +1,119 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/scanner/backend/models"
|
||||
)
|
||||
|
||||
// ScannerService handles scanner operations
|
||||
type ScannerService struct {
|
||||
state models.ScannerState
|
||||
}
|
||||
|
||||
// NewScannerService creates a new scanner service
|
||||
func NewScannerService() *ScannerService {
|
||||
return &ScannerService{
|
||||
state: models.ScannerState{
|
||||
IsScanning: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetScanStatus returns the current scan status
|
||||
func (s *ScannerService) IsScanning() bool {
|
||||
s.state.Mu.Lock()
|
||||
state := s.state.IsScanning
|
||||
s.state.Mu.Unlock()
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
// StartScan begins a new scanning process
|
||||
func (s *ScannerService) StartScan() (bool, error) {
|
||||
s.state.Mu.Lock()
|
||||
defer s.state.Mu.Unlock()
|
||||
|
||||
if s.state.IsScanning {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
s.state.IsScanning = true
|
||||
|
||||
go s.scan()
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// AbortScan stops an in-progress scan
|
||||
func (s *ScannerService) AbortScan() (bool, error) {
|
||||
s.state.Mu.Lock()
|
||||
defer s.state.Mu.Unlock()
|
||||
|
||||
if !s.state.IsScanning {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
s.state.IsScanning = false
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetDocuments returns all scanned documents
|
||||
func (s *ScannerService) GetDocuments() []models.Document {
|
||||
const outputDir = "/home/backend/var/documents"
|
||||
|
||||
files, err := os.ReadDir(outputDir)
|
||||
if err != nil {
|
||||
return []models.Document{}
|
||||
}
|
||||
|
||||
documents := []models.Document{}
|
||||
for _, file := range files {
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
filename := file.Name()
|
||||
if !strings.HasPrefix(filename, "scan_") || !strings.HasSuffix(filename, ".jpg") {
|
||||
continue
|
||||
}
|
||||
|
||||
documents = append(documents, models.Document{
|
||||
Filename: filename,
|
||||
URL: fmt.Sprintf("/api/files/%s", filename),
|
||||
})
|
||||
}
|
||||
|
||||
return documents
|
||||
}
|
||||
|
||||
func (s *ScannerService) scan() {
|
||||
s.state.Mu.Lock()
|
||||
isScanning := s.state.IsScanning
|
||||
s.state.Mu.Unlock()
|
||||
|
||||
if !isScanning {
|
||||
return
|
||||
}
|
||||
|
||||
outputDir := "/home/backend/var/documents"
|
||||
timestamp := time.Now().Format("20060102150405")
|
||||
outputFile := fmt.Sprintf("%s/scan_%s.jpg", outputDir, timestamp)
|
||||
|
||||
_, err := startScan(outputFile)
|
||||
|
||||
s.state.Mu.Lock()
|
||||
defer s.state.Mu.Unlock()
|
||||
|
||||
if !s.state.IsScanning {
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("%v\n", err)
|
||||
}
|
||||
|
||||
s.state.IsScanning = false
|
||||
}
|
||||
28
docker-compose.yml
Normal file
28
docker-compose.yml
Normal file
@ -0,0 +1,28 @@
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8089:80"
|
||||
extra_hosts:
|
||||
- "printer:192.168.178.36"
|
||||
networks:
|
||||
- printer_network
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8090:80"
|
||||
networks:
|
||||
- printer_network
|
||||
|
||||
networks:
|
||||
printer_network:
|
||||
driver: bridge
|
||||
|
||||
#scanimage --source "escl:https://printer:443" --format=png --no-ssl-verification
|
||||
7
frontend/Dockerfile
Normal file
7
frontend/Dockerfile
Normal file
@ -0,0 +1,7 @@
|
||||
FROM nginx:latest
|
||||
|
||||
COPY ./public /usr/share/nginx/html
|
||||
|
||||
COPY site.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
188
frontend/public/index.html
Normal file
188
frontend/public/index.html
Normal file
@ -0,0 +1,188 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document Scanner</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
}
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
button {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background-color: #4285f4;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #3367d6;
|
||||
}
|
||||
button:disabled {
|
||||
background-color: #cccccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.document-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
}
|
||||
.document-card {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.document-card img {
|
||||
width: 100%;
|
||||
height: 150px;
|
||||
object-fit: cover;
|
||||
}
|
||||
.document-card .info {
|
||||
padding: 10px;
|
||||
}
|
||||
.status {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.status.scanning {
|
||||
background-color: #e6f7ff;
|
||||
border: 1px solid #91d5ff;
|
||||
}
|
||||
.status.idle {
|
||||
background-color: #f6ffed;
|
||||
border: 1px solid #b7eb8f;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Document Scanner</h1>
|
||||
|
||||
<div id="status" class="status idle">Scanner is idle</div>
|
||||
|
||||
<div class="controls">
|
||||
<button id="startBtn">Start Scanning</button>
|
||||
<button id="abortBtn" disabled>Abort Scanning</button>
|
||||
</div>
|
||||
|
||||
<h2>Documents</h2>
|
||||
<div id="documents" class="document-grid">
|
||||
<p>No documents scanned yet.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_URL = `/api`;
|
||||
const startBtn = document.getElementById('startBtn');
|
||||
const abortBtn = document.getElementById('abortBtn');
|
||||
const statusEl = document.getElementById('status');
|
||||
const documentsEl = document.getElementById('documents');
|
||||
|
||||
function setScannerState(scanning) {
|
||||
startBtn.disabled = scanning;
|
||||
abortBtn.disabled = !scanning;
|
||||
|
||||
if (scanning) {
|
||||
statusEl.textContent = 'Scanner is running...';
|
||||
statusEl.className = 'status scanning';
|
||||
} else {
|
||||
statusEl.textContent = 'Scanner is idle';
|
||||
statusEl.className = 'status idle';
|
||||
}
|
||||
}
|
||||
|
||||
async function startScanning() {
|
||||
startBtn.disabled = true;
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/scan/start`, {
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error starting scan:', error);
|
||||
alert('Failed to connect to scanner service.');
|
||||
startBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function abortScanning() {
|
||||
abortBtn.disabled = true;
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/scan/abort`, {
|
||||
method: 'POST'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error aborting scan:', error);
|
||||
alert('Failed to connect to scanner service.');
|
||||
abortBtn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function pollDocuments() {
|
||||
fetch(`${API_URL}/documents`)
|
||||
.then(response => response.json())
|
||||
.then(documents => {
|
||||
if (documents.length === 0) {
|
||||
documentsEl.innerHTML = '<p>No documents scanned yet.</p>';
|
||||
setTimeout(() => {
|
||||
pollDocuments();
|
||||
}, 2000);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
documentsEl.innerHTML = documents.map(doc => `
|
||||
<div class="document-card">
|
||||
<img src="${doc.url}" alt="${doc.filename}">
|
||||
<div class="info">
|
||||
<h3>${doc.filename}</h3>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
|
||||
setTimeout(() => {
|
||||
pollDocuments();
|
||||
}, 2000);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching documents:', error);
|
||||
documentsEl.innerHTML = '<p>Error loading documents.</p>';
|
||||
});
|
||||
}
|
||||
|
||||
function pollStatus() {
|
||||
fetch(`${API_URL}/scan/status`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
setScannerState(data.isScanning);
|
||||
|
||||
setTimeout(() => {
|
||||
pollStatus();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
startBtn.addEventListener('click', startScanning);
|
||||
abortBtn.addEventListener('click', abortScanning);
|
||||
|
||||
pollStatus();
|
||||
pollDocuments();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
22
frontend/site.conf
Normal file
22
frontend/site.conf
Normal file
@ -0,0 +1,22 @@
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_pass http://backend:80/;
|
||||
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-Proto $scheme;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user