nibula 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eleventy.js CHANGED
@@ -70,7 +70,7 @@ module.exports = function (eleventyConfig) {
70
70
  watch: [`${OUTPUT_DIR}/js/**/*.js`]
71
71
  });
72
72
 
73
- return {
73
+ return {
74
74
  dir: {
75
75
  input: "src/frontend",
76
76
  output: OUTPUT_DIR,
package/CHANGELOG.md CHANGED
@@ -5,6 +5,51 @@ All notable changes to Nibula are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.1] - 2026-08-03
9
+
10
+ ### Added
11
+ - `nginx.conf` header now documents the full setup: package install,
12
+ certificate issuance with `certbot --cert-name`, auto-renew, and the
13
+ `sites-available` → `sites-enabled` steps.
14
+ - Troubleshooting table covering the errors whose message points elsewhere
15
+ than the actual cause: `nginx -t` without sudo, wrong certificate name,
16
+ certificate not covering the domain, nginx < 1.25, missing `404.html`,
17
+ DNS not pointing to the server.
18
+
19
+ ### Changed
20
+ - Certificates are now issued with `--cert-name SITE_NAME`, so the directory
21
+ under `/etc/letsencrypt/live/` matches the site name and `YOUR_CERTIFICATE`
22
+ is easier to fill in.
23
+
24
+ ## [1.4.0] - 2026-08-03
25
+
26
+ ### Changed
27
+ - `nginx.conf` is now a complete, ready-to-use site file instead of a set of
28
+ directives to paste into your own `server` block. Replace three placeholders
29
+ (`YOUR_DOMAIN`, `SITE_FOLDER`, `YOUR_CERTIFICATE`), symlink it into
30
+ `sites-enabled/`, reload.
31
+ - Nginx documentation moved from `docs/Deploy.md` to `docs/Nginx.md`;
32
+ `Deploy.md` now covers only where to publish, one section per server.
33
+
34
+ ### Added
35
+ - HTTP → HTTPS redirect on port 80, with an optional ACME webroot block.
36
+ - TLS setup via Let's Encrypt, with placeholders for the certificate path.
37
+ - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
38
+ `Referrer-Policy`, `Strict-Transport-Security` (`max-age=300` by default).
39
+ - `.php` requests return 404, preventing source-code leaks when php-fpm is
40
+ not configured.
41
+
42
+ ### Removed
43
+ - **Breaking:** the automatic Node → PHP fallback on Nginx. `/api` is now
44
+ proxied to Node only; if the process is down, Nginx returns 502. For a PHP
45
+ deployment, edit the `.php` block and `try_files` as described in
46
+ `docs/Nginx.md`.
47
+
48
+ ### Migration
49
+ Existing Nginx deployments: replace your `server` block with the new
50
+ `nginx.conf` and fill in the three placeholders. If you relied on the PHP
51
+ fallback, follow *Using the PHP backend* in `docs/Nginx.md`.
52
+
8
53
  ## [1.3.0] - 2026-08-01
9
54
 
10
55
  ### Added
package/README.md CHANGED
@@ -43,10 +43,10 @@ Nibula ships with a clean, opinionated layout so beginners are never lost. But i
43
43
 
44
44
  * **Node.js**: v18.0.0 or higher
45
45
  * **Composer** *(only if you choose the PHP backend)*: latest version
46
+ * **Better Nunjucks** — VS Code extension by **Ed Heltzel**
46
47
 
47
48
  ### Recommended
48
49
 
49
- * **Better Nunjucks** — VS Code extension by **Ed Heltzel**
50
50
  * **Material Icon Theme** — VS Code extension by **Philipp Kief**
51
51
 
52
52
  ## 📦 Installation
package/docs/Backend.md CHANGED
@@ -11,7 +11,7 @@ Only the language differs.
11
11
  > | Host | PHP | Node.js |
12
12
  > |---|---|---|
13
13
  > | Apache (shared hosting, VPS) | ✅ | ⚠️ needs a persistent process (VPS only) |
14
- > | Nginx + PHP-FPM (VPS) | ✅ | ✅ (Nginx reverse-proxies to Node) |
14
+ > | Nginx (VPS) | ⚠️ works, but the shipped `nginx.conf` targets Node — needs a manual `fastcgi_pass` block | ✅ (Nginx reverse-proxies to Node) |
15
15
  > | IIS (Windows Server) | ✅ FastCGI | ✅ via ARR reverse proxy |
16
16
  > | Static hosting (Netlify, Vercel, GitHub Pages, Cloudflare Pages) | ❌ | ❌ |
17
17
  >
package/docs/Deploy.md CHANGED
@@ -1,13 +1,8 @@
1
- # Server Configuration
1
+ # Deploy
2
2
 
3
- Nibula builds a static site into your output folder (`out`). To put it online you
4
- upload that folder to a web server. Which server config you need depends on
5
- **where** you publish and **which backend** you chose at scaffold time (PHP or
6
- Node.js — see `docs/Backend.md`).
7
-
8
- The shipped `.htaccess`, `web.config` and `nginx.conf` are written to cover
9
- **both** backends, so you don't swap config files based on your choice. There is
10
- one caveat on Apache/IIS, explained at the end.
3
+ Nibula builds a static site into `out`. To publish it you upload that folder to a
4
+ web server. What you need depends on **where** you publish and **which backend**
5
+ you chose at scaffold time (PHP or Node.js — see `docs/Backend.md`).
11
6
 
12
7
  ## Prerequisites
13
8
 
@@ -15,101 +10,56 @@ one caveat on Apache/IIS, explained at the end.
15
10
  FastCGI) and Composer for the backend dependencies. Works on typical shared
16
11
  hosting.
17
12
 
18
- **Node backend:** Node.js 18+ on the server and the ability to run a
19
- long-running process — i.e. a VPS you control, not typical shared hosting. No PHP
20
- or Composer required.
21
-
22
- ## Where to publish
23
-
24
- ### Shared hosting (Apache — e.g. Aruba, most cPanel providers)
25
-
26
- The most common and beginner-friendly option, and the natural home for the
27
- **PHP** backend (shared hosting can't keep a Node process alive). You rent space
28
- on a server that's already set up and just upload your files.
29
-
30
- Take the **contents of the `out` folder** and upload them to the hosting's public
31
- web root (often `htdocs`, `public_html`, or `www`). That's it — the site is live.
32
- `.htaccess` (Apache) or `web.config` (IIS) are already inside `out` and get picked
33
- up automatically, handling security and routing for you.
34
-
35
- ### Your own server (Nginx — e.g. an Ubuntu VPS)
36
-
37
- If you rent a bare server (a VPS) and install everything yourself, it typically
38
- runs **Nginx** on **Ubuntu Server**. Here nothing is pre-configured: you set up
39
- Nginx, the backend, and the security rules by hand. This is the setup for the
40
- **Node** backend (and also works for PHP + PHP-FPM). The Nginx section below
41
- gives you the essential rules to start from.
13
+ **Node backend:** Node.js 18+ and the ability to run a long-running process —
14
+ i.e. a VPS you control, not typical shared hosting. No PHP or Composer required.
42
15
 
43
16
  ---
44
17
 
45
- ## Apache (`.htaccess`)
46
-
47
- `.htaccess` files at `src/frontend/` and `src/backend/` are copied into the build
48
- output by Eleventy. No setup required — upload `out` and Apache reads them.
49
-
50
- They cover:
51
- - Directory listing disabled
52
- - 403 / 404 → `/404.html`
53
- - Sensitive files blocked (`web.config`, dotfiles, etc.)
54
- - Backend source directory sealed — all access funnels through the front controller
55
- - `/api/*` routing (see the dual-backend note below)
18
+ ## Shared hosting (Apache)
56
19
 
57
- **Dual backend:** if `mod_proxy` is available, `/api` is reverse-proxied to the
58
- Node backend (`127.0.0.1:3000`); if not (typical shared hosting), `/api` is
59
- rewritten to the PHP front controller. To force PHP on a server that *has*
60
- `mod_proxy`, comment the `mod_proxy` block in `.htaccess`.
20
+ The most common option, and the natural home for the **PHP** backend — shared
21
+ hosting can't keep a Node process alive.
61
22
 
62
- ## IIS (`web.config`)
23
+ Upload the **contents of `out`** to the hosting's web root (often `htdocs`,
24
+ `public_html`, or `www`). Done. `.htaccess` is already inside `out` and Apache
25
+ reads it automatically: directory listing off, 403/404 → `/404.html`, sensitive
26
+ files blocked, backend source sealed, `/api/*` routed.
63
27
 
64
- For Windows-based hosting. `web.config` files at `src/frontend/` and
65
- `src/backend/` are copied into the build output by Eleventy and read
66
- automatically — same idea as `.htaccess`, different server.
28
+ **Backend routing:** if `mod_proxy` is available, `/api` is reverse-proxied to
29
+ Node on `127.0.0.1:3000`; if not, `/api` is rewritten to the PHP front
30
+ controller. To force PHP on a proxy-enabled server, comment the `mod_proxy`
31
+ block in `.htaccess`.
67
32
 
68
- **Dual backend:** the `ApiToNode` rewrite rule (requires the ARR + URL Rewrite
69
- modules) reverse-proxies `/api` to Node and wins if present. To use PHP instead,
70
- remove the `ApiToNode` rule; the `ApiToPhp` fallback then rewrites `/api` to the
71
- PHP front controller.
33
+ ## Windows hosting (IIS)
72
34
 
73
- ## Nginx
35
+ Same idea, different server. Upload the contents of `out`; `web.config` is
36
+ already there and read automatically.
74
37
 
75
- Used when you run your **own Ubuntu Server** (a VPS). Unlike Apache and IIS, Nginx
76
- does **not** read per-directory config files, so there's nothing automatic here.
38
+ **Backend routing:** the `ApiToNode` rewrite rule (requires the ARR + URL Rewrite
39
+ modules) reverse-proxies `/api` to Node and wins if present. Remove it to fall
40
+ back to `ApiToPhp`, which rewrites `/api` to the PHP front controller.
77
41
 
78
- **`nginx.conf` in the project root is not a ready-to-use file.** It is a set of
79
- directives you adapt into a complete Nginx `server { }` block — the one that
80
- defines your domain (`server_name`), ports (`listen`), and SSL certificates.
81
- Paste these rules inside your own server block and set `root` to your `out`
82
- folder.
42
+ ## Your own server (Nginx on a VPS)
83
43
 
84
- They provide:
85
- - `server_tokens off` — hides the Nginx version
86
- - `autoindex off` — disables directory listing
87
- - 403 / 404 → `/404.html`
88
- - Backend source directory (`/backend/`) sealed with `return 404`
89
- - Server config files (`.htaccess`, `web.config`) blocked anywhere in the tree
90
- - `/api/*` routed to the backend (see below)
91
- - Security headers on static responses
44
+ The setup for the **Node** backend. Unlike Apache and IIS, Nginx doesn't read
45
+ per-directory config files — the whole site is defined in one file.
92
46
 
93
- **Dual backend (auto-fallback):** the shipped `nginx.conf` sends `/api` to the
94
- Node backend on `127.0.0.1:3000` and, if Node is unreachable (502/504), falls
95
- back automatically to the PHP front controller. So the same config works whether
96
- you deployed Node or PHP — Nginx is the only server that can do this fallback
97
- automatically.
47
+ Nibula ships `nginx.conf` in the project root as a **ready-to-use site file**:
48
+ replace three placeholders, symlink it, reload.
98
49
 
99
- > Setting up Nginx fully (SSL, HTTPS redirect, PHP-FPM and/or the Node service)
100
- > goes beyond these rules. These directives are the security starting point, not
101
- > a complete server setup.
50
+ ```bash
51
+ sudo cp nginx.conf /etc/nginx/sites-available/my-site
52
+ sudo nano /etc/nginx/sites-available/my-site # YOUR_DOMAIN, SITE_FOLDER, YOUR_CERTIFICATE
53
+ sudo ln -s /etc/nginx/sites-available/my-site /etc/nginx/sites-enabled/
54
+ sudo nginx -t && sudo systemctl reload nginx
55
+ ```
102
56
 
103
- ### PHP-FPM socket
57
+ Full reference, requirements and troubleshooting: **`docs/Nginx.md`**.
104
58
 
105
- When using the PHP path, the socket in the `/api` fallback targets Debian/Ubuntu
106
- by default. Check with `ls /run/php/` and adjust:
59
+ ## Static hosting (Netlify, Vercel, GitHub Pages)
107
60
 
108
- | Distro | Path |
109
- |---|---|
110
- | Debian / Ubuntu | `unix:/run/php/php8.3-fpm.sock` |
111
- | RHEL / Fedora | `unix:/run/php-fpm/php-fpm.sock` |
112
- | TCP fallback | `127.0.0.1:9000` |
61
+ Frontend only. Neither backend runs there — no PHP, no persistent process. Fine
62
+ if your site has no `/api` endpoints.
113
63
 
114
64
  ---
115
65
 
@@ -119,49 +69,48 @@ Unlike PHP, the Node backend is **not** executed by the web server per request
119
69
  it is a process you start and keep alive. After uploading your built `out` folder:
120
70
 
121
71
  1. Install the backend's runtime deps (only needed if an endpoint uses the DB):
122
- ```bash
72
+ ```bash
123
73
  cd /var/www/your-site/out/backend
124
74
  npm install
125
- ```
75
+ ```
126
76
 
127
77
  2. Make sure `config.js` exists in `out/backend/` (copy `example.config.js` to
128
78
  `config.js` if missing) and fill in your values.
129
79
 
130
80
  3. Start it — quick test first:
131
- ```bash
81
+ ```bash
132
82
  node _core/index.js
133
83
  # -> [backend-node] listening on http://127.0.0.1:3000 (env: production)
134
- ```
84
+ ```
135
85
  Then, from the server, confirm it answers:
136
- ```bash
86
+ ```bash
137
87
  curl http://127.0.0.1:3000/api/example-public
138
- ```
88
+ ```
139
89
 
140
90
  > Running `node _core/index.js` directly ties the process to your SSH session —
141
- > close the terminal and the backend dies. The recommended way to try it out
142
- > without staying stuck there is **`screen`** (a detachable terminal):
91
+ > close the terminal and the backend dies. To try it out without staying stuck
92
+ > there, use **`screen`** (a detachable terminal):
143
93
  > ```bash
144
94
  > screen -S backend # open a named session
145
95
  > node _core/index.js # start the backend inside it
146
96
  > # press Ctrl+A then D to detach — the backend keeps running
147
97
  > # reattach later with: screen -r backend
148
98
  > ```
149
- > `screen` is perfect for testing and small setups. For a real production
150
- > deployment that also restarts on crash/reboot, prefer **systemd** (step 4).
99
+ > `screen` is fine for testing. For production, prefer **systemd** (step 4).
151
100
 
152
101
  4. To keep it running after logout, use **systemd**. An example unit ships at
153
102
  `backend/backend-node.service.example` — copy it to
154
103
  `/etc/systemd/system/backend-node.service`, adjust `WorkingDirectory` and the
155
104
  `node` path (`which node`), then:
156
- ```bash
105
+ ```bash
157
106
  sudo systemctl daemon-reload
158
107
  sudo systemctl enable --now backend-node
159
108
  sudo systemctl status backend-node
160
- ```
109
+ ```
161
110
  (`pm2` also works: `pm2 start _core/index.js --name backend-node`.)
162
111
 
163
- The web server then reverse-proxies `/api` to this process; with the shipped
164
- `nginx.conf`, if Node is down Nginx falls back to PHP automatically.
112
+ The web server then reverse-proxies `/api` to this process. If Node is down the
113
+ proxy returns 502 — there is no automatic PHP fallback.
165
114
 
166
115
  ### Environment variables
167
116
 
@@ -174,17 +123,13 @@ The web server then reverse-proxies `/api` to this process; with the shipped
174
123
 
175
124
  ---
176
125
 
177
- ## The one caveat on Apache and IIS
126
+ ## One config file, one backend
178
127
 
179
- Nginx can health-check the Node upstream and fall back to PHP automatically.
180
- Apache (`.htaccess`) and IIS (`web.config`) **cannot** — a per-directory config
181
- can't know whether Node is up. So there the routing is decided by configuration,
182
- not at runtime:
128
+ Each server config targets a specific backend, decided at setup time rather than
129
+ at runtime:
183
130
 
184
- - **Apache:** `mod_proxy` present → Node; absent → PHP. Comment the `mod_proxy`
185
- block to force PHP on a proxy-enabled server.
186
- - **IIS:** `ApiToNode` rule present (needs ARR) → Node; remove it to use the
187
- `ApiToPhp` fallback.
131
+ - **Apache:** `mod_proxy` present → Node; absent → PHP
132
+ - **IIS:** `ApiToNode` rule present (needs ARR) → Node; remove it for `ApiToPhp`
133
+ - **Nginx:** ships configured for Node; see `docs/Nginx.md` for PHP
188
134
 
189
- Since a given deployment runs only one backend, this is a one-time setup, not a
190
- per-request concern.
135
+ Since a given deployment runs only one backend, this is a one-time setup.
package/docs/Nginx.md ADDED
@@ -0,0 +1,133 @@
1
+ # Nginx
2
+
3
+ `nginx.conf` in the project root is a **ready-to-use site file** for a Nibula
4
+ site on your own server (a VPS). Replace three placeholders, symlink it, reload.
5
+
6
+ It targets the **Node** backend; see *Using the PHP backend* below for PHP.
7
+
8
+ ## Setup
9
+
10
+ | Placeholder | Value |
11
+ |---|---|
12
+ | `YOUR_DOMAIN` | your domain — appears twice (port 80 and 443) |
13
+ | `SITE_FOLDER` | document root under `/var/www/` — your uploaded `out` folder |
14
+ | `YOUR_CERTIFICATE` | dir name under `/etc/letsencrypt/live/` — **not always equal to the domain**: a cert may be issued for a different hostname (common with DDNS) or cover several domains. Check with `sudo certbot certificates` |
15
+
16
+ ```bash
17
+ sudo cp nginx.conf /etc/nginx/sites-available/my-site
18
+ sudo nano /etc/nginx/sites-available/my-site # replace the placeholders
19
+ sudo ln -s /etc/nginx/sites-available/my-site /etc/nginx/sites-enabled/
20
+ sudo nginx -t && sudo systemctl reload nginx
21
+ ```
22
+
23
+ Verify:
24
+
25
+ ```bash
26
+ curl -I http://YOUR_DOMAIN/ # 301 to https
27
+ curl -I https://YOUR_DOMAIN/ # 200
28
+ curl -I https://YOUR_DOMAIN/nonexistent # 404, not 200 or 500
29
+ ```
30
+
31
+ On RHEL/Alpine there is no `sites-available`; put the file in
32
+ `/etc/nginx/conf.d/` instead.
33
+
34
+ ## Requirements
35
+
36
+ - A valid certificate covering `YOUR_DOMAIN`
37
+ - `404.html` present in the document root and readable by nginx
38
+ - Nginx ≥ 1.25 for `http2 on;` — on older versions use `listen 443 ssl http2;`
39
+
40
+ ## What it provides
41
+
42
+ - HTTP → HTTPS redirect on port 80
43
+ - TLS via Let's Encrypt, with the Certbot SSL options included
44
+ - `server_tokens off` and `autoindex off`
45
+ - 403 / 404 → `/404.html`, preserving the original status code
46
+ - Backend source directory (`/backend/`) sealed with `return 404`
47
+ - `web.config`, dotfiles and `.php` blocked
48
+ - Security headers: `X-Content-Type-Options`, `X-Frame-Options`,
49
+ `Referrer-Policy`, `Strict-Transport-Security`
50
+ - `/api/*` reverse-proxied to the Node backend on `127.0.0.1:3000`
51
+
52
+ ## Certificate renewal
53
+
54
+ The `/.well-known/acme-challenge/` block is only needed with the **webroot**
55
+ authenticator. If you obtained the certificate with `certbot --nginx`, remove it.
56
+ Check with:
57
+
58
+ ```bash
59
+ grep authenticator /etc/letsencrypt/renewal/YOUR_DOMAIN.conf
60
+ ```
61
+
62
+ When adding a domain to an existing certificate, always pass `--cert-name` **and
63
+ list every domain already covered** — omitted ones are dropped, and without the
64
+ flag Certbot creates a separate certificate instead of expanding.
65
+
66
+ ## HSTS
67
+
68
+ The file ships with `max-age=300` deliberately. Browsers cache the HSTS policy
69
+ for the whole `max-age` **even after you remove the header**, so a long value
70
+ combined with a broken certificate locks visitors out with no way back.
71
+
72
+ Raise it to `31536000` once HTTPS is confirmed stable. Add `; includeSubDomains`
73
+ only if every current and future subdomain is served over HTTPS with a valid
74
+ certificate.
75
+
76
+ ## WebSocket
77
+
78
+ Not enabled by default. If your backend uses socket.io or similar, add a map at
79
+ `http` level (e.g. `/etc/nginx/conf.d/websocket.conf`):
80
+
81
+ ```nginx
82
+ map $http_upgrade $connection_upgrade {
83
+ default upgrade;
84
+ '' close;
85
+ }
86
+ ```
87
+
88
+ and inside `location ^~ /api/`:
89
+
90
+ ```nginx
91
+ proxy_set_header Upgrade $http_upgrade;
92
+ proxy_set_header Connection $connection_upgrade;
93
+ ```
94
+
95
+ For long-lived connections also raise `proxy_read_timeout`, ideally in a
96
+ dedicated location for the socket path so normal API requests keep the 60s
97
+ default.
98
+
99
+ ## Using the PHP backend
100
+
101
+ This file targets Node. `.php` requests return 404 by design: without a
102
+ `fastcgi_pass` block Nginx would serve them as plain text and leak source code,
103
+ database credentials included.
104
+
105
+ For a PHP deployment, replace the `.php` block with:
106
+
107
+ ```nginx
108
+ location ~ \.php$ {
109
+ include snippets/fastcgi-php.conf;
110
+ fastcgi_pass unix:/run/php/php8.3-fpm.sock;
111
+ }
112
+ ```
113
+
114
+ and change `try_files` in `location /` to `$uri $uri/ /index.php?$query_string`.
115
+
116
+ Check the socket path with `ls /run/php/`:
117
+
118
+ | Distro | Path |
119
+ |---|---|
120
+ | Debian / Ubuntu | `unix:/run/php/php8.3-fpm.sock` |
121
+ | RHEL / Fedora | `unix:/run/php-fpm/php-fpm.sock` |
122
+ | TCP fallback | `127.0.0.1:9000` |
123
+
124
+ ## Troubleshooting
125
+
126
+ | Symptom | Cause |
127
+ |---|---|
128
+ | `cannot load certificate ... Permission denied` | `nginx -t` run without `sudo` — the certs are root-only |
129
+ | `no alternative certificate subject name matches` | the cert doesn't cover `YOUR_DOMAIN`; check `sudo certbot certificates` |
130
+ | 500 instead of the 404 page | `404.html` missing or unreadable by nginx |
131
+ | `unknown directive "http2"` | Nginx < 1.25 — use `listen 443 ssl http2;` |
132
+ | 502 on `/api/*` | the Node process isn't running; see `docs/Deploy.md` |
133
+ | Site not responding at all | symlink missing in `sites-enabled/`, or nginx not reloaded |
package/nginx.conf CHANGED
@@ -1,75 +1,137 @@
1
- # Example nginx directives for a Nibula site — covers BOTH backends.
1
+ # =============================================================================
2
+ # Nibula — default nginx site configuration
3
+ # Static site + optional HTTP backend on 127.0.0.1:3000. PHP not handled.
4
+ # -----------------------------------------------------------------------------
5
+ # REPLACE
2
6
  #
3
- # /api is served by Node (index.js) if it is running on 127.0.0.1:3000; if Node
4
- # is unreachable, nginx falls back to the PHP front controller automatically.
5
- # So the same config works whether you deployed the Node backend or the PHP one:
6
- # - Node backend running -> Node answers /api
7
- # - only PHP deployed -> Node is down -> falls back to PHP-FPM
7
+ # YOUR_DOMAIN server_name, twice (port 80 and 443)
8
+ # SITE_FOLDER document root under /var/www/
8
9
  #
9
- # This is NOT a ready-to-use file: paste these directives inside your own
10
- # server { } block (the one with server_name, listen and SSL) and set `root`
11
- # to your `out` folder.
10
+ # YOUR_CERTIFICATE dir under /etc/letsencrypt/live/ — not always the sam
11
+ # as YOUR_DOMAIN. Check: sudo certbot certificates
12
+ #
13
+ # SITE_NAME (commands below) name of this file and of the
14
+ # certificate; any short name, never appears in URLs
15
+ #
16
+ #
17
+ # 1. INSTALL (skip if already present)
18
+ # sudo apt update
19
+ # sudo apt install -y nginx certbot python3-certbot-nginx
20
+ # nginx -v # >= 1.25 for the http2 directive
21
+ #
22
+ # 2. CERTIFICATE (before enabling the site — nginx won't start without it)
23
+ # dig +short YOUR_DOMAIN A # must return this server's public IP
24
+ # sudo certbot certonly --nginx --cert-name SITE_NAME -d YOUR_DOMAIN
25
+ # sudo systemctl enable --now certbot.timer # auto-renew every 90 days
26
+ #
27
+ # 3. INSTALL THE SITE
28
+ # sudo cp nginx.conf /etc/nginx/sites-available/SITE_NAME
29
+ # sudo nano /etc/nginx/sites-available/SITE_NAME
30
+ # sudo ln -s /etc/nginx/sites-available/SITE_NAME /etc/nginx/sites-enabled/
31
+ # sudo nginx -t && sudo systemctl reload nginx
32
+ #
33
+ # IF IT FAILS
34
+ # cannot load certificate ... Permission denied → nginx -t needs sudo
35
+ # cannot load certificate ... No such file → wrong certificate name
36
+ # no alternative certificate subject name → cert doesn't cover domain
37
+ # unknown directive "http2" → nginx < 1.25
38
+ # 500 instead of the 404 page → 404.html missing
39
+ # NXDOMAIN / timeout during certbot → DNS not pointing here
40
+ # =============================================================================
12
41
 
13
- # Hide the nginx version from response headers
14
- server_tokens off;
42
+ # HTTP (80) configuration
43
+ server {
15
44
 
16
- # Force HTTPS on future requests (applies site-wide, including /api)
17
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
45
+ server_name YOUR_DOMAIN;
18
46
 
19
- root /var/www/your-site/out;
20
- index index.html;
47
+ listen 80;
48
+ listen [::]:80;
21
49
 
22
- # Disable directory listing
23
- autoindex off;
50
+ # Webroot ACME renewal; drop if using the nginx authenticator.
51
+ location ^~ /.well-known/acme-challenge/ {
52
+ root /var/www/certbot;
53
+ }
24
54
 
25
- error_page 403 404 /404.html;
26
- location = /404.html {
27
- internal;
55
+ location / {
56
+ return 301 https://$host$request_uri;
57
+ }
28
58
  }
29
59
 
30
- # Never expose the backend source directory over HTTP.
31
- location ^~ /backend/ {
32
- return 404;
33
- }
60
+ # HTTPS (443) configuration
61
+ server {
62
+ ### Essentials
63
+ listen 443 ssl;
64
+ listen [::]:443 ssl;
34
65
 
35
- # Block server config files anywhere in the tree (.htaccess, web.config).
36
- location ~* (^|/)(\.htaccess|web\.config)$ {
37
- return 404;
38
- }
66
+ # nginx >= 1.25; older: "listen 443 ssl http2;"
67
+ http2 on;
39
68
 
40
- # --- /api: Node primary, PHP fallback ---------------------------------------
41
- # Try the Node backend first. If it is down (502/504), retry through the PHP
42
- # front controller. Security headers for API responses are set by the backend.
43
- location ^~ /api/ {
44
- proxy_pass http://127.0.0.1:3000;
45
- proxy_http_version 1.1;
46
- proxy_set_header Host $host;
47
- proxy_set_header X-Real-IP $remote_addr;
48
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
49
- proxy_set_header X-Forwarded-Proto $scheme;
50
-
51
- proxy_intercept_errors on;
52
- error_page 502 504 = @php_backend;
53
- }
69
+ server_name YOUR_DOMAIN;
70
+ root /var/www/SITE_FOLDER;
71
+ index index.html;
54
72
 
55
- location @php_backend {
56
- include fastcgi_params;
57
- fastcgi_param SCRIPT_FILENAME $document_root/backend/_core/index.php;
73
+ ### Certificate
74
+ ssl_certificate /etc/letsencrypt/live/YOUR_CERTIFICATE/fullchain.pem;
75
+ ssl_certificate_key /etc/letsencrypt/live/YOUR_CERTIFICATE/privkey.pem;
76
+ include /etc/letsencrypt/options-ssl-nginx.conf;
77
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
58
78
 
59
- # Adjust the PHP-FPM socket to your distro:
60
- # Debian / Ubuntu : unix:/run/php/php8.3-fpm.sock
61
- # RHEL / Fedora : unix:/run/php-fpm/php-fpm.sock
62
- # TCP fallback : 127.0.0.1:9000
63
- fastcgi_pass unix:/run/php/php8.3-fpm.sock;
64
- }
79
+ ### Security headers
80
+ add_header X-Content-Type-Options "nosniff" always;
81
+ add_header X-Frame-Options "SAMEORIGIN" always;
82
+ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
65
83
 
66
- # Serve static files, fall back to the 404 page.
67
- # A location with add_header does not inherit server-level headers,
68
- # so Strict-Transport-Security is repeated here.
69
- location / {
70
- add_header X-Content-Type-Options "nosniff" always;
71
- add_header X-Frame-Options "SAMEORIGIN" always;
72
- add_header Referrer-Policy "strict-origin-when-cross-origin" always;
73
- add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
74
- try_files $uri $uri/ /404.html;
75
- }
84
+ # HSTS persists in browsers for max-age even if removed here. Raise to
85
+ # 31536000 once stable; "; includeSubDomains" needs HTTPS on all subdomains.
86
+ add_header Strict-Transport-Security "max-age=300" always;
87
+
88
+ server_tokens off;
89
+ autoindex off;
90
+
91
+ ### Blocked paths
92
+ error_page 403 404 /404.html;
93
+
94
+ location ^~ /backend/ {
95
+ return 404;
96
+ }
97
+
98
+ location ~* ^/(web\.config)$ {
99
+ return 404;
100
+ }
101
+
102
+ location ~ /\. {
103
+ return 404;
104
+ }
105
+
106
+ # PHP not handled: without php-fpm these would leak source code.
107
+ # For PHP sites, replace this block with fastcgi_pass and change
108
+ # try_files below to: $uri $uri/ /index.php?$query_string
109
+ location ~ \.php$ {
110
+ return 404;
111
+ }
112
+
113
+ ### API backend
114
+ location ^~ /api/ {
115
+ proxy_pass http://127.0.0.1:3000;
116
+ proxy_http_version 1.1;
117
+ proxy_set_header Host $host;
118
+ proxy_set_header X-Real-IP $remote_addr;
119
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
120
+ proxy_set_header X-Forwarded-Proto $scheme;
121
+
122
+ # proxy_read_timeout defaults to 60s; raise only for slow endpoints.
123
+ proxy_connect_timeout 5s;
124
+
125
+ # WebSocket is not enabled; needs a $connection_upgrade map at http level.
126
+ }
127
+
128
+ ### Static files
129
+ location / {
130
+ try_files $uri $uri/ $uri.html =404;
131
+ }
132
+
133
+ ### Error page
134
+ location = /404.html {
135
+ internal;
136
+ }
137
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nibula",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "A beginner-friendly static site generator built on Eleventy that stays close to vanilla HTML, CSS and JS — with a page-management CLI, an optional PHP backend, and SEO files generated for you.",
5
5
  "keywords": [
6
6
  "static-site-generator",