kagemomiji / airsonic-advanced

airsonic-advanced
GNU General Public License v3.0
142 stars 13 forks source link

[Bug]: Settings page does not display when using UI when using HTTPS URL #482

Closed litebito closed 1 month ago

litebito commented 1 month ago

What happened?

I've updated my setup to use SSL (https) Since then, I've come across some weird behavior in the UI. I observe the following when using the main menu:

when I hover over the Setting menu, I can see that it wants to go to: https://loftstream.xxx.xyz:14443/settings

Steps to reproduce

  1. Open the URL to HTTPS://hostname:14443 (going through a reverse proxy, this is translated to http://localhost:14040)
  2. Login with an admin user
  3. After the main page shows
  4. click on settings in the menu
  5. nothing happens

Version

11.1.4-SNAPSHOT (Edge)

Version Detail

11.1.4-SNAPSHOT.20240518150716

Operating System

Centos 9 Stream

Java Version

Java: 17.0.6+10-LTS

Database

Other

DB Detail

PostgreSQL 16

Configuration parameter

# cat /etc/sysconfig/airsonic
# Set the location of the standalone war to use
JAVA_JAR=/var/airsonic/airsonic.war

# Set any java opts separated by spaces
JAVA_OPTS=-Xmx4096m -Xms4096m

# Set a different location for airsonic home.
# If this path is /var/libresonic or even contains "libresonic",
# the data from a previous libresonic can be used as is (i.e. without
# renaming libresonic.properties,db/libresonic*,etc
AIRSONIC_HOME=/var/airsonic

# Change the port to listen on
PORT=14040

# Change the path that is listened on
CONTEXT_PATH=/

# Add any java args. These are different than JAVA_OPTS in that
# they are passed directly to the program. The default is empty:
#JAVA_ARGS=

# Note that there are several settings for spring boot, not explicitly listed
# here, but can be used in either JAVA_OPTS or JAVA_ARGS. The full list
# can be found here:
# https://docs.spring.io/spring-boot/docs/1.4.5.RELEASE/reference/htmlsingle/#common-application-properties
# For example to set debug across the board:
#JAVA_ARGS=--debug

# Or to change the ip address that is listened on:
#JAVA_ARGS=--server.address=127.0.0.1

JAVA_ARGS=--logging.level.org.airsonic=info

# cat /etc/systemd/system/airsonic.service
[Unit]
Description=Airsonic Media Server
After=remote-fs.target network.target
AssertPathExists=/var/airsonic

[Service]
Type=simple
Environment="JAVA_JAR=/var/airsonic/airsonic.war"
Environment="JAVA_OPTS=-Xmx4096m -Xms4096m"
Environment="AIRSONIC_HOME=/var/airsonic"
Environment="PORT=14040"
Environment="CONTEXT_PATH=/"
Environment="JAVA_ARGS="
EnvironmentFile=-/etc/sysconfig/airsonic
ExecStart=/usr/bin/java \
          $JAVA_OPTS \
          -Dairsonic.home=${AIRSONIC_HOME} \
          -Dserver.servlet.context-path=${CONTEXT_PATH} \
          -Dserver.port=${PORT} \
          -Dfile.encoding=UTF-8 \
          -Dsun.jnu.encoding=UTF-8 \
          -jar ${JAVA_JAR} $JAVA_ARGS
User=airsonic
Group=airsonic

# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
# for details
DevicePolicy=closed
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallFilter=@basic-io @file-system @chown @network-io @sync @timer @signal @process @system-service
ReadWritePaths=/var/airsonic

# You can change the following line to `strict` instead of `full`
# if you don't want airsonic to be able to
# write anything on your filesystem outside of AIRSONIC_HOME.
ProtectSystem=full

# You can uncomment the following line if you don't have any media
# in /home/…. This will prevent airsonic from ever reading/writing anything there.
#ProtectHome=true

# You can uncomment the following line if you're not using the OpenJDK.
# This will prevent processes from having a memory zone that is both writeable
# and executeable, making hacker's lifes a bit harder.
#MemoryDenyWriteExecute=yes

[Install]
WantedBy=multi-user.target

### Proxy Server

Apache 2.4.57

### client detail

Chrome, Edge, Firefox

### language

None

### Relevant log output
From the browser dev output:

Mixed Content: The page at 'https://loftstream.xxx.xyz:14443/index' was loaded over HTTPS, but requested an insecure resource 'http://loftstream.xxx.xyz:14443/musicFolderSettings'. This request has been blocked; the content must be served over HTTPS.
top:1  Mixed Content: The page at 'https://loftstream.xxx.xyz:14443/index' was loaded over HTTPS, but requested an insecure resource 'http://loftstream.xxx.xyz:14443/home'. This request has been blocked; the content must be served over HTTPS.
kagemomiji commented 1 month ago

@litebito Could you add -Dserver.forward-headers-strategy=native to the following part

ExecStart=/usr/bin/java \
          $JAVA_OPTS \
          -Dairsonic.home=${AIRSONIC_HOME} \
          -Dserver.servlet.context-path=${CONTEXT_PATH} \
          -Dserver.port=${PORT} \
          -Dfile.encoding=UTF-8 \
          -Dserver.forward-headers-strategy=native  #here
          -Dsun.jnu.encoding=UTF-8 \
          -jar ${JAVA_JAR} $JAVA_ARGS
litebito commented 1 month ago

@kagemomiji I did, and restarted both airsonic and httpd still the same issue and error

kagemomiji commented 1 month ago

@litebito I have tried with httpd (Apache 2.4.56) but I could not reproduce this issue. The folloing is my tested configuration which is masked ServerName and <airsonic-host>. Could you check your configuration. reference Airsonic Doc

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    SSLEngine On
    SSLCertificateFile "/usr/local/apache2/conf/server.crt"
    SSLCertificateKeyFile "/usr/local/apache2/conf/server.key"
    SSLProxyEngine on
    ServerName example.com
    LogLevel warn

    ProxyPass         /websocket/ ws://<airsonic-host>:4040/websocket/
    ProxyPassReverse  /websocket/ ws://<airsonic-host>:4040/websocket/
    ProxyPass         / http://<airsonic-host>:4040/
    ProxyPassReverse  / http://<airsonic-host>:4040/
    RequestHeader     set       X-Forwarded-Proto "https"
</VirtualHost>
thewriteway commented 1 month ago

I had a similar issue that was resolved by directly adding server.forward-headers-strategy=framework to the airsonic.properties file although its recommended to use the exec start method mentioned by kagemomiji.

This configures the Java Spring framework to correctly use the headers that are being set in the reverse proxy.

The headers to consider: X-Forwarded-Proto, X-Forwarded-Host, and X-Forwarded-Port.

Be sure to restart your Airsonic-advanced application and the reverse proxy service for the changes to take effect.

litebito commented 1 month ago

Hi,

@thewriteway I tried this, and restarted airsonic and httpd, no change, the issue is still there

But I saw that my httpd config for the server was different than the one from @kagemomiji the /websocket lines were missing, and the RequestHeader line was missing. So I updated that also.

SUCCESS: The combination of both changes resolves the issue

This is my httpd config for the airsonic server now:

/etc/httpd/conf.d/loftstream.conf:

Header always set Strict-Transport-Security "max-age=15552001; includeSubDomains;"

<VirtualHost *:14443>
    ServerName loftstream.xxx.xyz

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/loftstream.xxx.xyz/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/loftstream.xxx.xyz/privkey.pem

    ProxyPreserveHost On

    ProxyPass /websocket ws://localhost:14040/websocket
    ProxyPassReverse /websocket ws://localhost:14040/websocket

    ProxyPass / http://localhost:14040/
    ProxyPassReverse / http://localhost:14040/

    RequestHeader set X-Forwarded-Proto "https"

    <Location />
        Require all granted
    </Location>
</VirtualHost>

And

/etc/systemd/system/airsonic.service:

[Unit]
Description=Airsonic Media Server
After=remote-fs.target network.target
AssertPathExists=/var/airsonic

[Service]
Type=simple
Environment="JAVA_JAR=/var/airsonic/airsonic.war"
Environment="JAVA_OPTS=-Xmx4096m -Xms4096m"
Environment="AIRSONIC_HOME=/var/airsonic"
Environment="PORT=14040"
Environment="CONTEXT_PATH=/"
Environment="JAVA_ARGS="
EnvironmentFile=-/etc/sysconfig/airsonic
ExecStart=/usr/bin/java \
          $JAVA_OPTS \
          -Dairsonic.home=${AIRSONIC_HOME} \
          -Dserver.servlet.context-path=${CONTEXT_PATH} \
          -Dserver.port=${PORT} \
          -Dfile.encoding=UTF-8 \
          -Dserver.forward-headers-strategy=framework \
          -Dsun.jnu.encoding=UTF-8 \
          -jar ${JAVA_JAR} $JAVA_ARGS
User=airsonic
Group=airsonic

# See https://www.freedesktop.org/software/systemd/man/systemd.exec.html
# for details
DevicePolicy=closed
NoNewPrivileges=yes
PrivateDevices=yes
PrivateTmp=yes
PrivateUsers=yes
ProtectControlGroups=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
SystemCallFilter=@basic-io @file-system @chown @network-io @sync @timer @signal @process @system-service
ReadWritePaths=/var/airsonic

# You can change the following line to `strict` instead of `full`
# if you don't want airsonic to be able to
# write anything on your filesystem outside of AIRSONIC_HOME.
ProtectSystem=full

# You can uncomment the following line if you don't have any media
# in /home/…. This will prevent airsonic from ever reading/writing anything there.
#ProtectHome=true

# You can uncomment the following line if you're not using the OpenJDK.
# This will prevent processes from having a memory zone that is both writeable
# and executeable, making hacker's lifes a bit harder.
#MemoryDenyWriteExecute=yes

[Install]
WantedBy=multi-user.target

Note: The reason I'm using port 14443 is that I cannot use 443 from outside my network, I use 443 for another incoming service. And I want to use the same URI internal and externally (for example in the mobile apps and so). And obviously, you cannot have both httpd and airsonic listening on the same port: I decided to use 14443 to access the app, and run the app locally on 14040.

kagemomiji commented 1 month ago

@thewriteway @litebito Thanks to you, I figured out the recommended settings. I appreciate it! I have added the documentation related to reverse proxy by Apache(httpd), so I would like to consider this issue resolved.

docs/proxy/apache.md