Files
neko/webpage/docs/reverse-proxy-setup.md
T
SamAcctX 5f40eb9388 docs: fix Apache websocket rewrite for /api/ws (#717)
The Apache example forwarded websocket upgrades with
`RewriteRule /ws(.*) "ws://localhost:8080/ws$1"`. The pattern is not
anchored, so `/api/ws` matches it too and is rewritten to `/ws`, the
legacy endpoint. The 3.2 client connects to `/api/ws?token=...`; through
this rule the legacy handler sees no username/password, logs in with
empty credentials and answers `system/disconnect` ("couldn't create a
new session: error response from backend: Unauthorized"), while the
server logs `invalid password` from the legacy proxy.

Forward every websocket upgrade to the same path instead. Verified with
httpd:2.4 in front of ghcr.io/m1k1o/neko/firefox:3.2.0: the old rule
reproduces the error, the new one connects the 3.2 client and still
serves legacy `/ws` clients.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-16 21:43:34 +02:00

6.9 KiB

Reverse Proxy Setup

If you want to run Neko behind a reverse proxy, you can use the following examples to configure your server.

:::tip Do not forget to enable server.proxy=true in your config.yml file to allow the server to trust the proxy headers. :::

Neko pings websocket client every 10 seconds, and client is scheduled to send heartbeat to the server every 120 seconds. Make sure, that your timeout settings in the reverse proxy are set accordingly.

Traefik v2

See the example below for a docker-compose.yml file.

labels:
  - "traefik.enable=true"
  - "traefik.http.services.neko-frontend.loadbalancer.server.port=8080"
  - "traefik.http.routers.neko.rule=${TRAEFIK_RULE}"
  - "traefik.http.routers.neko.entrypoints=${TRAEFIK_ENTRYPOINTS}"
  - "traefik.http.routers.neko.tls.certresolver=${TRAEFIK_CERTRESOLVER}"

For more information, check out the official Traefik documentation. For SSL, see the official Traefik SSL documentation.

Nginx

See the example below for an Nginx configuration file.

server {
  listen 443 ssl http2;
  server_name example.com;

  location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_cache_bypass $http_upgrade;
  }
}

For more information, check out the official Nginx documentation. For SSL, see the official Nginx SSL documentation or use certbot.

Apache

To do this, you need to have a running Apache server. Navigate to the /etc/apache2/sites-available folder and create a new configuration file, for example, neko.conf.

After creating the new configuration file, you can use the example below and paste it in. Some things may vary on your machine, so read through and modify it if needed.

Bear in mind that your Neko server does not have to run on the same computer as Apache. They just need to be on the same network, and then you replace localhost with the correct internal IP.

<VirtualHost *:80>
  # The ServerName directive sets the request scheme, hostname, and port that
  # the server uses to identify itself. This is used when creating
  # redirection URLs. In the context of virtual hosts, the ServerName
  # specifies what hostname must appear in the request's Host: header to
  # match this virtual host. For the default virtual host (this file), this
  # value is not decisive as it is used as a last resort host regardless.
  # However, you must set it explicitly for any further virtual host.

  # Paths of these modules might vary across different distros.
  LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
  LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
  LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so

  ServerName example.com
  ServerAlias www.example.com

  ProxyRequests Off
  ProxyPass / http://localhost:8080/
  ProxyPassReverse / http://localhost:8080/

  RewriteEngine on
  RewriteCond %{HTTP:Upgrade} websocket [NC]
  RewriteCond %{HTTP:Connection} upgrade [NC]
  # forward every websocket upgrade to the same path (the client connects to /api/ws)
  RewriteRule ^/(.*) "ws://localhost:8080/$1" [P,L]

  # Available log levels: trace8, ..., trace1, debug, info, notice, warn,
  # error, crit, alert, emerg.
  # It is also possible to configure the log level for particular
  # modules, e.g.
  #LogLevel info ssl:warn

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  # For most configuration files from conf-available/, which are
  # enabled or disabled at a global level, it is possible to
  # include a line for only one particular virtual host. For example, the
  # following line enables the CGI configuration for this host only
  # after it has been globally disabled with "a2disconf".
  #Include conf-available/serve-cgi-bin.conf
</VirtualHost>

After creating your new configuration file, just use sudo a2ensite neko.conf and then sudo systemctl reload apache2.

See the official Apache documentation for more information. For SSL, see the official Apache SSL documentation or use certbot.

Caddy

See the example below for a Caddyfile.

https://example.com {
  reverse_proxy localhost:8080
}

For more information, check out the official Caddy documentation. For SSL, see the official Caddy automatic HTTPS documentation.

HAProxy

Using your frontend section (mine is called http-in), add the ACL to redirect correctly to your Neko instance.

frontend http-in
  #/********
  #* NEKO *
  acl neko_rule_http hdr(host) neko.domain.com # Adapt the domain
  use_backend neko_srv if neko_rule_http
  #********/

backend neko_srv
  mode http
  option httpchk
      server neko 172.16.0.0:8080 # Adapt the IP

Then, restart the HAProxy service.

service haproxy restart

See the official HAProxy documentation for more information.

Troubleshooting HAProxy Issues

If you're having trouble reaching your HAProxy instance, try the following steps:

  1. Check HAProxy Logs
    Verify what HAProxy is reporting by checking its status:

    service haproxy status
    
  2. Monitor Logs in Real-Time
    If the service is running and the ACL rule and backend configuration seem correct, tail the logs to investigate further:

    tail -f /var/log/haproxy.log
    

    Then, access your neko.instance.com and observe the logs for any issues.

  3. Adjust Timeout Settings
    Ensure the global timeout is set to 60 seconds to prevent premature request failures:

    global
      stats timeout 60s
    
  4. Configure Defaults Section
    Add the following settings to the defaults section to handle timeouts and forward headers properly:

    defaults
      option forwardfor
      timeout connect 30000
      timeout client  65000
      timeout server  65000
    

:::note Don't forget to restart the service each time you modify the .cfg file! :::