Giter Club home page Giter Club logo

Comments (20)

nunombispo avatar nunombispo commented on August 27, 2024 2

Not sure if it helps, but in my case I managed to log in successfully after changing the BASE_URL.

Since I am using Plausible behind Nginx, I had the BASE_URL defined to the local IP address. Changing this to the real domain name allowed me to log in.

But now I get a websocket error and on the dashboard, I don't see graphs but entering the details of a site all is correct:

image

from analytics.

ledermann avatar ledermann commented on August 27, 2024 1

The only changes made while upgrading to v2.1.0 were bumping PostgreSQL, [...] image versions to the recommended values [...]

@nmaggioni: Besides all other things: Bumping PostgreSQL to a new major version will not work. It requires a backup/restore. Check the logs of the PostgreSQL container.

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024 1

👋 @nunombispo you probably need to enable websockets in nginx: https://github.com/plausible/community-edition/blob/c5f3386338057878648fd30af9c0462d6de78425/reverse-proxy/nginx/plausible#L12-L17

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024 1

It didn't break anything during my checks: #4126 (comment)

YMMV :)

I think BASE_URL is mainly used for URL generation and now its host is used for setting Domain attribute in the cookie for dashboard sessions.

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

👋 @nmaggioni

Would you be able to verify that SECRET_KEY_BASE env var is the same in both containers (even if untouched in plausible-conf.env)? Also would you be able to decode the contents of the _plausible_key cookie? Please see #3762 (comment)

from analytics.

nmaggioni avatar nmaggioni commented on August 27, 2024

Thanks, the contents of the cookie seem to be correct (the token matches [a-zA-Z0-9_]+ as usual):

%{
  "_csrf_token" => "<TOKEN_HERE>",
  "current_user_id" => 1,
  "last_seen" => 1716469476,
  "login_dest" => nil,
  "session_timeout_at" => 1717679076
}

This cookie was set by v2.0.0 and, I guess, ignored or rejected by v2.1.0 since I am prompted to login again. When using the new version deleting it and/or using a temporary browser profile still gets me a 403 on login and no new cookie is set.

The SECRET_KEY_BASE env var has indeed the same expected value in both images.

If that can be of interest I am deploying Plausible on Kubernetes and my manifests have been more or less the same since v1.4.4. The only changes made while upgrading to v2.1.0 were bumping PostgreSQL, ClickHouse and Plausible image versions to the recommended values and setting the new TOTP_VAULT_KEY env var.

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

The cookie data seems OK. I guess we'll need to do some tracing similar to #2767 (reply in thread)

iex> :recon_trace.calls({PlausibleWeb.AuthPlug, :call, 2}, 10)

Do you get any traces if you execute this command and then visit the dashboard?


Also would you be able to share more information on your setup? Configs, manifests, proxies, env vars, logs, etc.

from analytics.

nmaggioni avatar nmaggioni commented on August 27, 2024

@ruslandoga Here are the traces, recorded using a fresh browser profile.

Visiting the root and being served the Welcome dialog
'Elixir.PlausibleWeb.AuthPlug':call(#{owner=><0.4407.0>, port=>INTERNAL_PORT_HERE, private=>#{'Elixir.PlausibleWeb.Router'=>[], plug_session_fetch=>done, plug_session=>#{}, before_send=>[#Fun<Elixir.Phoenix.Controller.4.96996861>,
 #Fun<Elixir.Plug.Session.0.76384852>,#Fun<Elixir.Plug.Telemetry.0.54455629>], phoenix_endpoint=>'Elixir.PlausibleWeb.Endpoint', phoenix_format=><<"html">>, phoenix_router=>'Elixir.PlausibleWeb.Router', robots=><<"noindex, nofollow">>}, scheme=>http, status=>nil, script_name=>[], state=>unset, host=><<"INTERNAL_HOSTNAME_HERE">>, cookies=>#{}, params=>#{}, '__struct__'=>'Elixir.Plug.Conn', halted=>false, assigns=>#{flash=>#{}}, method=><<"GET">>, path_info=>[], adapter=>{'Elixir.Plug.Cowboy.Conn',#{pid => <0.4406.0>,port => INTERNAL_PORT_HERE,
                             scheme => <<"http">>,version => 'HTTP/1.1',
                             path => <<"/">>,host => <<"INTERNAL_HOSTNAME_HERE">>,
                             peer => {{CLIENT_IP_HERE},44704},
                             sock => {{10,42,1,88},8000},
                             bindings => #{},
                             ref => 'Elixir.PlausibleWeb.Endpoint.HTTP',
                             cert => undefined,
                             headers =>
                                 #{<<"accept">> =>
                                       <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>,
                                   <<"accept-encoding">> =>
                                       <<"gzip, deflate">>,
                                   <<"accept-language">> =>
                                       <<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>,
                                   <<"connection">> => <<"keep-alive">>,
                                   <<"host">> => <<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>,
                                   <<"upgrade-insecure-requests">> => <<"1">>,
                                   <<"user-agent">> =>
                                       <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>},
                             method => <<"GET">>,qs => <<>>,
                             path_info => undefined,body_length => 0,
                             has_body => false,streamid => 1,
                             host_info => undefined}}, secret_key_base=><<"SECRET_KEY_BASE_ENV_VAR_HERE">>, req_headers=>[{<<"accept">>,
  <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>},
 {<<"accept-encoding">>,<<"gzip, deflate">>},
 {<<"accept-language">>,<<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>},
 {<<"connection">>,<<"keep-alive">>},
 {<<"host">>,<<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>},
 {<<"upgrade-insecure-requests">>,<<"1">>},
 {<<"user-agent">>,
  <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>}], remote_ip=>{CLIENT_IP_HERE}, body_params=>#{}, query_params=>#{}, query_string=><<>>, request_path=><<"/">>, path_params=>#{}, req_cookies=>#{}, resp_body=>nil, resp_cookies=>#{}, resp_headers=>[{<<"cache-control">>,<<"max-age=0, private, must-revalidate">>},
 {<<"x-request-id">>,<<"F9IvVG98mZw3SeEAACVh">>},
 {<<"access-control-allow-credentials">>,<<"true">>},
 {<<"access-control-allow-origin">>,<<"*">>},
 {<<"access-control-expose-headers">>,<<>>},
 {<<"referrer-policy">>,<<"strict-origin-when-cross-origin">>},
 {<<"x-content-type-options">>,<<"nosniff">>},
 {<<"x-download-options">>,<<"noopen">>},
 {<<"x-frame-options">>,<<"SAMEORIGIN">>},
 {<<"x-permitted-cross-domain-policies">>,<<"none">>},
 {<<"x-robots-tag">>,<<"noindex, nofollow">>}]}, [])
Visiting the login page
'Elixir.PlausibleWeb.AuthPlug':call(#{owner=><0.4416.0>, port=>INTERNAL_PORT_HERE, private=>#{'Elixir.PlausibleWeb.Router'=>[], plug_session_fetch=>done, plug_session=>#{}, before_send=>[#Fun<Elixir.Phoenix.Controller.4.96996861>,
 #Fun<Elixir.Plug.Session.0.76384852>,#Fun<Elixir.Plug.Telemetry.0.54455629>], phoenix_endpoint=>'Elixir.PlausibleWeb.Endpoint', phoenix_format=><<"html">>, phoenix_router=>'Elixir.PlausibleWeb.Router', robots=><<"noindex, nofollow">>}, scheme=>http, status=>nil, script_name=>[], state=>unset, host=><<"INTERNAL_HOSTNAME_HERE">>, cookies=>#{}, params=>#{}, '__struct__'=>'Elixir.Plug.Conn', halted=>false, assigns=>#{flash=>#{}}, method=><<"GET">>, path_info=>[<<"login">>], adapter=>{'Elixir.Plug.Cowboy.Conn',#{pid => <0.4406.0>,port => INTERNAL_PORT_HERE,
                             scheme => <<"http">>,version => 'HTTP/1.1',
                             path => <<"/login">>,
                             host => <<"INTERNAL_HOSTNAME_HERE">>,
                             peer => {{CLIENT_IP_HERE},44704},
                             sock => {{10,42,1,88},8000},
                             bindings => #{},
                             ref => 'Elixir.PlausibleWeb.Endpoint.HTTP',
                             cert => undefined,
                             headers =>
                                 #{<<"accept">> =>
                                       <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>,
                                   <<"accept-encoding">> =>
                                       <<"gzip, deflate">>,
                                   <<"accept-language">> =>
                                       <<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>,
                                   <<"connection">> => <<"keep-alive">>,
                                   <<"host">> => <<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>,
                                   <<"referer">> =>
                                       <<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE/">>,
                                   <<"upgrade-insecure-requests">> => <<"1">>,
                                   <<"user-agent">> =>
                                       <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>},
                             method => <<"GET">>,qs => <<>>,
                             path_info => undefined,body_length => 0,
                             has_body => false,streamid => 3,
                             host_info => undefined}}, secret_key_base=><<"SECRET_KEY_BASE_ENV_VAR_HERE">>, req_headers=>[{<<"accept">>,
  <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>},
 {<<"accept-encoding">>,<<"gzip, deflate">>},
 {<<"accept-language">>,<<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>},
 {<<"connection">>,<<"keep-alive">>},
 {<<"host">>,<<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>},
 {<<"referer">>,<<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE/">>},
 {<<"upgrade-insecure-requests">>,<<"1">>},
 {<<"user-agent">>,
  <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>}], remote_ip=>{CLIENT_IP_HERE}, body_params=>#{}, query_params=>#{}, query_string=><<>>, request_path=><<"/login">>, path_params=>#{}, req_cookies=>#{}, resp_body=>nil, resp_cookies=>#{}, resp_headers=>[{<<"cache-control">>,<<"max-age=0, private, must-revalidate">>},
 {<<"x-request-id">>,<<"F9IvXDuFqRl3FxYAACYh">>},
 {<<"access-control-allow-credentials">>,<<"true">>},
 {<<"access-control-allow-origin">>,<<"*">>},
 {<<"access-control-expose-headers">>,<<>>},
 {<<"referrer-policy">>,<<"strict-origin-when-cross-origin">>},
 {<<"x-content-type-options">>,<<"nosniff">>},
 {<<"x-download-options">>,<<"noopen">>},
 {<<"x-frame-options">>,<<"SAMEORIGIN">>},
 {<<"x-permitted-cross-domain-policies">>,<<"none">>},
 {<<"x-robots-tag">>,<<"noindex, nofollow">>}]}, [])
Logging in and receiving the customized 403 page
'Elixir.PlausibleWeb.AuthPlug':call(#{owner=><0.4427.0>, port=>INTERNAL_PORT_HERE, private=>#{'Elixir.PlausibleWeb.Router'=>[], plug_session_fetch=>done, plug_session=>#{}, before_send=>[#Fun<Elixir.Phoenix.Controller.4.96996861>,
 #Fun<Elixir.Plug.Session.0.76384852>,#Fun<Elixir.Plug.Telemetry.0.54455629>], phoenix_endpoint=>'Elixir.PlausibleWeb.Endpoint', phoenix_format=><<"html">>, phoenix_router=>'Elixir.PlausibleWeb.Router', robots=><<"noindex, nofollow">>}, scheme=>http, status=>nil, script_name=>[], state=>unset, host=><<"INTERNAL_HOSTNAME_HERE">>, cookies=>#{}, params=>#{<<"_csrf_token">>=><<"DiN8JgMHIjwJPXUpGjoPZyAHFEQYE0wYAgNkaeHqsYGLQJe4WIFtwaxH">>, <<"email">>=><<"USERNAME_HERE">>, <<"password">>=><<"PASSWORD_HERE">>}, '__struct__'=>'Elixir.Plug.Conn', halted=>false, assigns=>#{flash=>#{}}, method=><<"POST">>, path_info=>[<<"login">>], adapter=>{'Elixir.Plug.Cowboy.Conn',#{pid => <0.4406.0>,port => INTERNAL_PORT_HERE,
                             scheme => <<"http">>,version => 'HTTP/1.1',
                             path => <<"/login">>,
                             host => <<"INTERNAL_HOSTNAME_HERE">>,
                             peer => {{CLIENT_IP_HERE},44704},
                             sock => {{10,42,1,88},8000},
                             bindings => #{},
                             ref => 'Elixir.PlausibleWeb.Endpoint.HTTP',
                             cert => undefined,
                             headers =>
                                 #{<<"accept">> =>
                                       <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>,
                                   <<"accept-encoding">> =>
                                       <<"gzip, deflate">>,
                                   <<"accept-language">> =>
                                       <<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>,
                                   <<"cache-control">> => <<"max-age=0">>,
                                   <<"connection">> => <<"keep-alive">>,
                                   <<"content-length">> => <<"133">>,
                                   <<"content-type">> =>
                                       <<"application/x-www-form-urlencoded">>,
                                   <<"host">> => <<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>,
                                   <<"origin">> =>
                                       <<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>,
                                   <<"referer">> =>
                                       <<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE/login">>,
                                   <<"upgrade-insecure-requests">> => <<"1">>,
                                   <<"user-agent">> =>
                                       <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>},
                             method => <<"POST">>,qs => <<>>,
                             path_info => undefined,body_length => 133,
                             has_body => true,streamid => 4,
                             host_info => undefined,has_read_body => true}}, secret_key_base=><<"SECRET_KEY_BASE_ENV_VAR_HERE">>, req_headers=>[{<<"accept">>,
  <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>},
 {<<"accept-encoding">>,<<"gzip, deflate">>},
 {<<"accept-language">>,<<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>},
 {<<"cache-control">>,<<"max-age=0">>},
 {<<"connection">>,<<"keep-alive">>},
 {<<"content-length">>,<<"133">>},
 {<<"content-type">>,<<"application/x-www-form-urlencoded">>},
 {<<"host">>,<<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>},
 {<<"origin">>,<<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>},
 {<<"referer">>,<<"http://INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE/login">>},
 {<<"upgrade-insecure-requests">>,<<"1">>},
 {<<"user-agent">>,
  <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>}], remote_ip=>{CLIENT_IP_HERE}, body_params=>#{<<"_csrf_token">>=><<"DiN8JgMHIjwJPXUpGjoPZyAHFEQYE0wYAgNkaeHqsYGLQJe4WIFtwaxH">>, <<"email">>=><<"USERNAME_HERE">>, <<"password">>=><<"PASSWORD_HERE">>}, query_params=>#{}, query_string=><<>>, request_path=><<"/login">>, path_params=>#{}, req_cookies=>#{}, resp_body=>nil, resp_cookies=>#{}, resp_headers=>[{<<"cache-control">>,<<"max-age=0, private, must-revalidate">>},
 {<<"x-request-id">>,<<"F9IvZhFTQP3eEl8AACdh">>},
 {<<"access-control-allow-credentials">>,<<"true">>},
 {<<"access-control-allow-origin">>,<<"*">>},
 {<<"access-control-expose-headers">>,<<>>},
 {<<"referrer-policy">>,<<"strict-origin-when-cross-origin">>},
 {<<"x-content-type-options">>,<<"nosniff">>},
 {<<"x-download-options">>,<<"noopen">>},
 {<<"x-frame-options">>,<<"SAMEORIGIN">>},
 {<<"x-permitted-cross-domain-policies">>,<<"none">>},
 {<<"x-robots-tag">>,<<"noindex, nofollow">>}]}, [])
Navigating back the root and being served the Welcome dialog once again
'Elixir.PlausibleWeb.AuthPlug':call(#{owner=><0.4403.0>, port=>INTERNAL_PORT_HERE, private=>#{'Elixir.PlausibleWeb.Router'=>[], plug_session_fetch=>done, plug_session=>#{}, before_send=>[#Fun<Elixir.Phoenix.Controller.4.96996861>,
 #Fun<Elixir.Plug.Session.0.76384852>,#Fun<Elixir.Plug.Telemetry.0.54455629>], phoenix_endpoint=>'Elixir.PlausibleWeb.Endpoint', phoenix_format=><<"html">>, phoenix_router=>'Elixir.PlausibleWeb.Router', robots=><<"noindex, nofollow">>}, scheme=>http, status=>nil, script_name=>[], state=>unset, host=><<"INTERNAL_HOSTNAME_HERE">>, cookies=>#{}, params=>#{}, '__struct__'=>'Elixir.Plug.Conn', halted=>false, assigns=>#{flash=>#{}}, method=><<"GET">>, path_info=>[], req_headers=>[{<<"accept">>,
  <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>},
 {<<"accept-encoding">>,<<"gzip, deflate">>},
 {<<"accept-language">>,<<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>},
 {<<"connection">>,<<"keep-alive">>},
 {<<"host">>,<<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>},
 {<<"upgrade-insecure-requests">>,<<"1">>},
 {<<"user-agent">>,
  <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>}], remote_ip=>{CLIENT_IP_HERE}, adapter=>{'Elixir.Plug.Cowboy.Conn',#{pid => <0.4387.0>,port => INTERNAL_PORT_HERE,
                             scheme => <<"http">>,version => 'HTTP/1.1',
                             path => <<"/">>,host => <<"INTERNAL_HOSTNAME_HERE">>,
                             peer => {{CLIENT_IP_HERE},48096},
                             sock => {{10,42,1,90},8000},
                             bindings => #{},
                             ref => 'Elixir.PlausibleWeb.Endpoint.HTTP',
                             cert => undefined,
                             headers =>
                                 #{<<"accept">> =>
                                       <<"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7">>,
                                   <<"accept-encoding">> =>
                                       <<"gzip, deflate">>,
                                   <<"accept-language">> =>
                                       <<"it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7">>,
                                   <<"connection">> => <<"keep-alive">>,
                                   <<"host">> => <<"INTERNAL_HOSTNAME_HERE:INTERNAL_PORT_HERE">>,
                                   <<"upgrade-insecure-requests">> => <<"1">>,
                                   <<"user-agent">> =>
                                       <<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36">>},
                             method => <<"GET">>,qs => <<>>,
                             path_info => undefined,streamid => 7,
                             body_length => 0,has_body => false,
                             host_info => undefined}}, body_params=>#{}, query_params=>#{}, query_string=><<>>, request_path=><<"/">>, secret_key_base=><<"SECRET_KEY_BASE_ENV_VAR_HERE">>, resp_body=>nil, resp_cookies=>#{}, resp_headers=>[{<<"cache-control">>,<<"max-age=0, private, must-revalidate">>},
 {<<"x-request-id">>,<<"F9Iw2qjk2SXhwd8AACYB">>},
 {<<"access-control-allow-credentials">>,<<"true">>},
 {<<"access-control-allow-origin">>,<<"*">>},
 {<<"access-control-expose-headers">>,<<>>},
 {<<"referrer-policy">>,<<"strict-origin-when-cross-origin">>},
 {<<"x-content-type-options">>,<<"nosniff">>},
 {<<"x-download-options">>,<<"noopen">>},
 {<<"x-frame-options">>,<<"SAMEORIGIN">>},
 {<<"x-permitted-cross-domain-policies">>,<<"none">>},
 {<<"x-robots-tag">>,<<"noindex, nofollow">>}], req_cookies=>#{}, path_params=>#{}}, [])

By enabling query logging on Postgres through the -c log_statement=all flag I saw that (on top of the background noise generated by Oban jobs) only a single query was being made when serving each of the above requests: SELECT TRUE FROM "users" AS u0 LIMIT 1. Running this query manually returns t as expected.

I have no Elixir knowledge but while I was at it I have also tried tracing other Plugs out of curiosity and, while FirstLaunchPlug, LastSeenPlug, NoRobots, SessionTimeoutPlug, Tracker produced some output when POSTing the login data, none of them seemed to log anything that caught my eye.

Here are the relevant portions of my K8S manifest:

K8S deployment
# PostgreSQL
---
apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: plausible
spec:
  type: ClusterIP
  ports:
    - name: postgres
      port: 5432
      targetPort: 5432
      protocol: TCP
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: plausible
spec:
  replicas: 1
  serviceName: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:16-alpine
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
          env: # Auth vars
      volumes:
        - name: data
          hostPath:
            path: # Unix path
            type: Directory

# Plausible
---
apiVersion: v1
kind: Secret
metadata:
  name: plausible
  namespace: plausible
type: Opaque
data:
  secretKeyBase: # SECRET_KEY_BASE value re-encoded to base64
  totpVaultKey: # TOTP_VAULT_KEY value re-encoded to base64
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: plausible
  namespace: plausible
spec:
  replicas: 1
    spec:
      initContainers:
        - name: wait-postgres
          image: docker.io/library/alpine:3.17
          command: ["sh", "-c", "for i in $(seq 1 300); do nc -zvw1 postgres 5432 && exit 0 || sleep 3; done; exit 1"]
        - name: wait-clickhouse
          image: docker.io/library/alpine:3.17
          command: ["sh", "-c", "for i in $(seq 1 300); do nc -zvw1 clickhouse 8123 && exit 0 || sleep 3; done; exit 1"]
      containers:
        - name: plausible
          image: plausible/analytics:v2.0.0  # ghcr.io/plausible/community-edition:v2.1.0
          env:
            - name: BASE_URL
              value: # EXTERNAL URL
            - name: SECRET_KEY_BASE
              valueFrom:
                secretKeyRef:
                  name: plausible
                  key: secretKeyBase
                  optional: false
            - name: TOTP_VAULT_KEY
              valueFrom:
                secretKeyRef:
                  name: plausible
                  key: totpVaultKey
                  optional: false
            - name: GEOLITE2_COUNTRY_DB
              value: /geoip/GeoLite2-Country.mmdb
            - name: IP_GEOLOCATION_DB
              value: /geoip/GeoLite2-City.mmdb
            - name: GEONAMES_SOURCE_FILE
              value: /geoip/geonames.lite.csv
            - name: DISABLE_REGISTRATION
              value: "true"
            - name: MAILER_EMAIL
              value: # Sender address
            - name: CRON_ENABLED
              value: "true"
            - name: DATABASE_URL
              value: "postgres://<USERNAME>:<PASSWORD>@postgres:5432/plausible_db"
            - name: CLICKHOUSE_DATABASE_URL
              value: "http://clickhouse:8123/plausible_events_db"
            - name: SMTP_HOST_ADDR
              value: "mailer"
            - name: SMTP_HOST_PORT
              value: "25"
          ports:
            - protocol: TCP
              containerPort: 8000
              hostPort: # Host port
          livenessProbe:
            httpGet:
              path: /api/health
              port: 8000
          readinessProbe:
            httpGet:
              path: /api/health
              port: 8000
          command: ["/bin/sh"]
          args: ["-c", "/entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh run"]
          volumeMounts:
            - mountPath: /geoip
              name: geoip
              readOnly: true
      volumes:
        - name: geoip
          hostPath:
            path: # Unix path
            type: Directory

For these tests I am accessing the instance locally through its exposed port.


@ledermann My bad, I took that for granted and did not elaborate for the sake of brevity. The upgrade was indeed done as recommended and Postgres shows no errors at startup or when trying to log in. ClickHouse seems happy too, just in case.

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

@nmaggioni the traces show that there are no cookies being passed into the requests. Please check that your BASE_URL is the same as the cookie domain and please share your reverse-proxy setup. I've tried to reproduce the problem by starting docker compose with plausible:v2.0.0, logging in, and then upgrading to v2.1.0 but it all works as expected. So it seems to be a configuration issue.

from analytics.

nmaggioni avatar nmaggioni commented on August 27, 2024

@ruslandoga Sorry for not proving enough info from the start, I am trying to pinpoint the issue as we go. I am running a split-horizon setup, in which the necessary tracking scripts are accessible from public networks while the management interface itself is not; when clients request the tracking snippet they ultimately hit a Caddy proxy configured as such:

@tracking_paths path /js/plausible.js /api/event /api/error

handle @tracking_paths {
  reverse_proxy <INTERNAL_HOST>:<INTERNAL_PORT> {
    header_down Access-Control-Allow-Origin [...]
  }
}

handle {
  abort
}

Basically all Caddy is doing here is passing on the requests to /js/plausible.js, /api/event and /api/error to the actual Plausible instance, adding a necessary Access-Control-Allow-Origin header on the reply, and denying everything else. When I need to check the tracking stats I head to <INTERNAL_HOST>:<INTERNAL_PORT> from the local network and do my business.

This flow has been working for quite some time and a behavioral change in v2.1.0 has broken it, so I don't think this is a configuration issue. Obligatory xkcd, I know.

Again, I'm no Elixir expert, but could the issue stem from the CSRF tokens being tied to the session and in turn it now being tied to the BASE_URL instead of the domain the login request is received at? Could this commit explain the new behavior? Am I relying on an edge case of Plug.Session's default configuration?
I have spun up a local development environment to confirm this suspicion and indeed, with BASE_URL=http://localhost:8000 (and LISTEN_IP=0.0.0.0 since I'm juggling development containers) I can login just fine through localhost but CSRF validation fails when I try to do the same through my machine's IP address. The port is 8888 instead of 8000 due to the devcontainer's port forwarding.

screencapture-10-0-0-37-8888-login-2024-05-24-16_47_32

If I login through localhost, copy the session cookie and manually add it in the browser for the bare IP "domain" too, I can get to the dashboard without triggering CSRF errors. It then breaks because the session is not valid and the WS connection can't be stabilished, but that's obvious. Am I on the right track, could the (I'm guessing here!) new BASE_URL usage be the curlprit?

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

@nmaggioni thank you for a comprehensive reply! I'll try reproducing this later following your split setup.

I have one question though, do sessions work if BASE_URL is set to the machine's IP address + 8888 port? The listening port can be configured separately via PORT env var.

from analytics.

nunombispo avatar nunombispo commented on August 27, 2024

👋 @nunombispo you probably need to enable websockets in nginx: https://github.com/plausible/community-edition/blob/c5f3386338057878648fd30af9c0462d6de78425/reverse-proxy/nginx/plausible#L12-L17

@ruslandoga thanks for the info. Since I am using Nginx proxy manager it was just setting a flag for websocket support.

So for me, this worked (behind Nginx):

  • Setting the BASE_URL for the domain and not the internal IP address
  • Enabling websocket support

from analytics.

nmaggioni avatar nmaggioni commented on August 27, 2024

do sessions work if BASE_URL is set to the machine's IP address + 8888 port? The listening port can be configured separately via PORT env var.

@ruslandoga They indeed do and connections through other hostnames/IPs break as expected. The port is not taken into account as far as I can see.

I'm struggling to grasp why my setup was/is working at all then: I suppose that commenting this line is the equivalent to minimally reverting the commit I mentioned above in the current codebase and doing that in fact solves the CSRF errors (but not the WS ones), but that doesn't explain much.

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

They indeed do and connections through other hostnames/IPs break as expected.

@nmaggioni So it works? Or is there a problem still?

I've tried running a CE build locally with BASE_URL=http://127.0.0.1:8000 to simulate your internal URL and login (forms), sites (websockets), dashboards (ajax), etc. seem to work fine.

Posting events to an "external" URL like http://localhost:8000/api/event also works and the events show up on the dashboard. http://localhost:8000/js/plausible.js works too.

from analytics.

ZackBoe avatar ZackBoe commented on August 27, 2024

I'm seeing this when attempting to login via multiple domains. Events are still coming in on both domains, but I can only login from whichever is set as the BASE_URL.

from analytics.

nmaggioni avatar nmaggioni commented on August 27, 2024

@ruslandoga I've waited a couple of days and data is being collected without evident discrepancies, so I would say that the base URL change was enough to fix the issue without side effects on the tracking activities. My notes said that such variable was set to the external domain value due to it being involved in the tracking snippet's code, but most probably that referred to a behavior that was dropped long ago by either Plausible or my own network architecture. That is indeed a thing of the past as linked by @ZackBoe.

What @ZackBoe wrote still holds, though: the dashboard is now served on a single, fixed URL. That does not impact my use case since I have already worked around it at the network level, but I can see how that would not always be a viable approach.

from analytics.

wheeleran avatar wheeleran commented on August 27, 2024

just to add to this and confuse things, i've just updated to v.2.1.1 and had to delete and then recreate my websocket proxies to be able to log on to Plausible self-hosted on a Synology NAS. no idea why, but i'm finally up, after not being able to get v.2.1.0 running either after everything running fine on 2.1.0.rc.1 for ages.

from analytics.

mpas97 avatar mpas97 commented on August 27, 2024

I just upgraded our plausible instance on k8s 2.0.0 -> 2.1.0. Now I'm also getting that 403, although it worked before. I then reset the password directly in the database, because I first though I may have got broken somehow. However, it was still impossible to login afterwards.

As soon as I've read through this (closed) issue, I tried to fake the k8s internal dns on my local machine by setting 127.0.0.1 analytics.plausible.svc.cluster.local in my /etc/hosts. This because I used to access the instance on localhost:8000 (via kubectl port-forward) only when I really needed backend access. Else serving the API within the cluster is more than enough.

With that, the login works again. But that can't be a solution... Can we reopen this?

from analytics.

ruslandoga avatar ruslandoga commented on August 27, 2024

@mpas97 👋

If you access the dashboard on localhost:8000 then setting BASE_URL=http://localhost:8000 should work. I'll check with the core team if it's possible to make the cookie domain-less again.

from analytics.

mpas97 avatar mpas97 commented on August 27, 2024

@ruslandoga thanks a lot for that hint. Would be nice if it works, but as everything within the cluster uses servicename.namespace.svc.cluster.local (current BASE_URL) to connect, would that not break more than it actually fixes? This variable is then only relevant for dashboard logins, correct? And for instance the API will still work with a non-matching URL?

from analytics.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.