Skip to content

Commit 15ae0ed

Browse files
committed
create compose file
1 parent 40d988f commit 15ae0ed

8 files changed

Lines changed: 166 additions & 27 deletions

File tree

backend/Dockerfile

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,9 @@
1-
FROM golang:1.25-alpine AS builder
2-
ENV CGO_ENABLED=0 \
3-
GOOS=linux \
4-
GOARCH=amd64
5-
WORKDIR /build
6-
COPY go.mod go.sum ./
7-
COPY .env /app/.env
8-
RUN go mod tidy
1+
FROM golang:1.26
2+
RUN apt-get install -y --no-install-recommends git ca-certificates tzdata
3+
WORKDIR /backend
94
COPY . .
10-
RUN go build -o /pastectl ./cmd/main.go
11-
FROM alpine:3.21 AS FINAL
12-
RUN apk add --no-cache ca-certificates
13-
COPY --from=builder /pastectl /bin/pastectl
14-
RUN chmod +x /bin/pastectl
5+
RUN go mod download
6+
RUN go build -o main cmd/main.go
7+
RUN chmod +x main
158
EXPOSE 8080
16-
CMD ["/bin/pastectl"]
9+
CMD ["./main"]

backend/cmd/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ func main() {
4343

4444
r.Use(cors.New(config))
4545

46-
// --- Rate Limiting (rate-limiter-go) ---
47-
rateLimit := 60 // default: 60 requests per minute per IP
46+
rateLimit := 120
4847
if v := os.Getenv("RATE_LIMIT"); v != "" {
4948
if parsed, err := strconv.Atoi(v); err == nil && parsed > 0 {
5049
rateLimit = parsed
@@ -59,6 +58,9 @@ func main() {
5958
r.Use(rateLimitMiddleware.RateLimitMiddleware(rateLimiter, rlConfig))
6059
log.Printf("Rate limiting enabled: %d requests/minute per IP", rateLimit)
6160

61+
r.GET("/api/health", func(c *gin.Context) {
62+
c.JSON(200, gin.H{"status": "ok"})
63+
})
6264
r.POST("/api/pastes", handler.CreatePasteHandler)
6365
r.GET("/api/pastes/:id", handler.GetPasteHandler)
6466
r.GET("/api/pastes/:id/raw", handler.GetContentHandler)

backend/internal/db/db.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,20 @@ func Init() {
2727
}
2828

2929
DB = pool
30-
log.Println("Database initialized")
30+
log.Println("Database connected")
31+
createTableSQL := `
32+
CREATE TABLE IF NOT EXISTS pastes(
33+
id TEXT PRIMARY KEY,
34+
content TEXT NOT NULL,
35+
language TEXT NOT NULL,
36+
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
37+
expire_at TIMESTAMP,
38+
views INT NOT NULL DEFAULT 0
39+
);`
40+
if _, err := pool.Exec(context.Background(), createTableSQL); err != nil {
41+
log.Fatalf("Failed to run migration: %v\n", err)
42+
}
43+
log.Println("Database initialized (migration applied)")
3144
}
3245
func Close() {
3346
if DB != nil {

backend/internal/http/paste.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (h *Handler) CreatePasteHandler(c *gin.Context) {
3333
}
3434

3535
var req CreatePasteRequest
36-
if err := c.BindJSON(&req); err != nil {
36+
if err := c.ShouldBindJSON(&req); err != nil {
3737
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body or missing fields"})
3838
return
3939
}
@@ -92,7 +92,7 @@ func (h *Handler) UpdatePasteHandler(c *gin.Context) {
9292
}
9393

9494
var req UpdatePasteRequest
95-
if err := c.BindJSON(&req); err != nil {
95+
if err := c.ShouldBindJSON(&req); err != nil {
9696
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid or incomplete request"})
9797
return
9898
}

backend/internal/middleware/ratelimit.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,16 @@ import (
1010
"github.com/sumedhvats/rate-limiter-go/pkg/limiter"
1111
)
1212

13-
// RateLimitMiddleware returns a Gin middleware that enforces per-IP rate
14-
// limiting using the provided Limiter instance from rate-limiter-go.
15-
//
16-
// It sets standard rate-limit response headers on every request and returns
17-
// a 429 JSON response when the limit is exceeded.
1813
func RateLimitMiddleware(rateLimiter limiter.Limiter, cfg limiter.Config) gin.HandlerFunc {
1914
return func(c *gin.Context) {
2015
key := fmt.Sprintf("ip:%s", c.ClientIP())
2116

2217
allowed, err := rateLimiter.Allow(key)
2318
if err != nil {
24-
// If the limiter errors, fail open to avoid blocking legitimate
25-
// traffic due to an internal issue (e.g. storage hiccup).
2619
c.Next()
2720
return
2821
}
2922

30-
// Set standard rate-limit headers.
3123
c.Header("X-RateLimit-Limit", strconv.Itoa(cfg.Rate))
3224

3325
if !allowed {

compose.yaml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: pasteCTL_web
2+
3+
services:
4+
backend:
5+
build:
6+
context: ./backend
7+
dockerfile: Dockerfile
8+
ports:
9+
- "8080:8080"
10+
environment:
11+
- FRONTEND_URL=http://localhost:3000
12+
- DATABASE_URL=postgres://user:password@db:5432/pastectl
13+
depends_on:
14+
db:
15+
condition: service_healthy
16+
healthcheck:
17+
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/health || exit 1"]
18+
interval: 10s
19+
timeout: 5s
20+
retries: 5
21+
start_period: 10s
22+
restart: unless-stopped
23+
24+
db:
25+
image: postgres:13
26+
environment:
27+
POSTGRES_USER: user
28+
POSTGRES_PASSWORD: password
29+
POSTGRES_DB: pastectl
30+
ports:
31+
- "5432:5432"
32+
volumes:
33+
- pgdata:/var/lib/postgresql/data
34+
healthcheck:
35+
test: ["CMD-SHELL", "pg_isready -U user -d pastectl"]
36+
interval: 10s
37+
timeout: 5s
38+
retries: 5
39+
restart: unless-stopped
40+
41+
frontend:
42+
build:
43+
context: ./frontend
44+
dockerfile: Dockerfile
45+
args:
46+
- NEXT_PUBLIC_BACKEND_URL=http://localhost:8080
47+
- NEXT_PUBLIC_WS_URL=ws://localhost:8080
48+
ports:
49+
- "3000:3000"
50+
depends_on:
51+
backend:
52+
condition: service_healthy
53+
restart: unless-stopped
54+
55+
volumes:
56+
pgdata:

docker.txt

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
FROM golang:1.26
2+
ENV FRONTEND_URL=http://paste.sumedh.app
3+
ENV DATABASE_URL=https://notdburl.com
4+
RUN apt-get install -y --no-install-recommends git ca-certificates tzdata
5+
WORKDIR /backend
6+
COPY . .
7+
RUN go mod download
8+
RUN go build -o main cmd/main.go
9+
RUN chmod +x main
10+
EXPOSE 8080
11+
CMD ["./main"]
12+
13+
14+
15+
pasteCTL_web main  ? ✗ docker build backend
16+
[+] Building 38.5s (12/12) FINISHED docker:default
17+
=> [internal] load build definition from Dockerfile 0.0s
18+
=> => transferring dockerfile: 330B 0.0s
19+
=> [internal] load metadata for docker.io/library/golang:1.26 1.0s
20+
=> [internal] load .dockerignore 0.1s
21+
=> => transferring context: 34B 0.0s
22+
=> [1/7] FROM docker.io/library/golang:1.26@sha256:792443b89f65105abba56b9bd5e97f680a80074ac6 0.0s
23+
=> [internal] load build context 0.1s
24+
=> => transferring context: 1.62kB 0.0s
25+
=> CACHED [2/7] RUN apt-get install -y --no-install-recommends git ca-certificates tzdata 0.0s
26+
=> CACHED [3/7] WORKDIR /backend 0.0s
27+
=> [4/7] COPY . . 0.4s
28+
=> [5/7] RUN go mod download 12.7s
29+
=> [6/7] RUN go build -o main cmd/main.go 16.2s
30+
=> [7/7] RUN chmod +x main 0.5s
31+
=> exporting to image 7.0s
32+
=> => exporting layers 7.0s
33+
=> => writing image sha256:1383a0a76a5a9ac4b6de3852bca2d2bd27983e776156bf926aed29e3f902b0b1 0.0s
34+
35+
pasteCTL_web main  ? ❯
36+
37+
38+
FROM node
39+
ENV NEXT_PUBLIC_BACKEND_URL = http://paste.sumedh.app
40+
ENV NEXT_PUBLIC_WS_URL = ws://paste.sumedh.app
41+
WORKDIR /frontend
42+
COPY . .
43+
RUN npm install --legacy-peer-deps
44+
RUN npm run build
45+
EXPOSE 3000
46+
CMD ["npm","run","start"]
47+
48+
49+
pasteCTL_web main  ? ✗ docker build --no-cache -t paste-frontend frontend
50+
[+] Building 59.8s (10/10) FINISHED docker:default
51+
=> [internal] load build definition from Dockerfile 0.1s
52+
=> => transferring dockerfile: 336B 0.0s
53+
=> [internal] load metadata for docker.io/library/node:latest 0.4s
54+
=> [internal] load .dockerignore 0.1s
55+
=> => transferring context: 2B 0.0s
56+
=> [1/5] FROM docker.io/library/node:latest@sha256:f9a1756160a9e1c3dca456bc0b185bf8f2f112a677 0.0s
57+
=> [internal] load build context 2.1s
58+
=> => transferring context: 2.89MB 2.0s
59+
=> CACHED [2/5] WORKDIR /frontend 0.0s
60+
=> [3/5] COPY . . 9.0s
61+
=> [4/5] RUN npm install --legacy-peer-deps 22.3s
62+
=> [5/5] RUN npm run build 16.6s
63+
=> exporting to image 9.0s
64+
=> => exporting layers 8.9s
65+
=> => writing image sha256:0d8d7bed7895820bd484d3331963bc327cdd3c33032876d3960a2f60c86c98b2 0.0s
66+
=> => naming to docker.io/library/paste-frontend 0.0s
67+
68+
2 warnings found (use docker --debug to expand):
69+
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 2)
70+
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 3)
71+
72+
pasteCTL_web main  ? ❯

frontend/Dockerfile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
FROM node
2+
WORKDIR /frontend
3+
COPY . .
4+
ARG NEXT_PUBLIC_BACKEND_URL
5+
ARG NEXT_PUBLIC_WS_URL
6+
ENV NEXT_PUBLIC_BACKEND_URL=$NEXT_PUBLIC_BACKEND_URL
7+
ENV NEXT_PUBLIC_WS_URL=$NEXT_PUBLIC_WS_URL
8+
RUN npm install --legacy-peer-deps
9+
RUN npm run build
10+
EXPOSE 3000
11+
CMD ["npm","run","start"]

0 commit comments

Comments
 (0)