Skip to content

Self-Hosted / Generic

Pageflare works with any static site regardless of host or build system. This guide covers the most common self-hosted patterns: Docker builds, generic CI/CD pipelines, Nginx/Apache post-build integration, and cron-based re-optimization.

Every integration follows the same three-step pattern:

Terminal window
# 1. Build your static site
npm run build # or hugo, jekyll build, eleventy, etc.
# 2. Optimize the output
pageflare dist/ --in-place --no-progress
# 3. Deploy
rsync -avz dist/ user@server:/var/www/html/
Terminal window
npm install -g @pageflare/cli
Terminal window
curl -fsSL https://get.appz.dev/pageflare/install.sh | sh
Terminal window
pageflare --version
Dockerfile
FROM node:20-alpine AS build
WORKDIR /app
# Install dependencies
COPY package*.json ./
RUN npm ci
# Install pageflare
RUN npm install -g @pageflare/cli
# Copy source
COPY . .
# Build the site
RUN npm run build
# Optimize the output
ARG PAGEFLARE_LICENSE
ENV PAGEFLARE_LICENSE=${PAGEFLARE_LICENSE}
RUN pageflare dist/ --in-place --no-progress
# Serve with Nginx
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

Build and run:

Terminal window
docker build --build-arg PAGEFLARE_LICENSE=your-license-key -t mysite .
docker run -p 8080:80 mysite

Multi-stage Dockerfile (with separate builder and server stages)

Section titled “Multi-stage Dockerfile (with separate builder and server stages)”
Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS optimizer
WORKDIR /app
COPY --from=builder /app/dist ./dist
ARG PAGEFLARE_LICENSE
ENV PAGEFLARE_LICENSE=${PAGEFLARE_LICENSE}
RUN npm install -g @pageflare/cli && \
pageflare dist/ --in-place --no-progress
FROM nginx:alpine AS server
COPY --from=optimizer /app/dist /usr/share/nginx/html
EXPOSE 80

The pattern is the same for any CI provider. See the CI/CD guide for provider-specific YAML examples (GitHub Actions, GitLab CI).

build-and-deploy.sh
#!/usr/bin/env bash
set -e
# Build
npm ci
npm run build
# Optimize
pageflare dist/ --in-place --no-progress
# Deploy (example: rsync to a server)
rsync -avz --delete dist/ deploy@myserver.example.com:/var/www/html/
Terminal window
export PAGEFLARE_LICENSE="your-license-key"

Or store it in a .env file (never commit this):

.env
PAGEFLARE_LICENSE=your-license-key

Load it in your script:

Terminal window
set -a && source .env && set +a
pageflare dist/ --in-place --no-progress

Pageflare runs at build time, not at runtime. Point Nginx at the already-optimized output directory:

/etc/nginx/sites-available/mysite
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.html;
# Serve pre-compressed files if available
gzip_static on;
brotli_static on;
# Cache static assets aggressively
location ~* \.(css|js|woff2|png|jpg|webp|avif|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri $uri/ $uri.html =404;
}
}

After running pageflare, reload Nginx:

Terminal window
pageflare /var/www/html --in-place --no-progress
nginx -s reload
/etc/apache2/sites-available/mysite.conf
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html
<Directory /var/www/html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
# Cache static assets
<FilesMatch "\.(css|js|woff2|png|jpg|webp|avif|svg)$">
Header set Cache-Control "public, max-age=31536000, immutable"
</FilesMatch>
</VirtualHost>

For sites that regenerate on a schedule (e.g., data-driven static sites rebuilt nightly), set up a cron job:

/etc/cron.d/pageflare-optimize
# Run at 3 AM every day
0 3 * * * deploy /home/deploy/scripts/rebuild-and-optimize.sh >> /var/log/pageflare.log 2>&1
/home/deploy/scripts/rebuild-and-optimize.sh
#!/usr/bin/env bash
set -e
SITE_DIR="/var/www/mysite"
BUILD_DIR="$HOME/build/mysite"
cd "$BUILD_DIR"
echo "[$(date -Is)] Starting rebuild"
# Pull latest content
git pull --quiet
# Build
npm run build
# Optimize
PAGEFLARE_LICENSE="$(cat /etc/pageflare-license)" \
pageflare dist/ --in-place --no-progress --json > /tmp/pageflare-last-run.json
# Swap in the optimized build
rsync -avz --delete dist/ "$SITE_DIR/"
echo "[$(date -Is)] Done — $(jq '.summary.bytes_after' /tmp/pageflare-last-run.json) bytes deployed"

Use --json to capture a machine-readable report and verify the optimization ran correctly:

Terminal window
pageflare dist/ --in-place --json > /tmp/report.json
# Check for errors
ERRORS=$(jq '.summary.errors' /tmp/report.json)
if [ "$ERRORS" -gt 0 ]; then
echo "pageflare reported $ERRORS errors" >&2
exit 1
fi
echo "Optimized $(jq '.summary.optimized' /tmp/report.json) files"

Place pageflare.jsonc in the directory where you run the command, or pass it explicitly:

Terminal window
pageflare dist/ --in-place --config /etc/pageflare/pageflare.jsonc
pageflare.jsonc
{
"minify_html": true,
"minify_css": true,
"minify_js": true,
"js_defer": true,
"lazy_images": true,
"img_dimensions": true,
"font_swap": true
}

See the Configuration reference for all available options.