nibula 2.4.3 → 2.4.4
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/CHANGELOG.md +24 -0
- package/README.md +82 -53
- package/package.json +7 -7
- package/src/frontend/components/global/footer.njk +1 -1
- package/src/frontend/components/global/header.njk +1 -1
- package/src/frontend/components/welcome.njk +1 -2
- package/src/frontend/data/site.json +5 -2
- package/src/frontend/indexing/llms.njk +2 -2
- package/src/frontend/layouts/base.njk +5 -4
- package/docs/Assistant CLI.md +0 -70
- package/docs/Backend.md +0 -219
- package/docs/Components.md +0 -236
- package/docs/Creating pages.md +0 -52
- package/docs/Deploy.md +0 -279
- package/docs/Head and SEO.md +0 -198
- package/docs/JavaScript.md +0 -127
- package/docs/Project structure.md +0 -66
- package/docs/Styling with SCSS.md +0 -147
package/docs/Components.md
DELETED
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# Nunjucks (HTML) Components
|
|
2
|
-
|
|
3
|
-
## What is Nunjucks
|
|
4
|
-
|
|
5
|
-
Nunjucks (`.njk`) is an HTML file that supports logic like variables, `if` statements, and `for` loops. It can extend a base layout and include other `.njk` components
|
|
6
|
-
|
|
7
|
-
## Create a component
|
|
8
|
-
|
|
9
|
-
Create a new `.njk` file anywhere inside `src/frontend/components/`. You can organize them into subfolders freely
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
src/frontend/components/
|
|
13
|
-
├── global/
|
|
14
|
-
│ ├── header.njk
|
|
15
|
-
│ └── footer.njk
|
|
16
|
-
├── not-found.njk
|
|
17
|
-
├── welcome.njk
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Include a component
|
|
21
|
-
|
|
22
|
-
Components are included in the page that renders them. Open the page's file in `src/frontend/routes/` and write the includes in its body
|
|
23
|
-
|
|
24
|
-
### example-page.njk <small>(`src/frontend/routes/`)</small>
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
---
|
|
28
|
-
title: "examplePage"
|
|
29
|
-
permalink: "/example-page/"
|
|
30
|
-
layout: base.njk
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
{% include "example-component-1.njk" %}
|
|
34
|
-
{% include "subfolder/example-component-2.njk" %}
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
Components render in the order you list them. If a component lives in a subfolder, specify the relative path accordingly
|
|
38
|
-
|
|
39
|
-
Paths are resolved from `src/frontend/components/`, so you never write that part — `"welcome.njk"`, not `"components/welcome.njk"`
|
|
40
|
-
|
|
41
|
-
> ⚠️ If you move or delete a component, update every route that includes it or the build will fail
|
|
42
|
-
|
|
43
|
-
Writing HTML directly in the route works too, and is perfectly fine for a short page. Components are the recommendation when there is something to reuse or when a page grows past a screenful — not a rule
|
|
44
|
-
|
|
45
|
-
## Nest components
|
|
46
|
-
|
|
47
|
-
A component can include other components. This is useful for breaking complex sections into smaller, reusable pieces.
|
|
48
|
-
|
|
49
|
-
### exampleComponent.njk
|
|
50
|
-
```html
|
|
51
|
-
<section class="hero">
|
|
52
|
-
{% include "hero/hero-title.njk" %}
|
|
53
|
-
{% include "hero/hero-button.njk" %}
|
|
54
|
-
</section>
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
> The same path rules apply: if the included component is in a subfolder, specify the full relative path.
|
|
58
|
-
|
|
59
|
-
## Markdown files
|
|
60
|
-
|
|
61
|
-
### What is Markdown
|
|
62
|
-
|
|
63
|
-
Markdown (`.md`) is a way to write formatted text without HTML tags. You write
|
|
64
|
-
`**bold**` instead of `<strong>bold</strong>`, and a line starting with `-`
|
|
65
|
-
becomes a list item. For a page that is mostly text — an article, a privacy
|
|
66
|
-
policy, a changelog — it is much faster than writing the markup by hand.
|
|
67
|
-
|
|
68
|
-
### Write the file
|
|
69
|
-
|
|
70
|
-
Create a `.md` file in `src/frontend/components/`, next to your `.njk` ones.
|
|
71
|
-
|
|
72
|
-
#### article.md <small>(`src/frontend/components/`)</small>
|
|
73
|
-
|
|
74
|
-
```markdown
|
|
75
|
-
## Section title
|
|
76
|
-
|
|
77
|
-
Regular paragraph text. **Bold** and *italic* work as usual.
|
|
78
|
-
|
|
79
|
-
- First item
|
|
80
|
-
- Second item
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Show it in a page
|
|
84
|
-
|
|
85
|
-
Open the page's file in `src/frontend/routes/` and add this line to its body:
|
|
86
|
-
|
|
87
|
-
```html
|
|
88
|
-
<article class="markdown-body">
|
|
89
|
-
{% renderFile "article.md" | markdownPath, { site: site }, "md" %}
|
|
90
|
-
</article>
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Four parts to it:
|
|
94
|
-
|
|
95
|
-
| Part | What it does |
|
|
96
|
-
|---|---|
|
|
97
|
-
| `class="markdown-body"` | the wrapper that applies the Markdown styling — without it your content renders unstyled |
|
|
98
|
-
| `renderFile` | turns the Markdown into HTML and puts it in the page |
|
|
99
|
-
| `markdownPath` | fills in the `src/frontend/components/` part of the path for you |
|
|
100
|
-
| `{ site: site }` | hands the file your site settings — see below |
|
|
101
|
-
| `"md"` | specifies that the rendering should be done as Markdown, ignoring the njk engine associated by default with the file extension |
|
|
102
|
-
|
|
103
|
-
Subfolders work the same way as with components:
|
|
104
|
-
`"legal/privacy.md" | markdownPath`
|
|
105
|
-
|
|
106
|
-
### Why `{ site: site }`
|
|
107
|
-
|
|
108
|
-
A `.md` file can use site values, exactly like a component:
|
|
109
|
-
|
|
110
|
-
```markdown
|
|
111
|
-
Welcome to {{ site.title }}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
But a Markdown file does not automatically see them. Anything the file needs has
|
|
115
|
-
to be listed in the curly braces:
|
|
116
|
-
|
|
117
|
-
```js
|
|
118
|
-
{% renderFile "article.md" | markdownPath, { site: site, pages: pages } %}
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
If you forget, nothing breaks — the value simply comes out empty. So if a
|
|
122
|
-
`{{ site.something }}` disappears from your page, this is why.
|
|
123
|
-
|
|
124
|
-
### Extras you get for free
|
|
125
|
-
|
|
126
|
-
**Links to a section.** Every `##` and `###` heading gets an anchor, so you can
|
|
127
|
-
link straight to it: `yoursite.com/my-page/#section-title`.
|
|
128
|
-
|
|
129
|
-
**CSS classes.** Markdown produces plain HTML with no classes, so your framework's
|
|
130
|
-
styling doesn't reach it. Add a class in curly braces after the element:
|
|
131
|
-
|
|
132
|
-
```markdown
|
|
133
|
-
## Section title {.text-center}
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
> ⚠️ If the `.md` file is missing or the name is misspelled, the build stops with
|
|
137
|
-
> an error. That is on purpose: silently skipping content you asked for is worse.
|
|
138
|
-
|
|
139
|
-
## Global components
|
|
140
|
-
|
|
141
|
-
Header and footer live in `src/frontend/components/global/` and are automatically included in every page via `base.njk`. Edit them to change the site-wide layout
|
|
142
|
-
|
|
143
|
-
## Custom layouts
|
|
144
|
-
|
|
145
|
-
`base.njk` is the default layout, but it isn't the only one you can have. Any
|
|
146
|
-
`.njk` file in `src/frontend/layouts/` is a layout, and each route picks its own.
|
|
147
|
-
|
|
148
|
-
The usual reason is a page that doesn't fit the standard shell: a landing page
|
|
149
|
-
with no header or footer, a full-screen login, a "coming soon" holding page.
|
|
150
|
-
|
|
151
|
-
Copy `base.njk`, rename it, and change only what you need — that way you keep the
|
|
152
|
-
head, the SEO tags and the CSS/JS wiring, which is the part you don't want to
|
|
153
|
-
rewrite:
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
src/frontend/layouts/
|
|
157
|
-
├── base.njk
|
|
158
|
-
└── custom.njk
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### custom.njk <small>(`src/frontend/layouts/`)</small>
|
|
162
|
-
|
|
163
|
-
Same as `base.njk`, without the two global includes:
|
|
164
|
-
|
|
165
|
-
```html
|
|
166
|
-
<body>
|
|
167
|
-
<main>
|
|
168
|
-
{{ content | safe }}
|
|
169
|
-
</main>
|
|
170
|
-
</body>
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
Then point the route at it:
|
|
174
|
-
|
|
175
|
-
### landing.njk <small>(`src/frontend/routes/`)</small>
|
|
176
|
-
|
|
177
|
-
```js
|
|
178
|
-
---
|
|
179
|
-
title: "landing"
|
|
180
|
-
permalink: "/landing/"
|
|
181
|
-
layout: custom.njk
|
|
182
|
-
---
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Paths are resolved from `src/frontend/layouts/`, so you write `"custom.njk"`, not
|
|
186
|
-
`"layouts/custom.njk"` — the same rule as components.
|
|
187
|
-
|
|
188
|
-
> ⚠️ A layout you copy is a copy: a later fix to `base.njk` won't reach it. Keep
|
|
189
|
-
> the differences to the minimum, and check your custom layouts when you change
|
|
190
|
-
> something in the head.
|
|
191
|
-
|
|
192
|
-
## Site data in components
|
|
193
|
-
|
|
194
|
-
All values defined in `src/frontend/data/site.json` are globally available in every component via `{{ site.* }}`
|
|
195
|
-
|
|
196
|
-
### site.json <small>(`src/frontend/data/`)</small>
|
|
197
|
-
```json
|
|
198
|
-
{
|
|
199
|
-
"site_name": "Site name",
|
|
200
|
-
"title": "Site title",
|
|
201
|
-
"description": "Site description",
|
|
202
|
-
"keywords": "keyword1, keyword2, keyword3",
|
|
203
|
-
"domain": "yoursite.com",
|
|
204
|
-
"url": "https://yoursite.com",
|
|
205
|
-
"lang": "en",
|
|
206
|
-
"author": "Name and surname",
|
|
207
|
-
"logo": "/assets/brand/logo.svg",
|
|
208
|
-
"legal": {
|
|
209
|
-
"privacy": "",
|
|
210
|
-
"cookie": "",
|
|
211
|
-
"terms": "",
|
|
212
|
-
"copyright": {
|
|
213
|
-
"year": "2026",
|
|
214
|
-
"text": "All rights reserved."
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
`legal.privacy`, `legal.cookie` and `legal.terms` hold the URLs of your legal pages — the footer links to them. See **Head & SEO** DOC file for what every field does
|
|
221
|
-
|
|
222
|
-
### Usage in any `.njk` file
|
|
223
|
-
```html
|
|
224
|
-
<p>{{ site.title }}</p>
|
|
225
|
-
<a href="{{ site.legal.privacy }}">Privacy Policy</a>
|
|
226
|
-
<img src="{{ site.logo }}" alt="{{ site.title }}">
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
> In a `.md` file rendered with `renderFile`, these values only work if you passed
|
|
230
|
-
> `site` in the curly braces — see *Why `{ site: site }`* above.
|
|
231
|
-
|
|
232
|
-
## Your own data files
|
|
233
|
-
|
|
234
|
-
`site.json` isn't special: **any** `.json` file you drop in `src/frontend/data/` becomes a global variable, and the variable takes the name of the file.
|
|
235
|
-
|
|
236
|
-
Create `test.json`, put anything you want inside it, and every key is reachable as `test.yourKey` — no import, no configuration, no restart.
|
package/docs/Creating pages.md
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Creating Pages
|
|
2
|
-
|
|
3
|
-
> Examples use JavaScript, but everything applies equally to TypeScript. The only difference is the file extension (`.ts` instead of `.js`), that imports do **not** include the extension, and that paths use `src/frontend/ts/` instead of `src/frontend/js/`.
|
|
4
|
-
|
|
5
|
-
The recommended way is via the **Assistant CLI**
|
|
6
|
-
|
|
7
|
-
## What gets created
|
|
8
|
-
For a page named `my-page`:
|
|
9
|
-
|
|
10
|
-
| File | Purpose |
|
|
11
|
-
|---|---|
|
|
12
|
-
| `src/frontend/routes/my-page.njk` | Template with front matter |
|
|
13
|
-
| `src/frontend/scss/pages/myPage.scss` | Imports framework + modules |
|
|
14
|
-
| `src/frontend/js/pages/myPage.js` | Imports JS/TS modules |
|
|
15
|
-
|
|
16
|
-
It also adds a stub entry in `src/frontend/data/pages.json` for the page's SEO and CDN links — fill it in as described in the **Head & SEO** DOC file.
|
|
17
|
-
|
|
18
|
-
## Adding content
|
|
19
|
-
|
|
20
|
-
The route is created empty, with two commented examples: one for including a
|
|
21
|
-
`.njk` component, one for rendering a `.md` file. Uncomment the one you need or
|
|
22
|
-
write your HTML directly in the body — see the **Components** DOC file.
|
|
23
|
-
|
|
24
|
-
## URL and title
|
|
25
|
-
|
|
26
|
-
The URL is the kebab-case name (`/my-page/`). The `title` in the front matter is camelCase (`myPage`) and is used internally to load the correct CSS and JS files, and to look up the page's record in `pages.json` — do not change it.
|
|
27
|
-
|
|
28
|
-
## Layout
|
|
29
|
-
|
|
30
|
-
`layout` decides the HTML skeleton the page is rendered into. New pages get `base.njk`, which brings the head, the SEO tags, the header and the footer.
|
|
31
|
-
|
|
32
|
-
A page that needs a different shell — a landing page with no header, for instance — points at a layout of its own. See **Components** DOC file, *Custom layouts*.
|
|
33
|
-
|
|
34
|
-
## Subpages (nested URLs)
|
|
35
|
-
|
|
36
|
-
To create a URL like `domain.it/about/team`, edit the `permalink` in `src/frontend/routes/team.njk` and add the parent segment before the final slash:
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
---
|
|
40
|
-
title: "team"
|
|
41
|
-
permalink: "/about/team/"
|
|
42
|
-
layout: base.njk
|
|
43
|
-
---
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
The parent path (`about`) does **not** need to exist as a real page — it's just a URL prefix. Only the last segment (`team`) must match the filename and the `title` in the front matter.
|
|
47
|
-
|
|
48
|
-
| Goal URL | permalink value | File |
|
|
49
|
-
|---|---|---|
|
|
50
|
-
| `/team/` | `/team/` | `routes/team.njk` |
|
|
51
|
-
| `/about/team/` | `/about/team/` | `routes/team.njk` |
|
|
52
|
-
| `/company/about/team/` | `/company/about/team/` | `routes/team.njk` |
|
package/docs/Deploy.md
DELETED
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
# Deploy
|
|
2
|
-
|
|
3
|
-
Nibula builds your finished site into a folder called `out`. Publishing means
|
|
4
|
-
copying that folder onto a web server so people can reach it.
|
|
5
|
-
|
|
6
|
-
How you do that depends on two things: **where** you are publishing, and **which
|
|
7
|
-
backend** you picked when you created the project (see `docs/Backend.md`).
|
|
8
|
-
|
|
9
|
-
## Start here
|
|
10
|
-
|
|
11
|
-
If you don't know which case you are in, answer this first:
|
|
12
|
-
|
|
13
|
-
**Did you choose the PHP backend or the Node backend?**
|
|
14
|
-
|
|
15
|
-
- **PHP** → almost anywhere works, including cheap hosting plans. Jump to
|
|
16
|
-
*Shared hosting* or *Windows hosting*.
|
|
17
|
-
- **Node** → you need a server you control. Jump to *Your own server*.
|
|
18
|
-
- **No `/api` endpoints at all?** Your site is fully static. Anything works,
|
|
19
|
-
including free hosting like Netlify or GitHub Pages.
|
|
20
|
-
|
|
21
|
-
## Why the backend decides everything
|
|
22
|
-
|
|
23
|
-
The two backends run in completely different ways, and this is the one thing
|
|
24
|
-
worth understanding before you pick a host.
|
|
25
|
-
|
|
26
|
-
**PHP** runs **once per visit**. A request arrives, the web server starts PHP,
|
|
27
|
-
PHP answers, PHP exits. Nothing stays running, so there is nothing to look after.
|
|
28
|
-
|
|
29
|
-
**Node is itself a server**. It is a program that must stay running all the time,
|
|
30
|
-
listening in the background, while the web server forwards `/api` requests to it.
|
|
31
|
-
Somebody has to start that program and restart it if the machine reboots or the
|
|
32
|
-
program crashes.
|
|
33
|
-
|
|
34
|
-
That is why **cheap shared hosting cannot run the Node backend**. On plans like
|
|
35
|
-
Aruba or cPanel you upload files into a folder and that's all you can do — there
|
|
36
|
-
is no way to start a program and keep it alive. If that's your host, choose PHP.
|
|
37
|
-
It isn't a limitation of Nibula.
|
|
38
|
-
|
|
39
|
-
> **Shared hosting** means a plan where you share a server with other customers
|
|
40
|
-
> and only get a folder to upload into. **A VPS** is a whole machine that is
|
|
41
|
-
> yours, where you can install and run whatever you want.
|
|
42
|
-
|
|
43
|
-
## Where you can publish
|
|
44
|
-
|
|
45
|
-
| Target | Frontend | PHP backend | Node backend |
|
|
46
|
-
|---|---|---|---|
|
|
47
|
-
| Shared hosting (Apache — Aruba, cPanel) | ✅ | ✅ | ❌ no program can stay running |
|
|
48
|
-
| Windows hosting (IIS) | ✅ | ✅ | ⚠️ only with the ARR module |
|
|
49
|
-
| Your own VPS (Nginx on Ubuntu) | ✅ | ✅ | ✅ |
|
|
50
|
-
| Static hosting (Netlify, Vercel, GitHub Pages) | ✅ | ❌ | ❌ |
|
|
51
|
-
|
|
52
|
-
Static hosting serves files and nothing else. Perfect if your site has no `/api`
|
|
53
|
-
endpoints, unusable if it does.
|
|
54
|
-
|
|
55
|
-
## What you need
|
|
56
|
-
|
|
57
|
-
**PHP backend:** a host with PHP support, and Composer to install the backend's
|
|
58
|
-
dependencies.
|
|
59
|
-
|
|
60
|
-
**Node backend:** Node.js 18 or newer, and command-line access to the server so
|
|
61
|
-
you can start the backend program.
|
|
62
|
-
|
|
63
|
-
## Editing the server config
|
|
64
|
-
|
|
65
|
-
Every server needs a configuration file telling it how to behave — which page to
|
|
66
|
-
show on a 404, which files to keep private, where to send `/api` requests. Nibula
|
|
67
|
-
writes these for you.
|
|
68
|
-
|
|
69
|
-
`.htaccess` (Apache) and `web.config` (IIS) are already inside `out`, ready to
|
|
70
|
-
upload. To change a rule, edit the original in `src/frontend/hosting/` — anything
|
|
71
|
-
you change directly inside `out` is erased the next time you build.
|
|
72
|
-
|
|
73
|
-
`nginx.conf` is different. It sits in your project root and is **not** copied into
|
|
74
|
-
`out`, because Nginx does not read config files from the site folder. You install
|
|
75
|
-
it on the server yourself, as described below.
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## Shared hosting (Apache)
|
|
80
|
-
|
|
81
|
-
Upload **the contents of `out`** — not the folder itself — into your web root.
|
|
82
|
-
Depending on the host it is called `htdocs`, `public_html` or `www`.
|
|
83
|
-
|
|
84
|
-
That's it. `.htaccess` is already in there and Apache reads it automatically:
|
|
85
|
-
folder listings are off, errors show your `/404.html`, sensitive files are
|
|
86
|
-
blocked, the backend source is sealed off, and `/api/*` is routed.
|
|
87
|
-
|
|
88
|
-
**How `/api` gets routed:** if the server has a module called `mod_proxy`, `/api`
|
|
89
|
-
is forwarded to Node. If it doesn't — the usual case on shared hosting — `/api`
|
|
90
|
-
goes to PHP instead. To force PHP on a server that does have `mod_proxy`, comment
|
|
91
|
-
out the `mod_proxy` block in `.htaccess`.
|
|
92
|
-
|
|
93
|
-
## Windows hosting (IIS)
|
|
94
|
-
|
|
95
|
-
Same as above: upload the contents of `out`. `web.config` is already there and
|
|
96
|
-
read automatically.
|
|
97
|
-
|
|
98
|
-
**How `/api` gets routed:** to PHP, by default. To use Node instead, uncomment
|
|
99
|
-
the `ApiToNode` rule in `web.config` and delete `ApiToPhp`. This only works if
|
|
100
|
-
the server has the ARR and URL Rewrite modules with proxying turned on — which
|
|
101
|
-
means a server you control, not shared hosting.
|
|
102
|
-
|
|
103
|
-
> ⚠️ **If you chose Node and your host has no ARR** (Aruba and most Windows
|
|
104
|
-
> shared hosting), do **not** upload the `backend` folder. Without it the static
|
|
105
|
-
> site works fine and `/api/*` simply shows your `404.html`. Upload it and every
|
|
106
|
-
> `/api` request returns an empty 404 instead, because IIS sends the request to
|
|
107
|
-
> the PHP front controller — a file a Node project doesn't have.
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Your own server (Nginx on a VPS)
|
|
112
|
-
|
|
113
|
-
Nginx doesn't read config files from the site folder: the whole site is described
|
|
114
|
-
in one file kept elsewhere on the machine. Nibula ships that file, ready to use,
|
|
115
|
-
as `nginx.conf` in your project root.
|
|
116
|
-
|
|
117
|
-
It **handles both backends with no edits**: `/api` goes to Node, and if Node
|
|
118
|
-
isn't running the request falls through to PHP automatically.
|
|
119
|
-
|
|
120
|
-
Upload the contents of `out` to `/var/www/SITE_FOLDER`, then work through the
|
|
121
|
-
steps below.
|
|
122
|
-
|
|
123
|
-
### 1. Fill in the placeholders
|
|
124
|
-
|
|
125
|
-
Open `nginx.conf` on your computer and replace these four words with your own
|
|
126
|
-
values:
|
|
127
|
-
|
|
128
|
-
| Placeholder | What to put there |
|
|
129
|
-
|---|---|
|
|
130
|
-
| `YOUR_DOMAIN` | your domain — appears twice, once for port 80 and once for 443 |
|
|
131
|
-
| `SITE_FOLDER` | the folder name you used under `/var/www/` |
|
|
132
|
-
| `YOUR_CERTIFICATE` | the folder name under `/etc/letsencrypt/live/` |
|
|
133
|
-
| `SITE_NAME` | the file name you'll use in the commands below — pick anything |
|
|
134
|
-
|
|
135
|
-
### 2. Install what's missing
|
|
136
|
-
|
|
137
|
-
Skip anything already installed.
|
|
138
|
-
|
|
139
|
-
```bash
|
|
140
|
-
sudo apt update
|
|
141
|
-
sudo apt install -y nginx certbot python3-certbot-nginx
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
With the PHP backend, also:
|
|
145
|
-
|
|
146
|
-
```bash
|
|
147
|
-
sudo apt install -y php-fpm
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### 3. Get an HTTPS certificate
|
|
151
|
-
|
|
152
|
-
This is what makes your site load over `https://` instead of `http://`.
|
|
153
|
-
Certificates are free and last 90 days; the second command renews them
|
|
154
|
-
automatically.
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
sudo certbot certonly --nginx --cert-name SITE_NAME -d YOUR_DOMAIN
|
|
158
|
-
sudo systemctl enable --now certbot.timer
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
### 4. Install the site file
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
# Go to the folder where Nginx keeps site files
|
|
165
|
-
cd /etc/nginx/sites-available
|
|
166
|
-
|
|
167
|
-
# Create the file and paste in the contents of your edited nginx.conf
|
|
168
|
-
sudo nano SITE_NAME
|
|
169
|
-
# Paste, then: CTRL + O, ENTER, CTRL + X
|
|
170
|
-
|
|
171
|
-
# Switch the site on by copying it into sites-enabled
|
|
172
|
-
sudo cp SITE_NAME ../sites-enabled/
|
|
173
|
-
|
|
174
|
-
# Check the config for mistakes, then apply it
|
|
175
|
-
sudo nginx -t && sudo systemctl reload nginx
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
If `nginx -t` reports an error, fix it before reloading — Nginx keeps running on
|
|
179
|
-
the old config until the reload succeeds, so your site stays up.
|
|
180
|
-
|
|
181
|
-
### If something goes wrong
|
|
182
|
-
|
|
183
|
-
| What you see | What it usually means |
|
|
184
|
-
|---|---|
|
|
185
|
-
| `cannot load certificate ... Permission denied` | you ran `nginx -t` without `sudo` |
|
|
186
|
-
| `cannot load certificate ... No such file` | wrong certificate name |
|
|
187
|
-
| `no alternative certificate subject name` | the certificate doesn't cover this domain |
|
|
188
|
-
| `unknown directive "http2"` | Nginx older than 1.25 — check with `nginx -v` |
|
|
189
|
-
| NXDOMAIN or a timeout during certbot | your domain's DNS isn't pointing at this server yet |
|
|
190
|
-
| A blank 500 instead of your 404 page | `404.html` is missing from the upload |
|
|
191
|
-
| 502 on `/api`, Node backend | the Node program isn't running |
|
|
192
|
-
| 502 on `/api`, PHP backend | wrong php-fpm socket path in the config |
|
|
193
|
-
|
|
194
|
-
---
|
|
195
|
-
|
|
196
|
-
## Starting the Node backend on the server
|
|
197
|
-
|
|
198
|
-
Only for the Node backend. After uploading `out`:
|
|
199
|
-
|
|
200
|
-
**1. Install its dependencies**
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
cd /var/www/SITE_FOLDER/backend
|
|
204
|
-
npm install
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
**2. Create its config file**
|
|
208
|
-
|
|
209
|
-
Make sure `config.js` exists in `out/backend/`. If it doesn't, copy
|
|
210
|
-
`example.config.js` to `config.js` and fill in your values.
|
|
211
|
-
|
|
212
|
-
**3. Try it out first**
|
|
213
|
-
|
|
214
|
-
`screen` lets you start a program, walk away, and come back to it later. Use it
|
|
215
|
-
to check the backend actually works before setting it up properly.
|
|
216
|
-
|
|
217
|
-
```bash
|
|
218
|
-
screen -S node-backend
|
|
219
|
-
# Inside the new screen:
|
|
220
|
-
sudo node /var/www/SITE_FOLDER/backend/_core/index.js
|
|
221
|
-
curl http://127.0.0.1:3000/api/example-public
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
If `curl` prints a JSON response, the backend is alive. Press `CTRL + A` then `D`
|
|
225
|
-
to leave the screen without stopping the program; `screen -r node-backend` brings
|
|
226
|
-
you back.
|
|
227
|
-
|
|
228
|
-
**4. Then set it up for real**
|
|
229
|
-
|
|
230
|
-
`screen` is for testing — the program dies if the server reboots. For a live site
|
|
231
|
-
use **systemd**, the part of Linux that manages background programs. It starts
|
|
232
|
-
your backend at boot and restarts it if it crashes.
|
|
233
|
-
|
|
234
|
-
Create `/etc/systemd/system/backend-node.service`:
|
|
235
|
-
|
|
236
|
-
```ini
|
|
237
|
-
[Unit]
|
|
238
|
-
Description=Nibula Node backend
|
|
239
|
-
After=network.target
|
|
240
|
-
|
|
241
|
-
[Service]
|
|
242
|
-
Type=simple
|
|
243
|
-
User=www-data
|
|
244
|
-
WorkingDirectory=/var/www/SITE_FOLDER/backend
|
|
245
|
-
ExecStart=/usr/bin/node /var/www/SITE_FOLDER/backend/_core/index.js
|
|
246
|
-
Restart=always
|
|
247
|
-
RestartSec=5
|
|
248
|
-
|
|
249
|
-
[Install]
|
|
250
|
-
WantedBy=multi-user.target
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
Adjust `WorkingDirectory`, and check the path to `node` with `which node`. Then:
|
|
254
|
-
|
|
255
|
-
```bash
|
|
256
|
-
sudo systemctl daemon-reload
|
|
257
|
-
sudo systemctl enable --now backend-node
|
|
258
|
-
sudo systemctl status backend-node
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
The last command should say `active (running)`.
|
|
262
|
-
|
|
263
|
-
(If you already use `pm2`, that works too:
|
|
264
|
-
`pm2 start _core/index.js --name backend-node`.)
|
|
265
|
-
|
|
266
|
-
### Settings the Node backend reads at startup
|
|
267
|
-
|
|
268
|
-
These are set in the systemd file, on their own lines, as
|
|
269
|
-
`Environment=KEY=value`. All three have sensible defaults — you usually don't
|
|
270
|
-
need to touch them.
|
|
271
|
-
|
|
272
|
-
| Setting | Default | What it does |
|
|
273
|
-
|---|---|---|
|
|
274
|
-
| `PORT` | `3000` | the port Node listens on — must match the one in `nginx.conf` |
|
|
275
|
-
| `HOST` | `127.0.0.1` | keep this as-is: it means "local only", so Node is reachable through the web server and not directly from the internet |
|
|
276
|
-
| `DOCUMENT_ROOT` | detected automatically | where `404.html` lives — the folder above `backend/` |
|
|
277
|
-
|
|
278
|
-
> Error detail is **not** set here. That's the `APP_ENV` key inside `config.js` /
|
|
279
|
-
> `config.php` — see `docs/Backend.md`.
|