About the Installing and Deploying Kotahi category

Questions about installing and deploying Kotahi.

I am trying to deploy kotahi on a remote VM using production files.
All the services are up.
I have installed postgres on the vm and pass the credentials
I have setup xsweet on anothe VM, pass the db credentials and it is up.
I have installed single node single drive minIO, and passed the Host(vmIP), port and used the credentials as key and secret what I am not sure of is the bucket.
When I run docker-compose.production, I got the following error, which I guess is related to file storage.
kotahi-flax-site_1 | No groups found.
server_1 | /home/node/app/node_modules/aws-sdk/lib/request.js:31
server_1 | throw err;
server_1 | ^
server_1 |
server_1 | Error [TypeError]: Cannot destructure property ‘Key’ of ‘data’ as it is undefined.
server_1 | at ManagedUpload.callback (/home/node/app/node_modules/@coko/server/src/services/fileStorage.js:149:15)
server_1 | at Response.finishSinglePart (/home/node/app/node_modules/aws-sdk/lib/s3/managed_upload.js:680:28)
server_1 | at Request. (/home/node/app/node_modules/aws-sdk/lib/request.js:367:18)
server_1 | at Request.callListeners (/home/node/app/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
server_1 | at Request.emit (/home/node/app/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
server_1 | at Request.emit (/home/node/app/node_modules/aws-sdk/lib/request.js:686:14)
server_1 | at Request.transition (/home/node/app/node_modules/aws-sdk/lib/request.js:22:10)
server_1 | at AcceptorStateMachine.runTo (/home/node/app/node_modules/aws-sdk/lib/state_machine.js:14:12)
server_1 | at /home/node/app/node_modules/aws-sdk/lib/state_machine.js:26:10
server_1 | at Request. (/home/node/app/node_modules/aws-sdk/lib/request.js:38:9)
server_1 | at Request. (/home/node/app/node_modules/aws-sdk/lib/request.js:688:12)
server_1 | at Request.callListeners (/home/node/app/node_modules/aws-sdk/lib/sequential_executor.js:116:18)
server_1 | at Request.emit (/home/node/app/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
server_1 | at Request.emit (/home/node/app/node_modules/aws-sdk/lib/request.js:686:14)
server_1 | at Request.transition (/home/node/app/node_modules/aws-sdk/lib/request.js:22:10)
server_1 | at AcceptorStateMachine.runTo (/home/node/app/node_modules/aws-sdk/lib/state_machine.js:14:12) {
server_1 | code: ‘TypeError’,
server_1 | time: 2024-06-12T11:01:10.934Z
server_1 | }
kotahi_server_1 exited with code 1

I kindly need help urgently. Thanks for your response and support in advance.

And a related error
Error: connect ETIMEDOUT vmip:9000
server_1 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
server_1 | errno: -110,
server_1 | code: ‘TimeoutError’,
server_1 | syscall: ‘connect’,
server_1 | address: ‘vmip’,
server_1 | port: 9000,
server_1 | time: 2024-06-12T11:35:29.171Z,
server_1 | region: ‘us-east-1’,
server_1 | hostname: ‘vmip’,
server_1 | retryable: true
server_1 | }

  • db-xsweet
    image: cokoapps/xsweet:2.3.1
    ports:
  • ${SERVICE_XSWEET_PORT:-3004}:${SERVICE_XSWEET_PORT:-3004}
    environment:
  • PUBSWEET_SECRET=xsweet_dev_secret
  • POSTGRES_USER=xsweet_user_dev
  • POSTGRES_PASSWORD=xsweet_user_password
  • POSTGRES_HOST=db-xsweet
  • POSTGRES_DB=xsweet_dev
  • POSTGRES_PORT=5432
  • SERVER_PORT=${SERVICE_XSWEET_PORT:-3004}
  • NODE_ENV=development
    entrypoint:
    [
    ‘sh’,
    ‘scripts/wait-for-it’,
    ‘db-xsweet:5432’,
    ‘–’,
    ‘sh’,
    ‘scripts/setupDevServer.sh’,
    ]
    command: [‘node’, ‘server/startServer.js’]

How do I handle the above in production, if I already have xsweet deployed on another VM

Xsweet is a standalone microservice with its own db, independent from kotahi. You could bring it up on the same server as kotahi, or on another machine (or VM) like you did from what I understand.

Kotahi server’s connection to the microservice will be handled with the SERVICE_XSWEET_ environment variables passed to the server. All it needs is a valid URL and valid credentials. If you’ve already brought xsweet up somewhere different from the server, you just need to populate those variables. You do not need to include it in your compose file (or any equivalent) in this scenario.

This is an aws error, which essentially means that there is a file in kotahi, which points to a key in object storage, and that key doesn’t exist. Please check the validity of the keys referenced on the files table in your database. And make sure you don’t manually delete files in storage unless you’re sure they’re not used in the server database.

There’s been some cases where minio was running out of space, and instead of throwing an error, it was simply returning empty data, which also resulted in this error. Might be worth doing a sanity check that this is not your case.

Hope the above helps.

Thanks Yannis, I want to believe that my minIO was running out of space which can result in that, because I did not do anything with the files table in the database. I will check minIO, if there is any help regarding minIO please share.

Thank I will work on it and revert

Error 3.
kotahi-flax-site_1 | Rebuilding Flax site upon startup…
kotahi-flax-site_1 | Error while making a API call. {
kotahi-flax-site_1 | requestData: {
kotahi-flax-site_1 | data: ‘{“query”:“query groups {\n groups {\n\t\t\t\tid\n\t\t\t\tname\n }\n }”}’,
kotahi-flax-site_1 | headers: { ‘Content-Type’: ‘application/json’, ‘group-id’: ‘’ },
kotahi-flax-site_1 | method: ‘post’,
kotahi-flax-site_1 | maxBodyLength: Infinity,
kotahi-flax-site_1 | url: ‘’
kotahi-flax-site_1 | },
kotahi-flax-site_1 | err: AxiosError: connect ECONNREFUSED 196.216.191.181:443
kotahi-flax-site_1 | at Function.AxiosError.from (/app/node_modules/axios/dist/node/axios.cjs:836:14)
kotahi-flax-site_1 | at RedirectableRequest.handleRequestError (/app/node_modules/axios/dist/node/axios.cjs:3086:25)
kotahi-flax-site_1 | at RedirectableRequest.emit (node:events:527:28)
kotahi-flax-site_1 | at ClientRequest.eventHandlers. (/app/node_modules/follow-redirects/index.js:38:24)
kotahi-flax-site_1 | at ClientRequest.emit (node:events:527:28)
kotahi-flax-site_1 | at TLSSocket.socketErrorListener (node:_http_client:454:9)
kotahi-flax-site_1 | at TLSSocket.emit (node:events:527:28)
kotahi-flax-site_1 | at emitErrorNT (node:internal/streams/destroy:157:8)
kotahi-flax-site_1 | at emitErrorCloseNT (node:internal/streams/destroy:122:3)
kotahi-flax-site_1 | at processTicksAndRejections (node:internal/process/task_queues:83:21)
kotahi-flax-site_1 | at Axios.request (/app/node_modules/axios/dist/node/axios.cjs:3876:41)
kotahi-flax-site_1 | at processTicksAndRejections (node:internal/process/task_queues:96:5)
kotahi-flax-site_1 | at async makeAPICall (/app/api.js:23:18)
kotahi-flax-site_1 | at async getGroups (/app/groups.js:13:18)
kotahi-flax-site_1 | at async setupAllGroups (/app/setup.js:114:17)
kotahi-flax-site_1 | at async Object.setupSiteForGroups (/app/controllers/groupController.js:52:2)
kotahi-flax-site_1 | at async Server. (/app/server.js:27:2) {
kotahi-flax-site_1 | port: 443,
kotahi-flax-site_1 | address: ‘1.1.1.1.1 example’
kotahi-flax-site_1 | syscall: ‘connect’,
kotahi-flax-site_1 | code: ‘ECONNREFUSED’,
kotahi-flax-site_1 | errno: -111,
kotahi-flax-site_1 | config: {
kotahi-flax-site_1 | transitional: [Object],
kotahi-flax-site_1 | adapter: [Array],
kotahi-flax-site_1 | transformRequest: [Array],
kotahi-flax-site_1 | transformResponse: [Array],
kotahi-flax-site_1 | timeout: 0,
kotahi-flax-site_1 | xsrfCookieName: ‘XSRF-TOKEN’,
kotahi-flax-site_1 | xsrfHeaderName: ‘X-XSRF-TOKEN’,
kotahi-flax-site_1 | maxContentLength: -1,
kotahi-flax-site_1 | maxBodyLength: Infinity,
kotahi-flax-site_1 | env: [Object],
kotahi-flax-site_1 | validateStatus: [Function: validateStatus],
kotahi-flax-site_1 | headers: [Object [AxiosHeaders]],
kotahi-flax-site_1 | data: ‘{“query”:“query groups {\n groups {\n\t\t\t\tid\n\t\t\t\tname\n }\n }”}’,
kotahi-flax-site_1 | method: ‘post’,
kotahi-flax-site_1 | url: ‘https://publisha.ren.africa/graphql’
kotahi-flax-site_1 | },
kotahi-flax-site_1 | request: Writable {
kotahi-flax-site_1 | _writableState: [WritableState],
kotahi-flax-site_1 | _events: [Object: null prototype],
kotahi-flax-site_1 | _eventsCount: 3,
kotahi-flax-site_1 | _maxListeners: undefined,
kotahi-flax-site_1 | _options: [Object],
kotahi-flax-site_1 | _ended: false,
kotahi-flax-site_1 | _ending: true,
kotahi-flax-site_1 | _redirectCount: 0,
kotahi-flax-site_1 | _redirects: ,
kotahi-flax-site_1 | _requestBodyLength: 84,
kotahi-flax-site_1 | _requestBodyBuffers: [Array],
kotahi-flax-site_1 | _onNativeResponse: [Function (anonymous)],
kotahi-flax-site_1 | _currentRequest: [ClientRequest],
kotahi-flax-site_1 | _currentUrl: ‘https://publisha.ren.africa/graphql’,
kotahi-flax-site_1 | [Symbol(kCapture)]: false
kotahi-flax-site_1 | },
kotahi-flax-site_1 | cause: Error: connect ECONNREFUSED 196.216.191.181:443
kotahi-flax-site_1 | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16) {
kotahi-flax-site_1 | errno: -111,
kotahi-flax-site_1 | code: ‘ECONNREFUSED’,
kotahi-flax-site_1 | syscall: ‘connect’,
kotahi-flax-site_1 | address: '1.1.1.1,
kotahi-flax-site_1 | port: 443
kotahi-flax-site_1 | }
kotahi-flax-site_1 | }
kotahi-flax-site_1 | }

Thanks for your help

I have a couple of errors in the logs and I would need help to point me to what to do to correct them.
1.
xsweet_1 | For more information, check the migration guide at
xsweet_1 | (Use node --trace-warnings ... to show where the warning was created)
server_1 | error: Error while running migrations: CREATE TABLE cms_file_templates (
server_1 | id UUID PRIMARY KEY NOT NULL DEFAULT public.gen_random_uuid(),
server_1 | name TEXT,
server_1 | group_id UUID REFERENCES groups(id) NOT NULL,
server_1 | file_id UUID REFERENCES files(id) on delete set null,
server_1 | parent_id UUID,
server_1 | root_folder BOOLEAN NOT NULL DEFAULT false,
server_1 | created TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT current_timestamp,
server_1 | updated TIMESTAMP WITH TIME ZONE
server_1 | );
server_1 | - relation “cms_file_templates” already exists
2.
server_1 | error: error: CREATE TABLE cms_file_templates (
server_1 | at Object.raw (/home/node/app/node_modules/knex/lib/util/make-knex.js:114:30)
server_1 | at Function.value (/home/node/app/node_modules/knex/lib/util/make-knex.js:90:29)
server_1 | at Object.up (/home/node/app/node_modules/@pubsweet/db-manager/src/helpers/umzug.js:16:15)
server_1 | + exec node ./startServer.js
server_1 | /home/node/app
server_1 | userPublicationMetadata doesn’t exist.
server_1 | userArticleMetadata doesn’t exist.
server_1 | INSTANCE_GROUPS: journal:journal,prc:prc,single_form:preprint1
server_1 | Number of groups in .env 3
server_1 | (node:1) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.

Thank you for your help

On this, are you sure that this (196.216.191.181:443) is where you server is? From what I can tell, flax is trying to make an api call to your kotahi server at this url. The most common reason for getting a connection refused error is that the url is wrong.

This is the important part here. It seems like you have the table in your database, but not the entry in your migrations table. Each migration will add an entry to the migrations table after it successfully runs. If you tamper with the database manually, you might end up in a scenario like this. If you don’t have any data yet, the simplest solution would be to drop the cms_file_templates table and restart the app.

Thanks for your response. I have not tamper with the database , neither did I run any database command yet. Aside running docker commands, I only exec into the services container to get ID and secret.
Please help me with database commands to run during setup. Thank you

with this, the only place 443 is mentioned is in the nginx. It is weird

In production can I leave the CLIENT_HOST, CLIENT_PORT AND CLIENT_PROTOCOL blank since the server serves as both the backend and the client?

First validate that the table cms_file_templates exists. Either by looking at your preferred database program, or by running \dt with psql. The command to drop the table would be DROP TABLE IF EXISTS cms_file_templates. Goes without saying that you shouldn’t do this if you have data in it.

1 Like

I think keep them. It will soon be the case that server and client will be separate in production as well. And the client url is added to a whitelist so that you avoid cross-origin request errors.

1 Like

Hello @yannis
As discussed in our chat, I have created links to the .env and the docker-compose.production.yml to avoid cluttering the chat space.
I have created ID and secrets for all services which I have not provided in what I share here. The IPs are just examples not real.
docker-compose.production.yml

.env

Thanks for your guidance

These look in order from what I can tell. Cannot say for sure without running it. What is your issue currently? Still the relation cms_file_templates already exists?

Thanks @yannis ,
If the configuration files are in order, I am currently in the process of configuring MinIO, after which I will run the set up again.
I will let you know the specific issues I may encounter.
I am grateful

Any clue on how to resolve the following error
Starting kotahi_server_1 … done
Starting kotahi_kotahi-flax-site_1 … done
Attaching to kotahi_server_1, kotahi_kotahi-flax-site_1
server_1 | + node_modules/.bin/pubsweet migrate
kotahi-flax-site_1 | wait-for-it.sh: waiting 180 seconds for server:3000
server_1 | userPublicationMetadata doesn’t exist.
server_1 | userArticleMetadata doesn’t exist.
server_1 | (node:13) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.
server_1 |
server_1 | Please migrate your code to use AWS SDK for JavaScript (v3).
server_1 | For more information, check the migration guide at Migrate from version 2.x to 3.x of the AWS SDK for JavaScript - AWS SDK for JavaScript
server_1 | (Use node --trace-warnings ... to show where the warning was created)
server_1 | error: Error while running migrations: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
server_1 | error: KnexTimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
server_1 | at Object.raw (/home/node/app/node_modules/knex/lib/util/make-knex.js:114:30)
server_1 | at Function.value (/home/node/app/node_modules/knex/lib/util/make-knex.js:90:29)
server_1 | at Object.executed (/home/node/app/node_modules/@pubsweet/db-manager/src/helpers/umzugStorage.js:17:14)
server_1 | at Umzug.executed (/home/node/app/node_modules/umzug/lib/index.js:163:51)
server_1 | at Umzug. (/home/node/app/node_modules/umzug/lib/index.js:174:47)
server_1 | at Umzug.tryCatcher (/home/node/app/node_modules/bluebird/js/release/util.js:16:23)
server_1 | at Promise._settlePromiseFromHandler (/home/node/app/node_modules/bluebird/js/release/promise.js:547:31)
server_1 | at Promise._settlePromise (/home/node/app/node_modules/bluebird/js/release/promise.js:604:18)
server_1 | at Promise._settlePromise0 (/home/node/app/node_modules/bluebird/js/release/promise.js:649:10)
server_1 | at Promise._settlePromises (/home/node/app/node_modules/bluebird/js/release/promise.js:729:18)
server_1 | at Promise._fulfill (/home/node/app/node_modules/bluebird/js/release/promise.js:673:18)
server_1 | at Promise._resolveCallback (/home/node/app/node_modules/bluebird/js/release/promise.js:466:57)
server_1 | at Promise._settlePromiseFromHandler (/home/node/app/node_modules/bluebird/js/release/promise.js:559:17)
server_1 | + exec node ./startServer.js
server_1 | /home/node/app
server_1 | userPublicationMetadata doesn’t exist.
server_1 | userArticleMetadata doesn’t exist.
server_1 | INSTANCE_GROUPS: journal:journal,prc:prc,single_form:preprint1
server_1 | Number of groups in .env 3
server_1 | (node:1) NOTE: We are formalizing our plans to enter AWS SDK for JavaScript (v2) into maintenance mode in 2023.
server_1 |
server_1 | Please migrate your code to use AWS SDK for JavaScript (v3).
server_1 | For more information, check the migration guide at Migrate from version 2.x to 3.x of the AWS SDK for JavaScript - AWS SDK for JavaScript
server_1 | (Use node --trace-warnings ... to show where the warning was created)
server_1 | /home/node/app/node_modules/knex/lib/client.js:348
server_1 | convertedError = new KnexTimeoutError(
server_1 | ^
server_1 |
server_1 | KnexTimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
server_1 | at Client_PG.acquireConnection (/home/node/app/node_modules/knex/lib/client.js:348:26)
server_1 | at async Transaction.acquireConnection (/home/node/app/node_modules/knex/lib/transaction.js:212:28)
server_1 | at async main (/home/node/app/startServer.js:6:3)
kotahi_server_1 exited with code 1
kotahi-flax-site_1 | nc: bad address ‘server’
kotahi-flax-site_1 | nc: bad address ‘server’
kotahi-flax-site_1 | nc: bad address ‘server’
kotahi-flax-site_1 | nc: bad address ‘server’
kotahi-flax-site_1 | nc: bad address ‘server’

@yannis

server_1 | KnexTimeoutError: Knex: Timeout acquiring a connection. The pool is probably full. Are you missing a .transacting(trx) call?
server_1 | at Client_PG.acquireConnection

The most likely scenario here is the server cannot connect to the database at all. Please check that all POSTGRES_ environment variables are passed correctly to the server and that the database is actually up an running.

Hello All,
We have been able to set up Kotahi and the services are up and running.
There is an error when we try to publish, it is related to ‘no groups’ found.
See below the logs

/kotahi$ docker logs 6800a55126c5
wait-for-it.sh: waiting 180 seconds for server:3000
wait-for-it.sh: server:3000 is available after 5 seconds
2024-07-09 10:46:25,711 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2024-07-09 10:46:25,711 CRIT Supervisor is running as root. Privileges were not dropped because no user is specified in the config file. If you intend to run as root, you can set user=root in the config file to avoid this message.
2024-07-09 10:46:25,712 INFO supervisord started with pid 35
2024-07-09 10:46:25,712 INFO supervisord started with pid 35
2024-07-09 10:46:26,715 INFO spawned: ‘nginx’ with pid 36
2024-07-09 10:46:26,715 INFO spawned: ‘nginx’ with pid 36
2024-07-09 10:46:26,717 INFO spawned: ‘node’ with pid 37
2024-07-09 10:46:26,717 INFO spawned: ‘node’ with pid 37
Flax and Express server running on port 8080 and 8082 respectively.
Rebuilding Flax site upon startup…
No groups found.
2024-07-09 10:46:28,115 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2024-07-09 10:46:28,115 INFO success: nginx entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2024-07-09 10:46:28,115 INFO success: node entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2024-07-09 10:46:28,115 INFO success: node entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
/app/groups.js:27
const group = groups.find(group => group.id === groupId);
^

TypeError: groups.find is not a function
at getGroupById (/app/groups.js:27:24)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async rebuild (/app/controllers/groupController.js:11:14)
2024-07-09 10:53:00,368 INFO exited: node (exit status 1; not expected)
2024-07-09 10:53:00,368 INFO exited: node (exit status 1; not expected)
2024-07-09 10:53:01,372 INFO spawned: ‘node’ with pid 56
2024-07-09 10:53:01,372 INFO spawned: ‘node’ with pid 56
Flax and Express server running on port 8080 and 8082 respectively.
Rebuilding Flax site upon startup…
No groups found.
2024-07-09 10:53:02,608 INFO success: node entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
2024-07-09 10:53:02,608 INFO success: node entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)