No description
  • JavaScript 61.7%
  • CSS 32.3%
  • HTML 5.4%
  • Dockerfile 0.6%
Find a file
Feiko c5c3428b05
All checks were successful
Build and Deploy to Cloud Run / deploy (push) Successful in 42s
chore: migrate project to Bun
2026-05-05 00:13:39 +02:00
.claude feat: add forgejo deploy workflow and replace svg avatar with png 2026-04-25 12:20:05 +02:00
.forgejo/workflows feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00
.vscode chore: implement SEO best practices (meta tags, JSON-LD, robots.txt, sitemap, semantic HTML) 2026-04-25 13:48:36 +02:00
public feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00
src feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00
.gcloudignore chore: migrate project to Bun 2026-05-05 00:13:39 +02:00
.gitignore chore: remove rust codepath and associated build configurations 2026-05-05 00:01:44 +02:00
bun.lock chore: migrate project to Bun 2026-05-05 00:13:39 +02:00
Dockerfile chore: migrate project to Bun 2026-05-05 00:13:39 +02:00
index.html feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00
nginx.conf chore: remove rust codepath and associated build configurations 2026-05-05 00:01:44 +02:00
package.json feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00
README.md chore: migrate project to Bun 2026-05-05 00:13:39 +02:00
vite.config.js feat: migrate to Vite build system and host libraries onsite 2026-04-25 22:49:44 +02:00

feikowielsma.nl — personal site

Static single-page site built with React + Vite (using Bun).
Just index.html — drop it anywhere that serves files over HTTP.


Before going live

1. Add your photo

Drop a photo (e.g. avatar.png) into the same folder as index.html.
Then in index.html, find:

<div className="avatar-placeholder">

Replace that whole block with:

<img src="avatar.png" alt="Feiko Wielsma"
  style={{ width: 240, height: 280, borderRadius: 20, objectFit: "cover" }} />

2. Wire up the contact form (Formspree — free, no backend needed)

  1. Go to formspree.io and create a free account
  2. Click New Form, name it anything, copy your form ID (looks like xrgvkpqz)
  3. In index.html, find:
    fetch("https://formspree.io/f/YOUR_FORM_ID"
    
    Replace YOUR_FORM_ID with your actual ID.
  4. Done. Formspree handles delivery, spam filtering, and optional reCAPTCHA from their dashboard.

Free tier = 50 submissions/month — more than enough for a personal site.

Search index.html for these and confirm they're correct:

  • linkedin.com/in/feikowielsma
  • github.com/feikowielsma
  • feiko@feikowielsma.nl (assembled in JS, search for feikowielsma)

Hosting options

Best option: free, fast, SSL included, custom domain trivial.

  1. Push index.html (+ your photo) to a GitHub repo
  2. Go to pages.cloudflare.com
  3. Connect your GitHub repo, no build command, output directory = / (root)
  4. Deploy → you get a .pages.dev URL immediately
  5. Go to Custom Domains → add feikowielsma.nl
  6. Point your domain's nameservers to Cloudflare (your registrar's DNS settings), or add a CNAME record:
    CNAME  @  <your-site>.pages.dev
    

Cost: €0/month


Option B — GCP Cloud Storage (static, cheap, slightly more manual)

Good if you already use GCP and want everything in one place.

  1. Create a bucket named exactly feikowielsma.nl in Cloud Console
  2. Upload index.html and your photo
  3. Make the bucket public: IAM → add allUsers with role Storage Object Viewer
  4. Enable Static website hosting on the bucket (index page = index.html)
  5. Point your domain DNS:
    • Add a CNAME record: wwwc.storage.googleapis.com
    • For the apex (@), use a A record pointing to 216.239.32.21 (GCP load balancer) — requires setting up a Cloud Load Balancer + SSL cert (more involved)
    • Easier: just redirect feikowielsma.nlwww.feikowielsma.nl at your registrar

Cost: ~€0.02/month (storage) + negligible egress


Option C — GCP Cloud Run (Docker, if you want a tiny backend later)

Use this if you eventually want a real backend (e.g. your own contact form endpoint instead of Formspree).

Dockerfile

FROM nginx:alpine
COPY index.html /usr/share/nginx/html/index.html
COPY avatar.png /usr/share/nginx/html/avatar.png
EXPOSE 8080
CMD ["nginx", "-g", "daemon off;"]

Note: Cloud Run expects port 8080 — add this to your nginx config or use the env var PORT.

nginx.conf (save next to Dockerfile)

server {
    listen 8080;
    server_name _;
    root /usr/share/nginx/html;
    index index.html;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

Deploy

# Build and push
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/feiko-site

# Deploy to Cloud Run
gcloud run deploy feiko-site \
  --image gcr.io/YOUR_PROJECT_ID/feiko-site \
  --platform managed \
  --region europe-west4 \
  --allow-unauthenticated \
  --port 8080

# Map your domain (Cloud Run console → Custom Domains)

Cost: €0/month when idle (scales to zero). You pay only for actual requests — essentially free for a personal site.


DNS quick reference (wherever your domain is registered)

For Cloudflare Pages (simplest):

CNAME  @    <yoursite>.pages.dev
CNAME  www  <yoursite>.pages.dev

For Cloud Run / Cloud Storage with a load balancer:

A      @    <load-balancer-IP>
CNAME  www  <load-balancer-IP or ghs.google.com>

SSL/TLS is handled automatically by Cloudflare Pages and Cloud Run.
Cloud Storage requires setting up a Google-managed cert on a load balancer if you want HTTPS on the apex domain.


Files in this project

src/         — React source files
public/      — static assets (icons, fonts)
bun.lock     — Bun lockfile
package.json — project configuration
Dockerfile   — container build instructions
README.md    — this file