Intermittent 60-second API response times

I am self-hosting a fresh installation of the pre-compiled Vikunja v0.24.6 binary via nginx and PostgreSQL on Ubuntu 22.04. All features seem to be working as expected, with the one notable exception that seemingly random actions result in a precisely 60-second delay.

The Network tab of the browser’s DevTools shows that certain requests have status (pending) during this delay, but they do eventually resolve and the API call is successfully completed or the .css/.js/etc file is downloaded.

When configuring Vikunja for aggressive logging, these delays are marked by an absence of new lines generated in journalctl, followed by a sudden wave of new lines after the 60-second period has passed. All of those sudden logs show response times well within the expected 20-100ms baseline demonstrated at https://try.vikunja.io/.

There do not appear to be any errors or reports of timed out requests in journalctl, and the PostgreSQL logs show a similar pattern of silence followed by a sudden wave of instantly-resolved transaction requests.

I tried matching versions with https://try.vikunja.io/ (v0.24.1) without success. I tried installing the Debian package instead of the zipped binary without success. I checked htop and found both processors and memory well below capacity. I tested other services running on the same server and found no similar delays.

nginx Config
server {
    server_name vikunja.example.org;

    location / {
        proxy_pass http://localhost:3456;
        client_max_body_size 50M;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/vikunja.example.org/fullchain.pem; # managed by Certbot                    
    ssl_certificate_key /etc/letsencrypt/live/vikunja.example.org/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = vikunja.example.org) {                                                                               
        return 301 https://$host$request_uri;
    } # managed by Certbot
    listen 80;
    server_name vikunja.example.org;                                                                                 
    return 404; # managed by Certbot
}

Vikunja Config
service:
  JWTSecret: "rAnDoM_sTrInG"
  jwtttl: 259200
  jwtttllong: 2592000
  interface: ":3456"
  unixsocket:
  unixsocketmode:
  publicurl: "vikunja.example.org"
  rootpath: /opt/vikunja
  maxitemsperpage: 50
  enablecaldav: true
  motd: ""
  enablelinksharing: true
  enableregistration: false
  enabletaskattachments: true
  timezone: America/Los_Angeles
  enabletaskcomments: true
  enabletotp: true
  testingtoken: ''
  enableemailreminders: true
  enableuserdeletion: true
  maxavatarsize: 1024
  demomode: false
  allowiconchanges: true
  customlogourl: ''
  enablepublicteams: true

sentry:
  enabled: false
  dsn: "https://440eedc957d545a795c17bbaf477497c@o1047380.ingest.sentry.io/4504254983634944"
  frontendenabled: false
  frontenddsn: "https://85694a2d757547cbbc90cd4b55c5a18d@o1047380.ingest.sentry.io/6024480"

database:
  type: "postgres"
  user: "vikunja"
  password: "postgres_password"
  host: "localhost"
  database: "vikunja"
  path: "./vikunja.db"
  maxopenconnections: 100
  maxidleconnections: 50
  maxconnectionlifetime: 10000
  sslmode: disable
  sslcert: ""
  sslkey: ""
  sslrootcert: ""
  tls: false

typesense:
  enabled: false
  url: ''
  apikey: ''

redis:
  enabled: false
  host: 'localhost:6379'
  password: ''
  db: 0

cors:
  enable: false
  origins:
    - "*"
  maxage: 0

mailer:
  enabled: false
  host: ""
  port: 587
  authtype: "plain"
  username: "user"
  password: ""
  skiptlsverify: false
  fromemail: "mail@vikunja"
  queuelength: 100
  queuetimeout: 30
  forcessl: false

log:
  path: /var/log/vikunja
  enabled: true
  standard: "stdout"
  level: "INFO"
  database: "off"
  databaselevel: "INFO"
  http: "off"
  echo: "off"
  events: "off"
  eventslevel: "INFO"
  mail: "off"
  maillevel: "INFO"

ratelimit:
  enabled: false
  kind: user
  period: 60
  limit: 100
  store: keyvalue
  noauthlimit: 10

files:
  basepath: /media/storage/vikunja # relative to the binary
  maxsize: 50MB

migration:
  todoist:
    enable: false
    clientid:
    clientsecret:
    redirecturl: <service.publicurl>/migrate/todoist
  trello:
    enable: false
    key:
    redirecturl: <frontend url>/migrate/trello
  microsofttodo:
    enable: false
    clientid:
    clientsecret:
    redirecturl: <frontend url>/migrate/microsoft-todo

avatar:
  gravatarexpiration: 3600

backgrounds:
  enabled: true
  providers:
    upload:
      enabled: true
    unsplash:
      enabled: false
      accesstoken:
      applicationid:
legal:
  imprinturl:
  privacyurl:
keyvalue:
  type: "memory"

auth:
  local:
    enabled: true
  openid:
    enabled: false
    providers:
      - name:
        authurl:
        logouturl:
        clientid:
        clientsecret:
        scope: openid email profile
metrics:
  enabled: false
  username:
  password:
defaultsettings:
  avatar_provider: initials
  avatar_file_id: 0
  email_reminders_enabled: false
  discoverable_by_name: false
  discoverable_by_email: false
  overdue_tasks_reminders_enabled: true
  overdue_tasks_reminders_time: 9:00
  default_project_id: 0
  week_start: 0
  language: en
  timezone: America/Los_Angeles

webhooks:
  enabled: true
  timeoutseconds: 30
  proxyurl:
  proxypassword:

It seems fairly clear that there is something wrong with my configuration, but I am ill-equipped to identify what. Any advice you might offer to help troubleshoot this problem would be greatly appreciated.

Update:
I took a look at bypassing nginx to see if the issue persisted. I opened Vikunja’s port and connected directly to the server, changing the frontend’s API target similarly. The issue was resolved, so I took a look into setting up a minimal nginx config as described in the documentation. This did not resolve the issue, so next I tried using the nginx upstream module instead.

upstream vikunja {
    server localhost:3456;
}

server {
    server_name vikunja.example.org;

    location / {
        proxy_pass http://vikunja;
  ...

Unfortunately, this was not adequate to work around this unexpected behavior. Making use of a reverse proxy at all seems to interfere in a way I do not quite understand.

Does it work if you access Vikunja directly, without the proxy?

Yes, that is what I tested by bypassing nginx. Connecting directly to Vikunja does not result in the same intermittent delays as doing so through a proxy.

I am not sure why only Vikunja is suffering this problem and none of the other half a dozen services nginx is pointing to; I would think the nginx configuration for this subdomain is at fault, but with or without SSL, using the upstream module or just the very basic config provided in the Vikunja documentation — regardless, the delays manifest.

Unsure why this might happen, but if it works when you access Vikunja directly without the proxy, this sounds like a proxy issue. Maybe there’s a setting which gives you more logs of the proxy, to figure out where this might come from?

I changed localhost to 127.0.0.1 in the Nginx config, and this seems to have cleared up my performance issues while accessing Vikunja via the proxied domain. I had a similar problem with Mautrix that caused Nginx to alternate between instant responses and precisely 60-second delays, and the solution was the same there.

Perhaps this is my inexperience showing, but I was under the impression 127.0.0.1 and localhost were functionally identical inputs for something like this. It appears Nginx consistently takes issue with localhost even though it still mostly works.

What a strange problem. In any case, thank you for offering what advice you could, even though it didn’t really have anything to do with Vikunja. :stuck_out_tongue:

1 Like

Ah. Typical Nginx :sob: Glad you figured this out.