- Home
- Learning paths
- Expert path
- Nginx, VPS, proxy and CDN: deploy Éclair
Nginx, VPS, proxy and CDN: deploy Éclair
Contents
- What Nginx must reproduce from .htaccess
- The commented Nginx configuration
- HTTPS with Certbot, then Éclair's settings
- How do you deploy Éclair behind a reverse proxy?
- Cloudflare: what to configure
- How do you deploy Éclair with Docker?
- Checks after you deploy Éclair
- Key points
- Going further
- Frequently asked questions
Contents
- What Nginx must reproduce from .htaccess
- The commented Nginx configuration
- HTTPS with Certbot, then Éclair's settings
- How do you deploy Éclair behind a reverse proxy?
- Cloudflare: what to configure
- How do you deploy Éclair with Docker?
- Checks after you deploy Éclair
- Key points
- Going further
- Frequently asked questions
To deploy Éclair on a VPS, behind a proxy or a CDN, you reproduce what .htaccess does on shared hosting: protect the internal folders, send everything to index.php, and compress and cache static files. This lesson gives you a commented Nginx configuration, the HTTPS, proxy and Cloudflare settings, a Docker example and the final checks.
What you'll be able to do
Configure Nginx
The .htaccess rules, PHP-FPM and the assistant's stream.
Switch to HTTPS
Certbot, Force HTTPS, the official address and HSTS.
Add a proxy or a CDN
Real IP address, Cloudflare and a Docker container.
What Nginx must reproduce from .htaccess
Nginx ignores .htaccess files. Its configuration must therefore guarantee the same protections:
| .htaccess rule | Why |
|---|---|
app/, data/ and cache/ return 404 | code, data and generated pages stay private |
hidden files return 404, except .well-known | .git or .env stay invisible, the MCP connector's OAuth discovery stays reachable |
no executable .php file other than index.php | a script dropped elsewhere never runs |
media/ without scripts or pages | a booby-trapped image doesn't become a page |
everything else goes to index.php | Éclair's router responds, clean URLs included |
| compression, one-year browser caching | light pages, static files reused |
The Authorization header, which .htaccess has to copy for the MCP connector, is passed to PHP-FPM by Nginx automatically.
The commented Nginx configuration
The rules follow the Nginx section of Éclair's official guide; the lines marked “added” complete the example for a real server. root is the folder that receives the contents of the archive's eclair folder.
server {
listen 80;
listen [::]:80;
server_name exemple.fr www.exemple.fr;
root /var/www/eclair;
index index.php;
client_max_body_size 24m; # added: images up to 20 MB (Nginx default: 1 MB)
gzip on; # added: compression, like .htaccess
gzip_types text/plain text/css text/xml text/markdown application/javascript
application/json application/xml application/rss+xml image/svg+xml;
# Internal folders and hidden files, except .well-known (OAuth discovery)
location ~ ^/(app|data|cache)(/|$) { return 404; }
location ~ /\.(?!well-known/) { return 404; }
# Media: images and fonts only
location ^~ /media/ {
location ~* \.(php\d?|phtml|phar|s?html?|svgz?|xml|js)$ { return 404; }
add_header X-Content-Type-Options nosniff;
add_header Content-Security-Policy "default-src 'none'; img-src 'self'; sandbox"; # added, like media/.htaccess
expires 1y;
}
# Versioned static files: one-year browser caching
location ~* \.(webp|avif|jpe?g|png|gif|ico|css|js|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; }
# Everything else goes through the front controller
location / { try_files $uri /index.php$is_args$args; }
location = /index.php {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_pass unix:/run/php/php-fpm.sock; # adapt, for example /run/php/php8.3-fpm.sock
fastcgi_buffering off; # recommended by the guide: AI assistant streaming
fastcgi_read_timeout 300s; # added: long AI requests (60 s by default)
}
# No other PHP script
location ~ \.php$ { return 404; }
}
Three settings deserve an explanation:
client_max_body_size: by default, Nginx refuses requests over 1 MB (error 413), whereas Éclair accepts 20 MB images. Also setupload_max_filesizeandpost_max_sizein PHP-FPM'sphp.ini.fastcgi_buffering off: the AI assistant streams its replies. Éclair already sendsX-Accel-Buffering: no, which Nginx respects by default; the directive covers configurations that ignore it.fastcgi_read_timeout: “Create with AI” replies in one go after 20 to 60 seconds, and Éclair allows itself up to 300 seconds, while Nginx cuts the connection after 60 seconds of silence.
sudo nginx -t && sudo systemctl reload nginx
# Éclair only writes to data/, cache/ and media/
sudo chown -R www-data:www-data /var/www/eclair/data /var/www/eclair/cache /var/www/eclair/media
HTTPS with Certbot, then Éclair's settings
sudo certbot --nginx -d exemple.fr -d www.exemple.fr
Certbot obtains a Let's Encrypt certificate, adds a listener on port 443 to the server block and can redirect HTTP to HTTPS. Then install Éclair by opening https://exemple.fr: the wizard saves the address exactly as you opened it, and already checks Force HTTPS. Next, in the admin:
- Open Security: the site address must be verified. If it isn't, click Verify the site address.
- In Settings › Advanced, make sure Force HTTPS is checked. Éclair refuses to turn it on as long as you're not connected over https.
- Leave Redirect to the official URL checked: a single version of the site, with or without www, as soon as the address is verified.
- Once everything is stable, check HSTS. Éclair then sends
Strict-Transport-Security: max-age=31536000, one year, without subdomains. Browsers will then refuse http:// for your domain, so never turn it on during tests.
Don't add HSTS in Nginx as well, or the header would be sent twice. To manage it in Nginx, uncheck Éclair's option, and remember that an add_header placed in a location block hides those of the server block.
How do you deploy Éclair behind a reverse proxy?
When another server terminates HTTPS (Nginx in front of a container, Caddy, Traefik…), PHP receives HTTP. Éclair considers the connection secure if the HTTPS variable is set, if the port is 443, or if the request carries X-Forwarded-Proto: https or X-Forwarded-SSL: on. The proxy must therefore send X-Forwarded-Proto and keep the Host header, which Éclair compares with its official address.
# Nginx as a reverse proxy in front of Éclair (container published on 127.0.0.1:8080)
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host; # original host, compared with the site address
proxy_set_header X-Forwarded-Proto $scheme; # https, as the visitor sees it
proxy_set_header X-Real-IP $remote_addr; # the visitor's real IP address
proxy_buffering off; # AI assistant streaming
proxy_read_timeout 300s;
client_max_body_size 24m;
}
Behind a proxy, PHP sees the proxy's IP address: the brute-force limits and the form limits would hit every visitor at once. In Settings › Advanced › Site behind a proxy / CDN, choose the header that carries the real address. Éclair only reads it if you've chosen it, and keeps only the last address in X-Forwarded-For, the one added by the nearest proxy.
| Situation | Choice in Éclair |
|---|---|
| no proxy, or address already corrected by Nginx's realip module | No (recommended) |
Nginx as a reverse proxy with proxy_set_header X-Real-IP | X-Real-IP |
a proxy that appends to X-Forwarded-For | X-Forwarded-For |
| Cloudflare in front of the site, with or without a proxy behind it | Cloudflare |
Only choose a header if the site really is behind that service: otherwise, a visitor could set it themselves and get around the limits. Behind Cloudflare, only accept connections coming from the IP addresses published by Cloudflare.
Cloudflare: what to configure
- Encryption: “Full (strict)” SSL/TLS mode, with a real certificate on your server, such as the one from Certbot.
- Firewall and bot protection: let
/_eclair/and/.well-known/through, otherwise Claude and ChatGPT can reach neither the MCP connector nor its authorization. - Cache: static files are already marked for one year. Don't cache the HTML at Cloudflare: Éclair clears its own cache on every publication, not Cloudflare's, and neither the admin nor
/_eclair/must ever end up there. - Options that inject scripts: according to Cloudflare's documentation, Rocket Loader requires
ajax.cloudflare.cominscript-src, and Web Analytics requiresstatic.cloudflareinsights.com. Éclair's CSP only allows scripts from the domain, so leave these options off. - IP address: choose “Cloudflare” in Settings › Advanced › Site behind a proxy / CDN.
How do you deploy Éclair with Docker?
Here is a starting example to adapt, based on the official php:8.3-apache image. It keeps Apache so that Éclair's .htaccess applies as is. Place this Dockerfile next to the unzipped eclair folder.
# Starting example, to adapt: Éclair 1.8 on the official PHP 8.3 + Apache image
FROM php:8.3-apache
# Already in the image: mbstring, json, dom, session, zlib, curl, openssl, sodium, Argon2id.
# To add: gd with JPEG and WebP (images), zip (backups), exif (phone photos turned upright).
RUN apt-get update \
&& apt-get install -y --no-install-recommends libjpeg62-turbo-dev libpng-dev libwebp-dev libzip-dev \
&& docker-php-ext-configure gd --with-jpeg --with-webp \
&& docker-php-ext-install -j"$(nproc)" gd zip exif \
&& rm -rf /var/lib/apt/lists/*
# Modules used by .htaccess: rewriting, headers, compression (no effect if already enabled)
RUN a2enmod rewrite headers deflate
# .htaccess files allowed: the image already does this for /var/www/ (docker-php.conf), we make it explicit
RUN printf '%s\n' '<Directory /var/www/html>' ' AllowOverride All' '</Directory>' \
> /etc/apache2/conf-available/eclair.conf \
&& a2enconf eclair
# Production PHP settings, image uploads up to 20 MB
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" \
&& printf '%s\n' 'upload_max_filesize = 20M' 'post_max_size = 24M' > "$PHP_INI_DIR/conf.d/eclair.ini"
# The contents of the archive's eclair folder, hidden files included
COPY --chown=www-data:www-data eclair/ /var/www/html/
# compose.yaml: persistent data and media, port reserved for the machine's HTTPS proxy
services:
eclair:
build: .
restart: unless-stopped
ports:
- "127.0.0.1:8080:80"
volumes:
- eclair-data:/var/www/html/data
- eclair-media:/var/www/html/media
volumes:
eclair-data:
eclair-media:
docker compose up -d --build starts the site on the machine's port 8080, behind the HTTPS proxy from the previous section. The named volumes keep data/ and media/ from one version to the next: to update, replace the eclair folder with the one from the new archive and rebuild the image. The official image also enables OPcache by default (Dockerfile checked on November 1, 2026).
docker compose exec eclair php -r 'var_dump(function_exists("imagewebp"));' # bool(true)
docker compose exec eclair apache2ctl -M | grep -E 'rewrite|headers|deflate'
Checks after you deploy Éclair
SITE=https://exemple.fr
# 1. Internal files inaccessible: 404 expected for each one
for f in /data/site.php /data/users.php /app/bootstrap.php /cache/runtime.php /data/.htaccess; do
printf '%s %s\n' "$(curl -s -o /dev/null -w '%{http_code}' "$SITE$f")" "$f"
done
# 2. URL rewriting: the controller answers "ok"
curl -s "$SITE/__eclair/ping"; echo
# 3. Static cache: X-Cache: HIT on the second call
curl -sI "$SITE/" > /dev/null; curl -sI "$SITE/" | grep -i x-cache
# 4. MCP connector turned on: 401 and WWW-Authenticate header
curl -si -X POST "$SITE/_eclair/mcp" | grep -i -E '^HTTP|www-authenticate'
Finish in the admin: the Security page must show a green protection test and a verified address, which requires the server to be able to call itself on its public address, even from a container. Finally, upload an image larger than 1 MB in Media and, if the AI assistant is turned on, check that its reply streams in as it's written.
Key points
- Nginx ignores
.htaccess: copy its rules while keeping.well-knownreachable for the MCP connector. - To deploy Éclair properly, allow 20 MB uploads and turn off FastCGI buffering for the AI assistant.
- Behind a proxy, send
X-Forwarded-ProtoandHost, and only choose an IP address header if it really exists. - With Cloudflare: Full (strict) mode,
/_eclair/and/.well-known/open, HTML kept out of the cache, Rocket Loader off. - The Docker example keeps Apache and the original
.htaccess, withdata/andmedia/in volumes.
Going further
- Éclair's architecture: why each
.htaccessrule exists. - Performance: staying at 100 out of 100: measure the site once it's deployed.
- Advanced security and maintenance: file permissions, backups and updates.
- Connect Claude to your site: the MCP connector, which requires HTTPS.
- Nginx: FastCGI module, for
fastcgi_bufferingandfastcgi_read_timeout. - Docker Hub: official php image, its extensions and its
php.ini.
Frequently asked questions
Should I keep the .htaccess files on Nginx?
They're useless on Nginx, but they do no harm and will be useful again if you go back to Apache. It's your Nginx configuration that protects the site.
Why does the AI assistant reply all at once behind Nginx?
A buffer is holding back the stream: check fastcgi_buffering off; in the PHP block, or proxy_buffering off; if Nginx acts as a reverse proxy. The rest of the site isn't affected.
Can Cloudflare cache my HTML pages?
It can, but Éclair will no longer be able to clear that cache on every publication, so your visitors would see old versions. Éclair's static cache already serves pages in a few milliseconds from your server.
Do I need Docker to deploy Éclair?
No. Shared hosting with Apache or LiteSpeed is enough, and so is a VPS with Nginx. Docker is mainly useful to standardize deployments or to isolate several sites on the same machine.