Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ dist/
# the pinned Linux build at build time. Never commit either binary or data.
pb/pocketbase
pb/pb_data/
# PocketBase backup archives (Settings → Backups) — contain live records incl.
# contact-form submissions (emails/PII). NEVER commit to this public repo.
pb_backup*.zip
**/pb_backup*.zip

# ── Logs ───────────────────────────────────────────────────────────────
*.log
Expand Down
2 changes: 2 additions & 0 deletions astro/.gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# build output
dist/
.output/
.vercel/

# test artifacts
coverage/
Expand Down Expand Up @@ -30,3 +31,4 @@ pnpm-debug.log*
.vscode/*
!.vscode/extensions.json
.idea/
.vercel
13 changes: 10 additions & 3 deletions astro/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@
import { defineConfig } from 'astro/config';
import vue from '@astrojs/vue';
import node from '@astrojs/node';
import vercel from '@astrojs/vercel';
import tailwindcss from '@tailwindcss/vite';

// Vercel sets VERCEL=1 in every build/runtime env. On Vercel we use the Vercel
// serverless adapter; everywhere else (local Docker, the DO VPS during the
// migration) we keep the @astrojs/node standalone adapter — so both deploy
// targets build from this one config without a breaking cutover.
const onVercel = !!process.env.VERCEL;

// English is the default locale and is served at "/" (no prefix).
// Italian → /it/…, Spanish → /es/….
//
Expand All @@ -12,12 +19,12 @@ import tailwindcss from '@tailwindcss/vite';
// `@astrojs/node` standalone adapter outputs a self-contained Node server at
// `dist/server/entry.mjs` (it also serves the static client assets). Truly
// static pages (e.g. a future 404 or legal page) can opt out with
// `export const prerender = true`. Swap the adapter for `@astrojs/vercel`,
// `@astrojs/cloudflare`, etc. when you pick a different host.
// `export const prerender = true`. The adapter is chosen at build time from the
// environment (see `onVercel` above).
export default defineConfig({
site: process.env.SITE_URL ?? 'https://micio86dev.example',
output: 'server',
adapter: node({ mode: 'standalone' }),
adapter: onVercel ? vercel() : node({ mode: 'standalone' }),
// Inline every stylesheet into the document instead of emitting render-blocking
// <link rel="stylesheet"> requests — the per-page CSS here is small and SSR
// serves a fresh document each request anyway, so cross-page CSS caching buys
Expand Down
193 changes: 127 additions & 66 deletions astro/bun.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions astro/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
},
"dependencies": {
"@astrojs/node": "^9.0.0",
"@astrojs/vercel": "9",
"@astrojs/vue": "^5.0.0",
"astro": "^5.0.0",
"gsap": "^3.15.0",
Expand Down
4 changes: 4 additions & 0 deletions astro/vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "astro"
}
21 changes: 12 additions & 9 deletions pb/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ARG PB_VERSION=0.36.3
ARG TARGETARCH=amd64

RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates unzip wget \
&& apt-get install -y --no-install-recommends ca-certificates unzip wget gosu \
&& rm -rf /var/lib/apt/lists/* \
&& wget -q "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_${TARGETARCH}.zip" -O /tmp/pb.zip \
&& unzip /tmp/pb.zip -d /pb \
Expand All @@ -25,20 +25,23 @@ WORKDIR /pb
# Versioned schema migrations — committed to the repo, applied with `migrate up`.
COPY pb_migrations ./pb_migrations

# Run as a non-root user. The host directory bound to /pb/pb_data must be
# writable by this uid (see README "VPS layout").
# Create the unprivileged runtime user. PB runs as `pocketbase` (uid 1001), but
# the container STARTS as root so the entrypoint can chown a root-owned mounted
# volume (Railway) before dropping privileges with gosu — see entrypoint.sh.
RUN useradd --system --uid 1001 --no-create-home pocketbase \
&& mkdir -p /pb/pb_data \
&& chown -R pocketbase:pocketbase /pb
USER pocketbase

COPY entrypoint.sh /pb/entrypoint.sh
RUN chmod +x /pb/entrypoint.sh

EXPOSE 8090
VOLUME ["/pb/pb_data"]
# NB: no `VOLUME` instruction — persistence is provided by the host bind mount
# (docker-compose `volumes:`) or a Railway Volume. Railway's builder rejects the
# Docker `VOLUME` directive outright, and docker-compose overrides it anyway, so
# declaring it here buys nothing.

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --spider -q http://127.0.0.1:8090/api/health || exit 1

CMD ["/pb/pocketbase", "serve", \
"--http=0.0.0.0:8090", \
"--dir=/pb/pb_data", \
"--migrationsDir=/pb/pb_migrations"]
ENTRYPOINT ["/pb/entrypoint.sh"]
28 changes: 28 additions & 0 deletions pb/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/bin/sh
# PocketBase launcher that works on both a host bind mount (docker-compose / the
# DO VPS) and a managed volume (Railway).
#
# Railway mounts the persistent volume owned by root, so a container that starts
# as the unprivileged `pocketbase` user cannot create the SQLite files → PB dies
# with "unable to open database file" (SQLITE_CANTOPEN). To stay non-root at
# runtime while still owning the volume, we start as root, fix ownership of the
# data dir, then drop to `pocketbase` via gosu. When the image is already run as
# a non-root user (nothing to fix), we just exec PB directly.
#
# We also bind PB to `[::]:8090` (IPv6, dual-stack) rather than `0.0.0.0`:
# Railway's private network — which its edge proxy uses to reach the container —
# is IPv6-only, so an IPv4-only listener answers the local healthcheck but is
# unreachable from the proxy (→ perpetual 502). `[::]` accepts both families.
set -e

DATA_DIR=/pb/pb_data

if [ "$(id -u)" = "0" ]; then
mkdir -p "$DATA_DIR"
chown -R pocketbase:pocketbase "$DATA_DIR" 2>/dev/null || true
exec gosu pocketbase /pb/pocketbase serve \
--http=[::]:8090 --dir="$DATA_DIR" --migrationsDir=/pb/pb_migrations
fi

exec /pb/pocketbase serve \
--http=[::]:8090 --dir="$DATA_DIR" --migrationsDir=/pb/pb_migrations
Loading