@twin.org/node 0.0.3-next.10
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/LICENSE +201 -0
- package/README.md +43 -0
- package/bin/index.js +4 -0
- package/dist/locales/en.json +1885 -0
- package/docs/changelog.md +742 -0
- package/docs/configuration.md +223 -0
- package/docs/deployment-docker.md +189 -0
- package/docs/deployment-ec2.md +193 -0
- package/docs/deployment.md +4 -0
- package/docs/examples.md +149 -0
- package/docs/open-api/spec.json +19808 -0
- package/locales/en.json +1 -0
- package/package.json +40 -0
- package/src/index.js +12 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# @twin.org/node - Configuration
|
|
2
|
+
|
|
3
|
+
## Extension Loading
|
|
4
|
+
|
|
5
|
+
The TWIN Node supports loading extensions dynamically to extend its functionality. Extensions can be loaded from multiple sources using protocol-based syntax.
|
|
6
|
+
|
|
7
|
+
### Extension Loading Syntax
|
|
8
|
+
|
|
9
|
+
Extensions are configured via the `TWIN_EXTENSIONS` environment variable. Multiple extensions can be specified as a comma-separated list.
|
|
10
|
+
|
|
11
|
+
#### Local File Extensions
|
|
12
|
+
|
|
13
|
+
Load extensions from the local filesystem:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Relative path
|
|
17
|
+
TWIN_EXTENSIONS="./my-extension.mjs"
|
|
18
|
+
|
|
19
|
+
# Absolute path
|
|
20
|
+
TWIN_EXTENSIONS="/path/to/extension.mjs"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
#### NPM Package Extensions
|
|
24
|
+
|
|
25
|
+
Load extensions from npm packages. The package will be automatically downloaded and installed if not already cached:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Basic npm package
|
|
29
|
+
TWIN_EXTENSIONS="npm:@twin.org/identity-management-service"
|
|
30
|
+
|
|
31
|
+
# Scoped package
|
|
32
|
+
TWIN_EXTENSIONS="npm:@org/custom-extension"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Note:** Version pinning (e.g., `npm:@twin.org/pkg@1.2.3`) is planned for a future release. Currently, the latest version is installed.
|
|
36
|
+
|
|
37
|
+
#### HTTPS URL Extensions
|
|
38
|
+
|
|
39
|
+
Load extensions from remote HTTPS URLs:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
TWIN_EXTENSIONS="https://example.twin.org/extensions/my-module.mjs"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**⚠️ SECURITY WARNING:** Loading code from HTTPS URLs introduces security risks. Only load extensions from trusted sources that you control or verify.
|
|
46
|
+
|
|
47
|
+
Security features:
|
|
48
|
+
|
|
49
|
+
- Only HTTPS is allowed (HTTP is rejected)
|
|
50
|
+
- Default 10 MB size limit to prevent DoS attacks
|
|
51
|
+
- Downloaded modules are cached locally
|
|
52
|
+
- Security warning is displayed when loading
|
|
53
|
+
|
|
54
|
+
#### Multiple Extensions
|
|
55
|
+
|
|
56
|
+
Load multiple extensions from different sources:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
TWIN_EXTENSIONS="@twin.org/identity-management-service,npm:@twin.org/custom-service,./local-extension.mjs,https://example.com/remote.mjs"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Extension Configuration Options
|
|
63
|
+
|
|
64
|
+
#### Maximum Download Size
|
|
65
|
+
|
|
66
|
+
Configure the maximum size (in MB) for HTTPS extension downloads:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
TWIN_EXTENSIONS_MAX_SIZE_MB=10 # Default is 10 MB
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
#### Cache Management
|
|
73
|
+
|
|
74
|
+
By default, downloaded extensions are cached in `.tmp/extensions/` directory to speed up subsequent startups. To clear the cache on each startup:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
TWIN_EXTENSIONS_CLEAR_CACHE=true # Default is false
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### Custom Cache Directory
|
|
81
|
+
|
|
82
|
+
You can configure a custom directory for extension caching:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
TWIN_EXTENSIONS_CACHE_DIRECTORY="cache" # Default is ".tmp"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This allows you to:
|
|
89
|
+
|
|
90
|
+
- Use a dedicated partition with more space
|
|
91
|
+
- Separate cache by environment (dev/staging/prod)
|
|
92
|
+
- Follow corporate storage policies
|
|
93
|
+
- Create persistent cache directories for better performance
|
|
94
|
+
|
|
95
|
+
### Extension API
|
|
96
|
+
|
|
97
|
+
Extensions must export specific lifecycle methods to integrate with the node:
|
|
98
|
+
|
|
99
|
+
#### `extensionInitialise(envVars, nodeEngineConfig)`
|
|
100
|
+
|
|
101
|
+
Called during configuration phase. Allows the extension to modify environment variables and engine configuration.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
export async function extensionInitialise(
|
|
105
|
+
envVars: INodeEnvironmentVariables,
|
|
106
|
+
nodeEngineConfig: INodeEngineConfig
|
|
107
|
+
): Promise<void> {
|
|
108
|
+
// Modify configuration here
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### `extensionInitialiseEngine(engineCore)`
|
|
113
|
+
|
|
114
|
+
Called after the engine is created but before the server starts.
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
export async function extensionInitialiseEngine(engineCore: IEngineCore): Promise<void> {
|
|
118
|
+
// Register components, set up services, etc.
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### `extensionInitialiseEngineServer(engineCore, engineServer)`
|
|
123
|
+
|
|
124
|
+
Called after the engine server is created but before it starts listening.
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
export async function extensionInitialiseEngineServer(
|
|
128
|
+
engineCore: IEngineCore,
|
|
129
|
+
engineServer: IEngineServer
|
|
130
|
+
): Promise<void> {
|
|
131
|
+
// Add routes, configure server, etc.
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### `extensionShutdown()`
|
|
136
|
+
|
|
137
|
+
Called when the node is shutting down. Clean up resources here.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
export async function extensionShutdown(): Promise<void> {
|
|
141
|
+
// Clean up resources
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Example Extension
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// my-extension.mjs
|
|
149
|
+
export async function extensionInitialise(envVars, nodeEngineConfig) {
|
|
150
|
+
console.log('Extension initializing with config');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export async function extensionInitialiseEngine(engineCore) {
|
|
154
|
+
engineCore.logInfo('Custom extension loaded');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function extensionInitialiseEngineServer(engineCore, engineServer) {
|
|
158
|
+
// Add custom routes
|
|
159
|
+
engineServer.addRestRoute({
|
|
160
|
+
path: '/custom/endpoint',
|
|
161
|
+
method: 'GET',
|
|
162
|
+
handler: async () => ({ body: { message: 'Hello from extension!' } })
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export async function extensionShutdown() {
|
|
167
|
+
console.log('Extension shutting down');
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Cache Directory Structure
|
|
172
|
+
|
|
173
|
+
Downloaded extensions are stored in:
|
|
174
|
+
|
|
175
|
+
```text
|
|
176
|
+
<execution-directory>/<cache-directory>/extensions/
|
|
177
|
+
├── npm/ # NPM packages
|
|
178
|
+
│ └── node_modules/
|
|
179
|
+
│ └── @twin.org/...
|
|
180
|
+
└── https/ # HTTPS downloads
|
|
181
|
+
└── <hashed-filename>.mjs
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Where `<cache-directory>` is:
|
|
185
|
+
|
|
186
|
+
- `.tmp` by default
|
|
187
|
+
- Configurable via `TWIN_EXTENSIONS_CACHE_DIRECTORY`
|
|
188
|
+
|
|
189
|
+
Examples:
|
|
190
|
+
|
|
191
|
+
- Default: `./.tmp/extensions/`
|
|
192
|
+
- Custom: `./cache/extensions/` (if `TWIN_EXTENSIONS_CACHE_DIRECTORY="cache"`)
|
|
193
|
+
- Absolute: `/var/cache/twin-node/extensions/` (if `TWIN_EXTENSIONS_CACHE_DIRECTORY="/var/cache/twin-node"`)
|
|
194
|
+
|
|
195
|
+
### Security Best Practices
|
|
196
|
+
|
|
197
|
+
1. **Prefer npm: protocol** over https: for third-party extensions (npm has package verification and malware scanning)
|
|
198
|
+
2. **Use local files** (`./extension.mjs`) for maximum security and control
|
|
199
|
+
3. **Verify HTTPS sources** before using - only load from domains you trust
|
|
200
|
+
4. **Review extension code** before deployment, especially for HTTPS sources
|
|
201
|
+
5. **Monitor cache directory** - review what's been downloaded to `.tmp/extensions/`
|
|
202
|
+
6. **Use environment-specific configuration** - different extensions for dev/staging/prod
|
|
203
|
+
|
|
204
|
+
### Troubleshooting
|
|
205
|
+
|
|
206
|
+
#### Extension fails to load
|
|
207
|
+
|
|
208
|
+
- Check that npm is installed and accessible in PATH (required for npm: protocol)
|
|
209
|
+
- Verify the extension file/URL is accessible
|
|
210
|
+
- Check `.tmp/extensions/` cache for partially downloaded files
|
|
211
|
+
- Review node logs for specific error messages
|
|
212
|
+
|
|
213
|
+
#### Clear extension cache manually
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
rm -rf .tmp/extensions
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
#### NPM package not found
|
|
220
|
+
|
|
221
|
+
- Verify the package name is correct
|
|
222
|
+
- Check network connectivity
|
|
223
|
+
- Ensure npm registry is accessible
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# @twin.org/node - Deployment Docker
|
|
2
|
+
|
|
3
|
+
## Docker Building
|
|
4
|
+
|
|
5
|
+
To run the API server in the docker environment there is an example dockerfile in `deploy/dockerfile`:
|
|
6
|
+
|
|
7
|
+
```shell
|
|
8
|
+
# Set the base image
|
|
9
|
+
FROM node:22
|
|
10
|
+
|
|
11
|
+
# Create the app directory
|
|
12
|
+
WORKDIR /app
|
|
13
|
+
|
|
14
|
+
# Copy the package.json
|
|
15
|
+
COPY package.json .
|
|
16
|
+
|
|
17
|
+
# Install dependencies including dev dependencies needed for merge-locales
|
|
18
|
+
RUN npm install --ignore-scripts
|
|
19
|
+
|
|
20
|
+
# Copy the rest of the files to the image
|
|
21
|
+
COPY . .
|
|
22
|
+
|
|
23
|
+
# Compile translation messages
|
|
24
|
+
RUN npm run merge-locales
|
|
25
|
+
|
|
26
|
+
# Remove dev dependencies to reduce image size
|
|
27
|
+
RUN npm prune --omit=dev
|
|
28
|
+
|
|
29
|
+
# Expose the port the app runs on
|
|
30
|
+
EXPOSE 3000
|
|
31
|
+
|
|
32
|
+
# Set the environment variables that will override the .env file in the package
|
|
33
|
+
ENV TWIN_HOST=0.0.0.0
|
|
34
|
+
ENV TWIN_PORT=3000
|
|
35
|
+
ENV TWIN_STORAGE_FILE_ROOT=/twin-node/data
|
|
36
|
+
|
|
37
|
+
# Start the server
|
|
38
|
+
CMD ["node", "src/index.mjs"]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You can build and execute this using docker from the root of the package with the following command.
|
|
42
|
+
|
|
43
|
+
```shell
|
|
44
|
+
docker build -t twin-node -f deploy/dockerfile . --load
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> **Note**: The `--load` flag is required when using Docker Buildx to ensure the image is loaded into your local Docker registry. Without it, the image will only exist in the build cache.
|
|
48
|
+
|
|
49
|
+
This will build and deploy an image called `twin-node` to your local docker server.
|
|
50
|
+
|
|
51
|
+
## Bootstrapping
|
|
52
|
+
|
|
53
|
+
Whenever the server starts it bootstraps all the components. If you have any entity storage configured to use `file` storage you should map a directory on the local host to contain the data, so that it remains persistent.
|
|
54
|
+
|
|
55
|
+
```shell
|
|
56
|
+
docker run -t -i -v /home/twin-node/data:/twin-node/data -p 3000:3000 twin-node
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
This example will map the local directory `/home/twin-node/data` and make it available in the docker container as `/twin-node/data` which is used to configure file entity storage using the environment variable `TWIN_STORAGE_FILE_ROOT`.
|
|
60
|
+
|
|
61
|
+
The output from the docker container should be something like the following.
|
|
62
|
+
|
|
63
|
+
```shell
|
|
64
|
+
🌩️ TWIN Node Server v1.0.0
|
|
65
|
+
|
|
66
|
+
Execution Directory: /app
|
|
67
|
+
Locales Directory: /app/dist/locales
|
|
68
|
+
Locales File: /app/dist/locales/en.json
|
|
69
|
+
OpenAPI Spec File: /app/docs/open-api/spec.json
|
|
70
|
+
Favicon File: /app/static/favicon.ico
|
|
71
|
+
Environment Variable Prefix: TWIN_
|
|
72
|
+
Default Environment File: /app/.env
|
|
73
|
+
|
|
74
|
+
INFO [2025-10-03T01:23:42.634Z] EngineCore Engine is starting
|
|
75
|
+
INFO [2025-10-03T01:23:42.635Z] EngineCore Debugging is enabled
|
|
76
|
+
INFO [2025-10-03T01:23:42.636Z] EngineCore Loading state from file storage with filename "twin-node/data/engine-state.json"
|
|
77
|
+
INFO [2025-10-03T01:23:42.637Z] EngineCore Configuring loggingConnector: console
|
|
78
|
+
INFO [2025-10-03T01:23:42.637Z] EngineCore Configuring loggingConnector: entity-storage
|
|
79
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring Entity Storage with name "log-entry" using "file" connector
|
|
80
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring loggingConnector: multi
|
|
81
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring loggingComponent: service
|
|
82
|
+
...
|
|
83
|
+
INFO [2025-10-03T01:23:42.655Z] EngineCore Bootstrap started
|
|
84
|
+
...
|
|
85
|
+
INFO [2025-10-03T01:23:42.662Z] EngineCore Generating mnemonic "weird focus prevent jewel enemy reveal supply dove then swallow topple goose case over endless garage width panic learn ask close fault immune shadow"
|
|
86
|
+
INFO [2025-10-03T01:23:42.662Z] EngineCore Storing mnemonic
|
|
87
|
+
INFO [2025-10-03T01:23:43.912Z] EngineCore Funding wallet "https://explorer.iota.org/address/0x69d531810657960fa07d346cb9bb7003e016e38c0b7486607002a10990ea0dd9?network=testnet"
|
|
88
|
+
INFO [2025-10-03T01:23:46.547Z] EngineCore Generating node identity
|
|
89
|
+
INFO [2025-10-03T01:23:49.584Z] EngineCore Node identity created "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
90
|
+
INFO [2025-10-03T01:23:49.585Z] EngineCore Identity explorer "https://explorer.iota.org/object/0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82?network=testnet"
|
|
91
|
+
INFO [2025-10-03T01:23:49.595Z] EngineCore Node identity "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
92
|
+
INFO [2025-10-03T01:23:49.596Z] EngineCore Creating node user "admin@node"
|
|
93
|
+
INFO [2025-10-03T01:23:49.597Z] EngineCore Node Admin User Email "admin@node"
|
|
94
|
+
INFO [2025-10-03T01:23:49.597Z] EngineCore Node Admin User Password "ayc^YC31TF%BVshQ"
|
|
95
|
+
INFO [2025-10-03T01:23:49.600Z] EngineCore Creating user profile "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
96
|
+
INFO [2025-10-03T01:23:49.601Z] EngineCore Creating authentication key "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82/auth-signing"
|
|
97
|
+
INFO [2025-10-03T01:23:49.617Z] EngineCore Creating blob encryption key "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82/blob-encryption"
|
|
98
|
+
INFO [2025-10-03T01:23:49.624Z] EngineCore Created blob encryption key "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82/blob-encryption" with value "4+S7bupEk/vLVhGxjKJ3jWw3uKo+3JsF8wYoB5B59bc="
|
|
99
|
+
INFO [2025-10-03T01:23:50.314Z] EngineCore Adding attestation verification method "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82#attestation-assertion"
|
|
100
|
+
INFO [2025-10-03T01:23:56.408Z] EngineCore Adding immutable proof verification method "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82#immutable-proof-assertion"
|
|
101
|
+
INFO [2025-10-03T01:24:01.772Z] EngineCore Bootstrap complete
|
|
102
|
+
INFO [2025-10-03T01:24:01.773Z] EngineCore Components are starting
|
|
103
|
+
...
|
|
104
|
+
INFO [2025-10-03T01:24:02.476Z] EngineCore Components have started
|
|
105
|
+
INFO [2025-10-03T01:24:02.476Z] EngineCore Engine has started
|
|
106
|
+
INFO [2025-10-03T01:24:02.477Z] EngineCore Saving state to file storage with filename "twin-node/data/engine-state.json"
|
|
107
|
+
INFO [2025-10-03T01:24:02.496Z] FastifyWebServer Building Web Server
|
|
108
|
+
...
|
|
109
|
+
INFO [2025-10-03T01:24:03.111Z] FastifyWebServer Starting Web Server at address "0.0.0.0" on port "3000"
|
|
110
|
+
INFO [2025-10-03T01:24:03.128Z] FastifyWebServer The Web Server started on http://0.0.0.0:3000
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
You will see it generated a node admin user with password for future use, these should be recorded as they will not be made visible again.
|
|
114
|
+
|
|
115
|
+
To run the bootstrap again you would have to manually remove the `engine-state.json` from the data directory.
|
|
116
|
+
|
|
117
|
+
## Docker Running
|
|
118
|
+
|
|
119
|
+
To run the server we use exactly the same command as before, when the `engine-state.json` exists the component states are passed in to the components.
|
|
120
|
+
|
|
121
|
+
```shell
|
|
122
|
+
docker run -t -i -v /home/twin-node/data:/twin-node/data -p 3000:3000 twin-node
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
You should now see output similar to the following:
|
|
126
|
+
|
|
127
|
+
```shell
|
|
128
|
+
🌩️ TWIN Node Server v1.0.0
|
|
129
|
+
|
|
130
|
+
Execution Directory: /app
|
|
131
|
+
Locales Directory: /app/dist/locales
|
|
132
|
+
Locales File: /app/dist/locales/en.json
|
|
133
|
+
OpenAPI Spec File: /app/docs/open-api/spec.json
|
|
134
|
+
Favicon File: /app/static/favicon.ico
|
|
135
|
+
Environment Variable Prefix: TWIN_
|
|
136
|
+
Default Environment File: /app/.env
|
|
137
|
+
|
|
138
|
+
INFO [2025-10-03T01:23:42.634Z] EngineCore Engine is starting
|
|
139
|
+
INFO [2025-10-03T01:23:42.635Z] EngineCore Debugging is enabled
|
|
140
|
+
INFO [2025-10-03T01:23:42.636Z] EngineCore Loading state from file storage with filename "twin-node/data/engine-state.json"
|
|
141
|
+
INFO [2025-10-03T01:23:42.637Z] EngineCore Configuring loggingConnector: console
|
|
142
|
+
INFO [2025-10-03T01:23:42.637Z] EngineCore Configuring loggingConnector: entity-storage
|
|
143
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring Entity Storage with name "log-entry" using "file" connector
|
|
144
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring loggingConnector: multi
|
|
145
|
+
INFO [2025-10-03T01:23:42.638Z] EngineCore Configuring loggingComponent: service
|
|
146
|
+
...
|
|
147
|
+
INFO [2025-10-03T01:23:42.655Z] EngineCore Bootstrap started
|
|
148
|
+
...
|
|
149
|
+
INFO [2025-10-03T01:27:34.331Z] EngineCore Wallet already funded
|
|
150
|
+
INFO [2025-10-03T01:27:35.064Z] EngineCore Node identity already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
151
|
+
INFO [2025-10-03T01:27:35.065Z] EngineCore Identity explorer "https://explorer.iota.org/object/0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82?network=testnet"
|
|
152
|
+
INFO [2025-10-03T01:27:35.065Z] EngineCore Node identity "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
153
|
+
INFO [2025-10-03T01:27:35.066Z] EngineCore Node user already exists "admin@node"
|
|
154
|
+
INFO [2025-10-03T01:27:35.066Z] EngineCore User profile already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82"
|
|
155
|
+
INFO [2025-10-03T01:27:35.067Z] EngineCore Authentication key already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82/auth-signing"
|
|
156
|
+
INFO [2025-10-03T01:27:35.067Z] EngineCore Blob encryption key already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82/blob-encryption"
|
|
157
|
+
INFO [2025-10-03T01:27:35.807Z] EngineCore Verification method for attestation already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82#attestation-assertion"
|
|
158
|
+
INFO [2025-10-03T01:27:36.512Z] EngineCore Verification method for immutable proof already exists "did:iota:testnet:0xc7aa88cd54c8c90fc1cbe5927b3e2fe33d478ca7b6b058020c0d87e8f88fac82#immutable-proof-assertion"
|
|
159
|
+
INFO [2025-10-03T01:27:36.512Z] EngineCore Bootstrap complete
|
|
160
|
+
INFO [2025-10-03T01:24:01.773Z] EngineCore Components are starting
|
|
161
|
+
...
|
|
162
|
+
INFO [2025-10-03T01:24:02.476Z] EngineCore Components have started
|
|
163
|
+
INFO [2025-10-03T01:24:02.476Z] EngineCore Engine has started
|
|
164
|
+
INFO [2025-10-03T01:24:02.477Z] EngineCore Saving state to file storage with filename "twin-node/data/engine-state.json"
|
|
165
|
+
INFO [2025-10-03T01:24:02.496Z] FastifyWebServer Building Web Server
|
|
166
|
+
...
|
|
167
|
+
INFO [2025-10-03T01:24:03.111Z] FastifyWebServer Starting Web Server at address "0.0.0.0" on port "3000"
|
|
168
|
+
INFO [2025-10-03T01:24:03.128Z] FastifyWebServer The Web Server started on http://0.0.0.0:3000
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
You should now be able to access the server in the browser [http://localhost:3000/info](http://localhost:3000/info).
|
|
172
|
+
|
|
173
|
+
On successfully communicating with the server you should see something similar to the following returned from the request:
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
{
|
|
177
|
+
"name": "TWIN Node Server",
|
|
178
|
+
"version": "1.0.0"
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
The logging in the docker container should also show the request and response.
|
|
183
|
+
|
|
184
|
+
```shell
|
|
185
|
+
INFO [2024-07-24T08:46:25.283Z] ===> GET /info
|
|
186
|
+
INFO [2024-07-24T08:46:25.287Z] <=== 200 GET /info duration: 3987µs {"name":"TWIN Node Server","version":"1.0.0"}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The API server responds to the correct terminate signals so that when the docker container is stopped the server will also stop gracefully.
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @twin.org/node - Deployment Amazon AWS EC2
|
|
2
|
+
|
|
3
|
+
## Amazon AWS EC2 Instance
|
|
4
|
+
|
|
5
|
+
To run the server on an AWS EC2 instance follow the steps below:
|
|
6
|
+
|
|
7
|
+
First follow one of the many online guides to create your EC2 instance with the ability to connect to it in terminal mode.
|
|
8
|
+
|
|
9
|
+
Network requirements are for the `https` port to be open to any address range i.e. `0.0.0.0`.
|
|
10
|
+
|
|
11
|
+
You should alias a domain name to the IP address of the instance e.g. `twin-node-api.example.com` using your DNS provider e.g. Cloudflare.
|
|
12
|
+
|
|
13
|
+
## Install Git
|
|
14
|
+
|
|
15
|
+
For retrieving the code from the repo.
|
|
16
|
+
|
|
17
|
+
```shell
|
|
18
|
+
sudo yum install git -y
|
|
19
|
+
git -version
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Install NVM and Node
|
|
23
|
+
|
|
24
|
+
For building and running the application.
|
|
25
|
+
|
|
26
|
+
```shell
|
|
27
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
|
|
28
|
+
nvm install 20
|
|
29
|
+
node -v
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Install nginx
|
|
33
|
+
|
|
34
|
+
To serve the app through an https reverse proxy.
|
|
35
|
+
|
|
36
|
+
```shell
|
|
37
|
+
sudo yum install nginx -y
|
|
38
|
+
nginx -v
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuring nginx
|
|
42
|
+
|
|
43
|
+
We need to configure nginx to use the certificate and reverse proxy https traffic to the node server.
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
sudo nano /etc/nginx/nginx.conf
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The configuration should be along the lines of:
|
|
50
|
+
|
|
51
|
+
```shell
|
|
52
|
+
server {
|
|
53
|
+
listen 80;
|
|
54
|
+
server_name twin-node-api.example.com;
|
|
55
|
+
|
|
56
|
+
# Redirect all traffic
|
|
57
|
+
return 301 https://$server_name$request_uri;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
server {
|
|
61
|
+
listen [::]:443 ssl ipv6only=on;
|
|
62
|
+
listen 443 ssl;
|
|
63
|
+
|
|
64
|
+
server_name twin-node-api.example.com;
|
|
65
|
+
|
|
66
|
+
ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
|
|
67
|
+
ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
|
|
68
|
+
|
|
69
|
+
location / {
|
|
70
|
+
# Redirect the https traffic to the node instance
|
|
71
|
+
proxy_pass http://localhost:3000;
|
|
72
|
+
proxy_set_header Host $host;
|
|
73
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
74
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
75
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
location /socket {
|
|
79
|
+
# Redirect the wss traffic to the node instance
|
|
80
|
+
proxy_pass http://localhost:3000;
|
|
81
|
+
proxy_set_header Host $host;
|
|
82
|
+
proxy_set_header Upgrade $http_upgrade;
|
|
83
|
+
proxy_set_header Connection "upgrade";
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Once configured you can restart nginx with `sudo systemctl restart nginx`
|
|
89
|
+
|
|
90
|
+
Run `sudo systemctl enable nginx` to auto start the server on instance startup.
|
|
91
|
+
|
|
92
|
+
## Building the server
|
|
93
|
+
|
|
94
|
+
We clone the repo, build it and then make a copy of the relevant .env file.
|
|
95
|
+
|
|
96
|
+
```shell
|
|
97
|
+
git clone https://github.com/twinfoundation/node.git
|
|
98
|
+
cd apps
|
|
99
|
+
npm install
|
|
100
|
+
npm run dist
|
|
101
|
+
cd apps/node
|
|
102
|
+
cp .env.example-entity-storage .env
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The .env file can be modified to suit your own use case. For example to set the location for the storage.
|
|
106
|
+
|
|
107
|
+
```shell
|
|
108
|
+
TWIN_STORAGE_FILE_ROOT="/home/ec2-user/twin-node/"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Bootstrapping the server
|
|
112
|
+
|
|
113
|
+
You can now bootstrap the server, this will initialise all the required services and generate an initial configuration file. You should take note of the information in the logging as it will display information such as node admin passwords which will only be displayed once.
|
|
114
|
+
|
|
115
|
+
```shell
|
|
116
|
+
node ./dist/es/index.js
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
You should also now be able to access the server at `https://twin-node-api.example.com`
|
|
120
|
+
|
|
121
|
+
## Configure the server to restart with server
|
|
122
|
+
|
|
123
|
+
We now need to install the server as a service, so that after any reboot it will continue to run.
|
|
124
|
+
|
|
125
|
+
Stop the server with `Ctrl-C`.
|
|
126
|
+
|
|
127
|
+
Create a service file e.g. `twin-node.service`
|
|
128
|
+
|
|
129
|
+
You might need to modify the location for the node version, you can find this out using `whereis node`
|
|
130
|
+
|
|
131
|
+
```shell
|
|
132
|
+
[Unit]
|
|
133
|
+
Description=TWIN Node Server
|
|
134
|
+
After=network.target
|
|
135
|
+
|
|
136
|
+
[Service]
|
|
137
|
+
ExecStart=/home/ec2-user/.nvm/versions/node/v20.16.0/bin/node /home/ec2-user/twin-node/apps/twin-node/dist/es/index.js
|
|
138
|
+
Restart=always
|
|
139
|
+
User=ec2-user
|
|
140
|
+
Group=ec2-user
|
|
141
|
+
Environment=PATH=/usr/bin:/usr/local/bin
|
|
142
|
+
Environment=NODE_ENV=production
|
|
143
|
+
WorkingDirectory=/home/ec2-user/twin-node/apps/twin-node/
|
|
144
|
+
|
|
145
|
+
[Install]
|
|
146
|
+
WantedBy=multi-user.target
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Reload systemd and start the service.
|
|
150
|
+
|
|
151
|
+
```shell
|
|
152
|
+
sudo systemctl daemon-reload
|
|
153
|
+
sudo systemctl enable ./twin-node.service
|
|
154
|
+
sudo systemctl start twin-node.service
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
To check the status of the service.
|
|
158
|
+
|
|
159
|
+
```shell
|
|
160
|
+
sudo systemctl status twin-node.service
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
or
|
|
164
|
+
|
|
165
|
+
```shell
|
|
166
|
+
sudo journalctl -u twin-node | tail
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Upgrade EC2 Instance
|
|
170
|
+
|
|
171
|
+
To upgrade a previous installation on an EC2 instance with the latest version.
|
|
172
|
+
|
|
173
|
+
```shell
|
|
174
|
+
sudo systemctl stop twin-node.service
|
|
175
|
+
cd apps
|
|
176
|
+
git reset --hard
|
|
177
|
+
git pull
|
|
178
|
+
npm i
|
|
179
|
+
npm run dist
|
|
180
|
+
cd apps/node
|
|
181
|
+
|
|
182
|
+
# Update any env vars if necessary
|
|
183
|
+
# nano .env
|
|
184
|
+
|
|
185
|
+
# If you want to start from clean configuration you should remove the databases manually
|
|
186
|
+
# and also remove the engine-state file
|
|
187
|
+
# rm /home/ec2-user/twin-node/engine-state.json
|
|
188
|
+
|
|
189
|
+
# To perform a test run before launching the service permanently
|
|
190
|
+
# npm run start
|
|
191
|
+
|
|
192
|
+
sudo systemctl start twin-node.service
|
|
193
|
+
```
|