@3sixty/node 0.0.0-stage → 0.20.0-next.0
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 +34 -2
- package/bin/index.js +4 -0
- package/dist/locales/en.json +18011 -0
- package/docs/changelog.md +0 -0
- package/docs/commands/bootstrap-dev.md +51 -0
- package/docs/commands/help.md +61 -0
- package/docs/commands/identity-create.md +67 -0
- package/docs/commands/identity-import.md +37 -0
- package/docs/commands/identity-list.md +31 -0
- package/docs/commands/identity-remove.md +46 -0
- package/docs/commands/identity-resolve.md +38 -0
- package/docs/commands/identity-verifiable-credential-create.md +58 -0
- package/docs/commands/identity-verification-method-create.md +55 -0
- package/docs/commands/identity-verification-method-import.md +46 -0
- package/docs/commands/node-identity-get.md +31 -0
- package/docs/commands/node-identity-set.md +36 -0
- package/docs/commands/node-org-id-get.md +32 -0
- package/docs/commands/node-org-id-set.md +37 -0
- package/docs/commands/org-users-list.md +40 -0
- package/docs/commands/tenant-create.md +55 -0
- package/docs/commands/tenant-get.md +34 -0
- package/docs/commands/tenant-import.md +46 -0
- package/docs/commands/tenant-list-by-org.md +34 -0
- package/docs/commands/tenant-list.md +31 -0
- package/docs/commands/tenant-org-alias-remove.md +39 -0
- package/docs/commands/tenant-org-id-set.md +39 -0
- package/docs/commands/tenant-remove.md +34 -0
- package/docs/commands/tenant-update.md +46 -0
- package/docs/commands/user-create.md +73 -0
- package/docs/commands/user-get.md +43 -0
- package/docs/commands/user-remove.md +43 -0
- package/docs/commands/user-update-password.md +58 -0
- package/docs/commands/user-update.md +58 -0
- package/docs/commands/vault-key-create.md +58 -0
- package/docs/commands/vault-key-import.md +43 -0
- package/docs/commands/vault-key-remove.md +37 -0
- package/docs/commands/vault-key-update.md +40 -0
- package/docs/configuration.md +234 -0
- package/docs/deployment-docker.md +142 -0
- package/docs/deployment-ec2.md +193 -0
- package/docs/deployment.md +4 -0
- package/docs/open-api/spec.json +24802 -0
- package/docs/usage.md +239 -0
- package/locales/en.json +1 -0
- package/package.json +39 -5
- package/src/index.js +12 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# vault-key-create
|
|
2
|
+
|
|
3
|
+
Create a vault key for an identity.
|
|
4
|
+
|
|
5
|
+
## Tenancy
|
|
6
|
+
|
|
7
|
+
Available in single-tenant and multi-tenant mode, with the same behaviour in both.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
vault-key-create: Create a vault key for an identity
|
|
13
|
+
|
|
14
|
+
env-prefix: (string, optional)
|
|
15
|
+
Prefix to use for standard .env files e.g. TWIN_.
|
|
16
|
+
|
|
17
|
+
identity: (string, did, required)
|
|
18
|
+
The DID to associate the key with.
|
|
19
|
+
|
|
20
|
+
key-id: (string, required)
|
|
21
|
+
The ID of the key.
|
|
22
|
+
|
|
23
|
+
key-type: (string, default: 'Ed25519', optional, options: [Ed25519, ChaCha20Poly1305])
|
|
24
|
+
The type of the key.
|
|
25
|
+
|
|
26
|
+
overwrite-mode: (string, default: 'skip', optional, options: [skip, overwrite, error])
|
|
27
|
+
The mode to use when a key with the same id already exists.
|
|
28
|
+
|
|
29
|
+
load-env: (string, optional)
|
|
30
|
+
Comma separated list of paths to .env files to read input parameters from.
|
|
31
|
+
|
|
32
|
+
output-json: (string, optional)
|
|
33
|
+
Path to a .json file to store the command output.
|
|
34
|
+
|
|
35
|
+
output-env: (string, optional)
|
|
36
|
+
Path to a .env file to store the command output.
|
|
37
|
+
|
|
38
|
+
output-env-prefix: (string, optional)
|
|
39
|
+
Prefix to use for variables in the output .env file.
|
|
40
|
+
|
|
41
|
+
Example: vault-key-create --identity="did:iota:...." --key-id="my-key" --key-type="Ed25519"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Examples
|
|
45
|
+
|
|
46
|
+
Create the authentication signing key for the node:
|
|
47
|
+
|
|
48
|
+
```shell
|
|
49
|
+
3sixty-node vault-key-create --load-env="node-identity.env" --identity=!NODE_DID --key-type=Ed25519 --key-id=!TWIN_AUTH_SIGNING_KEY_ID --overwrite-mode=skip --output-json="node-auth-key.json" --output-env="node-auth-key.env"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Create a blob storage encryption key for the organisation:
|
|
53
|
+
|
|
54
|
+
```shell
|
|
55
|
+
3sixty-node vault-key-create --load-env="organization-identity.env" --identity=!ORGANIZATION_DID --key-type=ChaCha20Poly1305 --key-id=!TWIN_BLOB_STORAGE_ENCRYPTION_KEY_ID --overwrite-mode=skip --output-json="organization-blob-encryption.json"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
See the [usage guide](../usage.md) for running the node and the full list of commands.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# vault-key-import
|
|
2
|
+
|
|
3
|
+
Import a vault key for an identity.
|
|
4
|
+
|
|
5
|
+
## Tenancy
|
|
6
|
+
|
|
7
|
+
Available in single-tenant and multi-tenant mode, with the same behaviour in both.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
vault-key-import: Import a vault key for an identity
|
|
13
|
+
|
|
14
|
+
env-prefix: (string, optional)
|
|
15
|
+
Prefix to use for standard .env files e.g. TWIN_.
|
|
16
|
+
|
|
17
|
+
identity: (string, did, required)
|
|
18
|
+
The DID to associate the key with.
|
|
19
|
+
|
|
20
|
+
key-id: (string, required)
|
|
21
|
+
The ID of the key.
|
|
22
|
+
|
|
23
|
+
key-type: (string, default: 'Ed25519', optional, options: [Ed25519, ChaCha20Poly1305])
|
|
24
|
+
The type of the key.
|
|
25
|
+
|
|
26
|
+
private-key-hex: (string, required)
|
|
27
|
+
The private key in hex format.
|
|
28
|
+
|
|
29
|
+
load-env: (string, optional)
|
|
30
|
+
Comma separated list of paths to .env files to read input parameters from.
|
|
31
|
+
|
|
32
|
+
Example: vault-key-import --identity="did:iota:...." --key-id="my-key" --key-type=Ed25519 --private-key-hex="15...a2"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Examples
|
|
36
|
+
|
|
37
|
+
Import an existing authentication signing key:
|
|
38
|
+
|
|
39
|
+
```shell
|
|
40
|
+
3sixty-node vault-key-import --load-env="node-identity.env,node-auth-key.env" --identity=!NODE_DID --key-id=!TWIN_AUTH_SIGNING_KEY_ID --key-type=!KEY_TYPE --private-key-hex=!PRIVATE_KEY_HEX
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
See the [usage guide](../usage.md) for running the node and the full list of commands.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# vault-key-remove
|
|
2
|
+
|
|
3
|
+
Remove a vault key for an identity.
|
|
4
|
+
|
|
5
|
+
## Tenancy
|
|
6
|
+
|
|
7
|
+
Available in single-tenant and multi-tenant mode, with the same behaviour in both.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
vault-key-remove: Remove a vault key for an identity
|
|
13
|
+
|
|
14
|
+
env-prefix: (string, optional)
|
|
15
|
+
Prefix to use for standard .env files e.g. TWIN_.
|
|
16
|
+
|
|
17
|
+
identity: (string, did, required)
|
|
18
|
+
The DID the key is associated with.
|
|
19
|
+
|
|
20
|
+
key-id: (string, required)
|
|
21
|
+
The ID of the key.
|
|
22
|
+
|
|
23
|
+
load-env: (string, optional)
|
|
24
|
+
Comma separated list of paths to .env files to read input parameters from.
|
|
25
|
+
|
|
26
|
+
Example: vault-key-remove --identity="did:iota:...." --key-id="my-key"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
Remove a vault key:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
3sixty-node vault-key-remove --load-env="node-identity.env" --identity=!NODE_DID --key-id="my-key"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
See the [usage guide](../usage.md) for running the node and the full list of commands.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# vault-key-update
|
|
2
|
+
|
|
3
|
+
Replace the key material of an existing vault key for an identity.
|
|
4
|
+
|
|
5
|
+
## Tenancy
|
|
6
|
+
|
|
7
|
+
Available in single-tenant and multi-tenant mode, with the same behaviour in both. The key keeps its existing type, only the key material is replaced.
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
vault-key-update: Replace the key material of an existing vault key for an identity
|
|
13
|
+
|
|
14
|
+
env-prefix: (string, optional)
|
|
15
|
+
Prefix to use for standard .env files e.g. TWIN_.
|
|
16
|
+
|
|
17
|
+
identity: (string, did, required)
|
|
18
|
+
The DID the key is associated with.
|
|
19
|
+
|
|
20
|
+
key-id: (string, required)
|
|
21
|
+
The ID of the key.
|
|
22
|
+
|
|
23
|
+
private-key-hex: (string, required)
|
|
24
|
+
The replacement private key in hex format, the key type is kept.
|
|
25
|
+
|
|
26
|
+
load-env: (string, optional)
|
|
27
|
+
Comma separated list of paths to .env files to read input parameters from.
|
|
28
|
+
|
|
29
|
+
Example: vault-key-update --identity="did:iota:...." --key-id="my-key" --private-key-hex="15...a2"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Examples
|
|
33
|
+
|
|
34
|
+
Replace the material of an existing key:
|
|
35
|
+
|
|
36
|
+
```shell
|
|
37
|
+
3sixty-node vault-key-update --load-env="node-identity.env" --identity=!NODE_DID --key-id="my-key" --private-key-hex="0x..."
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
See the [usage guide](../usage.md) for running the node and the full list of commands.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# Node Configuration
|
|
2
|
+
|
|
3
|
+
## Available Example Configurations
|
|
4
|
+
|
|
5
|
+
Four ready-to-use example files are provided in `apps/node/`. Copy the relevant file to `.env` as a starting point:
|
|
6
|
+
|
|
7
|
+
| File | Role |
|
|
8
|
+
| ----------------------------------- | ------------------------------------------------------------------------- |
|
|
9
|
+
| `.env.example-local-entity-storage` | Full-featured node using local file/entity storage |
|
|
10
|
+
| `.env.example-aws-ec2` | Full-featured node deployed on Amazon AWS EC2 with DynamoDB |
|
|
11
|
+
| `.env.example-iota-testnet` | Full-featured node connected to the IOTA testnet |
|
|
12
|
+
| `.env.example-federated-catalogue` | Standalone federated catalogue server (no dataspace or rights management) |
|
|
13
|
+
|
|
14
|
+
## Extension Loading
|
|
15
|
+
|
|
16
|
+
The 3Sixty Node supports loading extensions dynamically to extend its functionality. Extensions can be loaded from multiple sources using protocol-based syntax.
|
|
17
|
+
|
|
18
|
+
### Extension Loading Syntax
|
|
19
|
+
|
|
20
|
+
Extensions are configured via the `TWIN_EXTENSIONS` environment variable. Multiple extensions can be specified as a comma-separated list.
|
|
21
|
+
|
|
22
|
+
#### Local File Extensions
|
|
23
|
+
|
|
24
|
+
Load extensions from the local filesystem:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Relative path
|
|
28
|
+
TWIN_EXTENSIONS="./my-extension.mjs"
|
|
29
|
+
|
|
30
|
+
# Absolute path
|
|
31
|
+
TWIN_EXTENSIONS="/path/to/extension.mjs"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
#### NPM Package Extensions
|
|
35
|
+
|
|
36
|
+
Load extensions from npm packages. The package will be automatically downloaded and installed if not already cached:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Basic npm package
|
|
40
|
+
TWIN_EXTENSIONS="npm:@3sixty/identity-management-service"
|
|
41
|
+
|
|
42
|
+
# Scoped package
|
|
43
|
+
TWIN_EXTENSIONS="npm:@org/custom-extension"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Note:** Version pinning (e.g., `npm:@3sixty/pkg@1.2.3`) is planned for a future release. Currently, the latest version is installed.
|
|
47
|
+
|
|
48
|
+
#### HTTPS URL Extensions
|
|
49
|
+
|
|
50
|
+
Load extensions from remote HTTPS URLs:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
TWIN_EXTENSIONS="https://example.twin.org/extensions/my-module.mjs"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**⚠️ SECURITY WARNING:** Loading code from HTTPS URLs introduces security risks. Only load extensions from trusted sources that you control or verify.
|
|
57
|
+
|
|
58
|
+
Security features:
|
|
59
|
+
|
|
60
|
+
- Only HTTPS is allowed (HTTP is rejected)
|
|
61
|
+
- Default 10 MB size limit to prevent DoS attacks
|
|
62
|
+
- Downloaded modules are cached locally
|
|
63
|
+
- Security warning is displayed when loading
|
|
64
|
+
|
|
65
|
+
#### Multiple Extensions
|
|
66
|
+
|
|
67
|
+
Load multiple extensions from different sources:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
TWIN_EXTENSIONS="@3sixty/identity-management-service,npm:@3sixty/custom-service,./local-extension.mjs,https://example.com/remote.mjs"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Extension Configuration Options
|
|
74
|
+
|
|
75
|
+
#### Maximum Download Size
|
|
76
|
+
|
|
77
|
+
Configure the maximum size (in MB) for HTTPS extension downloads:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
TWIN_EXTENSIONS_MAX_SIZE_MB=10 # Default is 10 MB
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### Cache Management
|
|
84
|
+
|
|
85
|
+
By default, downloaded extensions are cached in `.tmp/extensions/` directory to speed up subsequent startups. To clear the cache on each startup:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
TWIN_EXTENSIONS_CLEAR_CACHE=true # Default is false
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Custom Cache Directory
|
|
92
|
+
|
|
93
|
+
You can configure a custom directory for extension caching:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
TWIN_EXTENSIONS_CACHE_DIRECTORY="cache" # Default is ".tmp"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
This allows you to:
|
|
100
|
+
|
|
101
|
+
- Use a dedicated partition with more space
|
|
102
|
+
- Separate cache by environment (dev/staging/prod)
|
|
103
|
+
- Follow corporate storage policies
|
|
104
|
+
- Create persistent cache directories for better performance
|
|
105
|
+
|
|
106
|
+
### Extension API
|
|
107
|
+
|
|
108
|
+
Extensions must export specific lifecycle methods to integrate with the node:
|
|
109
|
+
|
|
110
|
+
#### `extensionInitialise(envVars, nodeEngineConfig)`
|
|
111
|
+
|
|
112
|
+
Called during configuration phase. Allows the extension to modify environment variables and engine configuration.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
export async function extensionInitialise(
|
|
116
|
+
envVars: INodeEnvironmentVariables,
|
|
117
|
+
nodeEngineConfig: INodeEngineConfig
|
|
118
|
+
): Promise<void> {
|
|
119
|
+
// Modify configuration here
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `extensionInitialiseEngine(engineCore)`
|
|
124
|
+
|
|
125
|
+
Called after the engine is created but before the server starts.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
export async function extensionInitialiseEngine(engineCore: IEngineCore): Promise<void> {
|
|
129
|
+
// Register components, set up services, etc.
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `extensionInitialiseEngineServer(engineCore, engineServer)`
|
|
134
|
+
|
|
135
|
+
Called after the engine server is created but before it starts listening.
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
export async function extensionInitialiseEngineServer(
|
|
139
|
+
engineCore: IEngineCore,
|
|
140
|
+
engineServer: IEngineServer
|
|
141
|
+
): Promise<void> {
|
|
142
|
+
// Add routes, configure server, etc.
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
#### `extensionShutdown()`
|
|
147
|
+
|
|
148
|
+
Called when the node is shutting down. Clean up resources here.
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
export async function extensionShutdown(): Promise<void> {
|
|
152
|
+
// Clean up resources
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Example Extension
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// my-extension.mjs
|
|
160
|
+
export async function extensionInitialise(envVars, nodeEngineConfig) {
|
|
161
|
+
console.log('Extension initializing with config');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function extensionInitialiseEngine(engineCore) {
|
|
165
|
+
engineCore.logInfo('Custom extension loaded');
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export async function extensionInitialiseEngineServer(engineCore, engineServer) {
|
|
169
|
+
// Add custom routes
|
|
170
|
+
engineServer.addRestRoute({
|
|
171
|
+
path: '/custom/endpoint',
|
|
172
|
+
method: 'GET',
|
|
173
|
+
handler: async () => ({ body: { message: 'Hello from extension!' } })
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function extensionShutdown() {
|
|
178
|
+
console.log('Extension shutting down');
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Cache Directory Structure
|
|
183
|
+
|
|
184
|
+
Downloaded extensions are stored in:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
<execution-directory>/<cache-directory>/extensions/
|
|
188
|
+
├── npm/ # NPM packages
|
|
189
|
+
│ └── node_modules/
|
|
190
|
+
│ └── @3sixty/...
|
|
191
|
+
└── https/ # HTTPS downloads
|
|
192
|
+
└── <hashed-filename>.mjs
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Where `<cache-directory>` is:
|
|
196
|
+
|
|
197
|
+
- `.tmp` by default
|
|
198
|
+
- Configurable via `TWIN_EXTENSIONS_CACHE_DIRECTORY`
|
|
199
|
+
|
|
200
|
+
Examples:
|
|
201
|
+
|
|
202
|
+
- Default: `./.tmp/extensions/`
|
|
203
|
+
- Custom: `./cache/extensions/` (if `TWIN_EXTENSIONS_CACHE_DIRECTORY="cache"`)
|
|
204
|
+
- Absolute: `/var/cache/twin-node/extensions/` (if `TWIN_EXTENSIONS_CACHE_DIRECTORY="/var/cache/twin-node"`)
|
|
205
|
+
|
|
206
|
+
### Security Best Practices
|
|
207
|
+
|
|
208
|
+
1. **Prefer npm: protocol** over https: for third-party extensions (npm has package verification and malware scanning)
|
|
209
|
+
2. **Use local files** (`./extension.mjs`) for maximum security and control
|
|
210
|
+
3. **Verify HTTPS sources** before using - only load from domains you trust
|
|
211
|
+
4. **Review extension code** before deployment, especially for HTTPS sources
|
|
212
|
+
5. **Monitor cache directory** - review what's been downloaded to `.tmp/extensions/`
|
|
213
|
+
6. **Use environment-specific configuration** - different extensions for dev/staging/prod
|
|
214
|
+
|
|
215
|
+
### Troubleshooting
|
|
216
|
+
|
|
217
|
+
#### Extension fails to load
|
|
218
|
+
|
|
219
|
+
- Check that npm is installed and accessible in PATH (required for npm: protocol)
|
|
220
|
+
- Verify the extension file/URL is accessible
|
|
221
|
+
- Check `.tmp/extensions/` cache for partially downloaded files
|
|
222
|
+
- Review node logs for specific error messages
|
|
223
|
+
|
|
224
|
+
#### Clear extension cache manually
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
rm -rf .tmp/extensions
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### NPM package not found
|
|
231
|
+
|
|
232
|
+
- Verify the package name is correct
|
|
233
|
+
- Check network connectivity
|
|
234
|
+
- Ensure npm registry is accessible
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Node Deployment Docker
|
|
2
|
+
|
|
3
|
+
The 3Sixty Node can be run as a Docker container, either from the published image or from an image you build yourself.
|
|
4
|
+
|
|
5
|
+
## Published Image
|
|
6
|
+
|
|
7
|
+
Images are published to GitHub Packages as [ghcr.io/3sixtyglobal/node](https://github.com/3sixtyglobal/node/pkgs/container/3sixty-node) for `linux/amd64` and `linux/arm64`, with the following tags:
|
|
8
|
+
|
|
9
|
+
| Tag | Description |
|
|
10
|
+
| --------- | ------------------------------------------------ |
|
|
11
|
+
| `latest` | The most recent production release. |
|
|
12
|
+
| `next` | The most recent prerelease. |
|
|
13
|
+
| `<x.y.z>` | A specific version, for example `0.10.1-next.6`. |
|
|
14
|
+
|
|
15
|
+
```shell
|
|
16
|
+
docker pull ghcr.io/3sixtyglobal/node:latest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Building the Image
|
|
20
|
+
|
|
21
|
+
The dockerfile is in `apps/node/deploy/dockerfile`. It builds `@3sixty/node-core` from the repository source and packs it, then installs that package and the other dependencies with pnpm, merges the translation messages, and removes the development dependencies. The repository root forms the build context, and `apps/node/deploy/dockerfile.dockerignore` keeps your local `node_modules`, build output and `.env` files out of the image.
|
|
22
|
+
|
|
23
|
+
Build the image from the repository root:
|
|
24
|
+
|
|
25
|
+
```shell
|
|
26
|
+
docker build -t 3sixty-node -f apps/node/deploy/dockerfile . --load
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
> **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.
|
|
30
|
+
|
|
31
|
+
To build for both of the published platforms use a Buildx builder with the `docker-container` driver:
|
|
32
|
+
|
|
33
|
+
```shell
|
|
34
|
+
docker buildx create --name 3sixty-multiplatform-builder --driver docker-container --use
|
|
35
|
+
docker buildx build --platform linux/amd64,linux/arm64 -t 3sixty-node -f apps/node/deploy/dockerfile .
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The examples below use the locally built `3sixty-node` image, replace it with `ghcr.io/3sixtyglobal/node:<tag>` to use the published image.
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
The node reads its configuration from `/app/.env` in the container, and from environment variables, which take precedence over the file. The image does not contain a `.env`, so start from one of the example configurations described in [Node Configuration](./configuration.md) and mount it into the container:
|
|
43
|
+
|
|
44
|
+
```shell
|
|
45
|
+
-v /home/twin-node/.env:/app/.env:ro
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Mount the file rather than passing it with `--env-file`. Docker does not remove the quotes around values in an env file, so the quoted values used in the example configurations would be read incorrectly.
|
|
49
|
+
|
|
50
|
+
The image sets the following environment variables, which override the same settings in `/app/.env`:
|
|
51
|
+
|
|
52
|
+
| Variable | Value | Description |
|
|
53
|
+
| ------------------------ | ----------------- | ---------------------------------------------- |
|
|
54
|
+
| `TWIN_HOST` | `0.0.0.0` | Listen on all interfaces inside the container. |
|
|
55
|
+
| `TWIN_PORT` | `3000` | The port the API server listens on. |
|
|
56
|
+
| `TWIN_STORAGE_FILE_ROOT` | `/twin-node/data` | The root directory for `file` storage. |
|
|
57
|
+
|
|
58
|
+
Change any of them with `-e`, for example `-e TWIN_PORT=8080`.
|
|
59
|
+
|
|
60
|
+
## Data Persistence
|
|
61
|
+
|
|
62
|
+
When storage is configured to use the `file` connector, its data and the engine state in `engine-state.json` are written to `/twin-node/data`. Mount a volume or a host directory there so that the data is kept when the container is replaced:
|
|
63
|
+
|
|
64
|
+
```shell
|
|
65
|
+
-v /home/twin-node/data:/twin-node/data
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The same data directory must be mounted for the bootstrap commands and for the running node.
|
|
69
|
+
|
|
70
|
+
## Bootstrapping
|
|
71
|
+
|
|
72
|
+
The node will not start until it has been bootstrapped. A container started without a node identity stops with:
|
|
73
|
+
|
|
74
|
+
```shell
|
|
75
|
+
The node identity is enabled in config but is not set, please set it using the "node-identity-set" CLI command.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The CLI commands run from the same image by passing the command after `node src/index.js`, with the same configuration and data directory that the node will use. For a development node the [bootstrap-dev](./commands/bootstrap-dev.md) command creates the node identity, organisation identity and admin user in a single step:
|
|
79
|
+
|
|
80
|
+
```shell
|
|
81
|
+
docker run --rm \
|
|
82
|
+
-v /home/twin-node/.env:/app/.env:ro \
|
|
83
|
+
-v /home/twin-node/.env.bootstrap-dev:/app/.env.bootstrap-dev:ro \
|
|
84
|
+
-v /home/twin-node/data:/twin-node/data \
|
|
85
|
+
3sixty-node node src/index.js bootstrap-dev --load-env=.env.bootstrap-dev
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The values it reads are described in [bootstrap-dev](./commands/bootstrap-dev.md), and `.env.example-bootstrap-dev` is a starting point for the file. Any value that is not provided is generated. Generated mnemonics and passwords are only shown in the command output, so record them.
|
|
89
|
+
|
|
90
|
+
To bootstrap a production node step by step, or to manage identities, tenants and users later, run the relevant commands from [Node Usage](./usage.md) in the same way. Use `help` to list the commands available in the image:
|
|
91
|
+
|
|
92
|
+
```shell
|
|
93
|
+
docker run --rm 3sixty-node node src/index.js help
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Running the Node
|
|
97
|
+
|
|
98
|
+
Once bootstrapped, start the node with the same configuration and data directory:
|
|
99
|
+
|
|
100
|
+
```shell
|
|
101
|
+
docker run -d --name 3sixty-node \
|
|
102
|
+
-v /home/twin-node/.env:/app/.env:ro \
|
|
103
|
+
-v /home/twin-node/data:/twin-node/data \
|
|
104
|
+
-p 3000:3000 \
|
|
105
|
+
3sixty-node
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Follow the output with `docker logs -f 3sixty-node`. When the node is ready you should see:
|
|
109
|
+
|
|
110
|
+
```shell
|
|
111
|
+
INFO [2026-09-24T04:57:23.320Z] EngineCore Engine has started
|
|
112
|
+
INFO [2026-09-24T04:57:23.346Z] FastifyWebServer Building Web Server
|
|
113
|
+
INFO [2026-09-24T04:57:23.384Z] FastifyWebServer Starting Web Server with binding "0.0.0.0" on port "3000"
|
|
114
|
+
INFO [2026-09-24T04:57:23.392Z] FastifyWebServer The Web Server started on http://127.0.0.1:3000
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
You should now be able to access the server in the browser at [http://localhost:3000/info](http://localhost:3000/info), which returns something similar to:
|
|
118
|
+
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"name": "3Sixty Node",
|
|
122
|
+
"version": "0.10.1-next.6"
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The request and response are also shown in the logs:
|
|
127
|
+
|
|
128
|
+
```shell
|
|
129
|
+
INFO [2026-09-24T04:57:25.150Z] LoggingProcessor ===> GET /info {}
|
|
130
|
+
INFO [2026-09-24T04:57:25.150Z] LoggingProcessor <=== 200 GET /info duration: 722µs {"body":{"name":"3Sixty Node","version":"0.10.1-next.6"}}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Stopping the Node
|
|
134
|
+
|
|
135
|
+
The node responds to the standard termination signals, so `docker stop 3sixty-node` stops the components gracefully before the container exits:
|
|
136
|
+
|
|
137
|
+
```shell
|
|
138
|
+
INFO [2026-09-24T05:00:09.380Z] EngineCore Components have stopped
|
|
139
|
+
INFO [2026-09-24T05:00:09.380Z] EngineCore Engine has stopped
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Starting the container again with `docker start 3sixty-node` reuses the existing engine state, so the bootstrap does not need to be repeated.
|