I'm a developer who got tired of bloated online tools that require signup just to merge two PDFs. So I built three free alternatives and deployed them on a single ARM64 VPS.
The Tools
1. ImgCrush — Image Optimizer
Compress, resize, and convert images (JPEG, PNG, WebP). Drop files in, get optimized files out. No signup, no file count limits.
2. PDFCrush — PDF Toolkit
Merge, compress, split PDFs and edit metadata. Server-side processing means it works with large files that crash browser-based tools.
3. EU VAT Dev — VAT Calculator
Calculate EU VAT across all 27 member states, validate VAT numbers against the official VIES database. Built for developers and businesses selling digital products in the EU.
Architecture
All three follow the same pattern:
[Astro Frontend] → [Go API] → [SQLite]
↓
[File Processing]
(libvips / pdfcpu)
Why Go?
File processing is CPU-bound work. Go's standard library handles HTTP, file I/O, and concurrency out of the box. The compiled binary is ~15MB and starts in milliseconds. No runtime, no dependency hell.
Key libraries:
- chi for HTTP routing
- pdfcpu for PDF operations (pure Go, no CGO)
- modernc.org/sqlite for database (pure Go SQLite, works on ARM64)
- bimg/libvips for image processing
Why Astro?
The landing pages are 100% static HTML — zero JavaScript shipped to the browser. This matters for SEO (Core Web Vitals) and for users on slow connections. The actual tool UI uses React "islands" — interactive components that hydrate only where needed.
---
// This is a static Astro page
import Layout from '../layouts/Layout.astro';
---
<Layout title="PDF Toolkit">
<!-- Static marketing content, zero JS -->
<h1>Merge, Compress & Split PDFs</h1>
<!-- Only this component ships React JS -->
<PDFUploader client:load />
</Layout>
Deployment: Single VPS, Multiple Products
Everything runs on one Hetzner cax21 (ARM64, 4 vCPU, 8GB RAM, ~€7/mo):
Caddy (reverse proxy + auto HTTPS)
├── pdfcrush.dev → :8081 (pdf-toolkit container)
├── imgcrush.dev → :8082 (image-optimizer container)
├── euvat.dev → :8083 (eu-vat-calculator container)
└── analytics → :8000 (Plausible CE)
Each product is a multi-stage Docker build:
# Stage 1: Build Go binary
FROM golang:1.26-alpine AS go-builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o server ./cmd/server
# Stage 2: Build Astro frontend
FROM node:20-alpine AS frontend-builder
WORKDIR /app
COPY frontend/ .
RUN npm ci && npm run build
# Stage 3: Minimal runtime
FROM alpine:3.19
COPY --from=go-builder /app/server /server
COPY --from=frontend-builder /app/dist /static
EXPOSE 8080
CMD ["/server"]
Final image size: ~25MB per product.
Rate Limiting & Pro Tiers
Each product has IP-based rate limiting with a cookie-based "Pro" bypass:
- User pays via Stripe
- Webhook saves their email as an active subscription
- User enters email → gets an HMAC-signed HTTP-only cookie
- Rate limiter checks cookie before checking IP
No passwords, no sessions, no user accounts. Just email → cookie → unlimited access.
Numbers (Honest)
After a few weeks live:
- ~38 total visitors across all 3 products
- Zero revenue
- Near-zero SEO rankings (too new)
Traffic is the bottleneck, not product quality. ImgCrush shows 26s average session duration — people who find it actually use it. The problem is nobody can find it yet.
What's Next
- SEO content — Blog articles targeting long-tail keywords ("best free PNG compressor 2026", "how to compress PDF without losing quality")
- Directory submissions — AlternativeTo, SaaSHub, BetaList
- Community sharing — this post is part of that effort
If you're building similar tools, I'd recommend the Go + Astro stack. It's lightweight, fast, and the deployment story is simple.
Try them out: imgcrush.dev | pdfcrush.dev | euvat.dev
Top comments (0)