akeeba / panopticon

Self-hosted site monitoring and management
GNU Affero General Public License v3.0
42 stars 20 forks source link

Mixed content in Panopticon behind an HTTPS connection. #696

Closed alebak closed 3 months ago

alebak commented 5 months ago

Due diligence

Describe the issue

Hello,

I tried to deploy Akeeba Panopticon on CapRover using the main repository of the project but without success. I made a fork of the project, used the proposed Dockerfile and added captain-definition to deploy “without any problem”, and still no success, one of the problems is that when doing the build from CapRover it hung on the compilation of the mysqli extension. Anyway, no problem, I guess that's not the point, I guess the manifest to make the Docker image works fine in a development environment where there is no SSL connection behind. I managed to make my own Panopticon image version 1.1.3 from my computer and upload it to the Docker Hub adding some things to the Dockerfile and htaccess.txt file and see if I could get it working in CapRover, on localhost (my computer) it worked perfect but when deploying it to CapRover behind a domain with SSL certificate I started getting mixed content messages in the browser development console:

'Mixed Content: The page at 'https://akeeba-panopticon.xxxxxx.com/' was loaded over HTTPS, but requested an insecure stylesheet 'http://akeeba-panopticon.xxxxxx.com/media/css/theme.min.css?b099190...=1'. This request has been blocked; the content must be served over HTTPS.'

So I modified the Dockerfile by adding this:

# Install the MySQLi PHP extension
RUN docker-php-ext-install -j12 mysqli ftp

# Enable Apache modules
RUN a2enmod rewrite autoindex dir headers brotli deflate mime

And to the htaccess.txt (.httaccess) I added this to force everything with http to force it to https:

<IfModule mod_rewrite.c>
    RewriteEngine On

    # Redirect to HTTPS if not already using HTTPS
    RewriteCond %{HTTPS} !=on
    RewriteCond %{HTTP:X-Forwarded-Proto} !=https
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>

# Force HTTPS for all resources
<IfModule mod_headers.c>
    Header always set Content-Security-Policy "upgrade-insecure-requests;"
</IfModule>

It worked. The application styles were fixed but the forms were completely overridden. I don't know if this is a bug or a possible configuration error on my part, or, perhaps, the Dockerfile needs to be enhanced to support HTTPS connections. What could be going on, has anyone had this happen yet?

Screenshots

If I remove the .htaccess file, Akeeba Panopticon looks like this:

image

Devtools: image

If I copy the htaccess.txt file back to .htaccess, the one with the code that forces everything from http to https, it looks like this, but the forms don't work and it doesn't do any action:

image

Devtools: image

Panopticon version

1.1.3

PHP version

8.2-apache

Database type

MariaDB

Database version

10.4.34

Browser

Edge

Browser version

125.0.2535.79

Additional information

No response

nikosdion commented 5 months ago

If I understand this correctly, you have a TLS terminator that's separate from your web server (Apache). This is a bit of a problem because Apache does not see the HTTPS protocol when serving the request, therefore does not set the HTTPS environment variable, and it all becomes a bit of a clusterfsck on the PHP side.

The solution in this case is to edit Panopticon's config.php file, setting the $live_site with an https:// protocol prefix.

If you are using a .env file (which is probably easier for a Docker deployment) the environment variable you are looking for is PANOPTICON_LIVE_SITE.

Panopticon on Docker is still very much in a rough state. I still don't have a very good architecture for isolating its configuration, or passing configuration via environment variables (despite the .env file support). Suggestions are welcome.

alebak commented 5 months ago

Thank you, @nikosdion for the answer, I'll take note and I'll do the corresponding tests and I'll let you know. I think Akeeba Panopticon has a lot of future in containers as the requirement to run cron tasks every 60 seconds is better in an isolated environment (containers, pods, VPS and the like). Hosting providers lower the cron to 15 minutes minimum.

nikosdion commented 5 months ago

You're welcome! I have opened https://github.com/akeeba/panopticon/issues/697 to track Docker-related improvements. If you think of something I have forgotten, please leave a comment. Thank you!

alebak commented 3 months ago

Hello @nikosdion,

I tried again to deploy Akeeba Panopticon using the 'ghcr.io/akeeba/panopticon:latest' image but apparently it is not taking the PANOPTICON_LIVE_SITE environment variable, that is, every time the service (container) is restarted the $live_site variable returns empty, I have to set the URL manually after each restart.

image

image

nikosdion commented 3 months ago

You can either use environment variables or a config.php file, not both. Since you have a config.php file the environment variables are ignored.

Please remember that I completely redid the Docker implementation, as per the release notes. You have to export your data, spin up a new container, then re-import your data.

In the new version the configuration of the Dockerized Panopticon is entirely through environment variables. There is no config.php, or a setup step. The installation is initialised on first start of the container using the environment variables.

Also note that from now on the data will not be stored in the container itself, but a separate volume. Updates to Panopticon will not be shown in the interface when running under Docker, and you won't be able to overwrite Panopticon. You will instead have to update the image and restart the container, as should've been the case all along.

alebak commented 3 months ago

Hi @nikosdion,

If I have some environment variables, in my case, the same ones that are in the .env.docker.dist file then why does the image rerun the 'Setup' and generate a config.php? I also have the corresponding volumes configured.

image

This is a first screenshot from days ago:

image

And this is a second screenshot after restarting the service (container) today:

image

In a way, if the Docker image generates a config.php on the fly from the environment variables, it works, the only thing it does not take is the PANOPTICON_LIVE_SITE variable.

This is log complete:

2024-07-27T18:35:57.285482378Z   __
2024-07-27T18:35:57.285512598Z  /         /
2024-07-27T18:35:57.285515488Z (___  ___ (___       ___
2024-07-27T18:35:57.285517628Z     )|___)|    |   )|   )
2024-07-27T18:35:57.285519858Z  __/ |__  |__  |__/ |__/
2024-07-27T18:35:57.285521994Z                     |
2024-07-27T18:36:14.987534564Z Akeeba Panopticon CLI 1.2.1
2024-07-27T18:36:14.987836632Z Copyright (c) 2023-2024  Akeeba Ltd
2024-07-27T18:36:14.987939007Z 
2024-07-27T18:36:14.988029098Z Distributed under the terms of the GNU General Public License as published
2024-07-27T18:36:14.988193303Z by the Free Software Foundation, either version 3 of the License, or (at your
2024-07-27T18:36:14.988283340Z option) any later version. See LICENSE.txt.
2024-07-27T18:36:14.988375980Z 
2024-07-27T18:36:14.995897491Z Create a configuration file
2024-07-27T18:36:14.996082062Z ===========================
2024-07-27T18:36:14.996190836Z 
2024-07-27T18:36:15.004585600Z  [INFO] Verified database connection.                                           
2024-07-27T18:36:15.004803791Z 
2024-07-27T18:36:15.009330125Z  [OK] Created configuration file.                                               
2024-07-27T18:36:15.009464600Z                                                                                 
2024-07-27T18:36:15.009544500Z       File: /var/www/html/config/config.php                                     
2024-07-27T18:36:15.009597037Z 
2024-07-27T18:36:15.146811269Z Akeeba Panopticon CLI 1.2.1
2024-07-27T18:36:15.146994260Z Copyright (c) 2023-2024  Akeeba Ltd
2024-07-27T18:36:15.147035166Z 
2024-07-27T18:36:15.147105141Z Distributed under the terms of the GNU General Public License as published
2024-07-27T18:36:15.147217786Z by the Free Software Foundation, either version 3 of the License, or (at your
2024-07-27T18:36:15.147262043Z option) any later version. See LICENSE.txt.
2024-07-27T18:36:15.147348513Z 
2024-07-27T18:36:15.151859880Z Install or update the database tables
2024-07-27T18:36:15.152093921Z =====================================
2024-07-27T18:36:15.152185455Z 
2024-07-27T18:36:15.156675658Z  [INFO] Installing or updating the database tables                              
2024-07-27T18:36:15.156849303Z 
2024-07-27T18:36:15.540163475Z Akeeba Panopticon CLI 1.2.1
2024-07-27T18:36:15.540421520Z Copyright (c) 2023-2024  Akeeba Ltd
2024-07-27T18:36:15.540502809Z 
2024-07-27T18:36:15.540596211Z Distributed under the terms of the GNU General Public License as published
2024-07-27T18:36:15.540751638Z by the Free Software Foundation, either version 3 of the License, or (at your
2024-07-27T18:36:15.540879126Z option) any later version. See LICENSE.txt.
2024-07-27T18:36:15.541008833Z 
2024-07-27T18:36:15.545982452Z Creates or overwrites a Super User
2024-07-27T18:36:15.546127183Z ==================================
2024-07-27T18:36:15.546211700Z 
2024-07-27T18:36:15.556796492Z  [WARNING] Modifying existing user admin.                                       
2024-07-27T18:36:15.556967273Z 
2024-07-27T18:36:15.780203255Z  [ERROR] Could not save user admin.                                             
2024-07-27T18:36:15.780435435Z 
2024-07-27T18:36:15.920780581Z Akeeba Panopticon CLI 1.2.1
2024-07-27T18:36:15.921009847Z Copyright (c) 2023-2024  Akeeba Ltd
2024-07-27T18:36:15.921094645Z 
2024-07-27T18:36:15.921189447Z Distributed under the terms of the GNU General Public License as published
2024-07-27T18:36:15.921398023Z by the Free Software Foundation, either version 3 of the License, or (at your
2024-07-27T18:36:15.921520676Z option) any later version. See LICENSE.txt.
2024-07-27T18:36:15.921635868Z 
2024-07-27T18:36:15.927294244Z Set a configuration value
2024-07-27T18:36:15.927488794Z =========================
2024-07-27T18:36:15.927603688Z 
2024-07-27T18:36:15.937734435Z  [OK] Set config key ‘max_execution’ to ‘180’.                                  
2024-07-27T18:36:15.937981407Z 
2024-07-27T18:36:16.066211129Z Akeeba Panopticon CLI 1.2.1
2024-07-27T18:36:16.066470649Z Copyright (c) 2023-2024  Akeeba Ltd
2024-07-27T18:36:16.066591023Z 
2024-07-27T18:36:16.066802844Z Distributed under the terms of the GNU General Public License as published
2024-07-27T18:36:16.066987152Z by the Free Software Foundation, either version 3 of the License, or (at your
2024-07-27T18:36:16.067105269Z option) any later version. See LICENSE.txt.
2024-07-27T18:36:16.067224862Z 
2024-07-27T18:36:16.072658211Z Set a configuration value
2024-07-27T18:36:16.072883275Z =========================
2024-07-27T18:36:16.073017777Z 
2024-07-27T18:36:16.081439422Z  [OK] Set config key ‘finished_setup’ to ‘true’.                                
2024-07-27T18:36:16.081654323Z 
2024-07-27T18:36:16.102690905Z no crontab for panopticon
2024-07-27T18:36:16.155997755Z Starting periodic command scheduler: cron.
2024-07-27T18:36:16.280273347Z AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.0.1.62. Set the 'ServerName' directive globally to suppress this message
2024-07-27T18:36:16.318122146Z AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.0.1.62. Set the 'ServerName' directive globally to suppress this message
2024-07-27T18:36:16.369062385Z [Sat Jul 27 18:36:16.368792 2024] [mpm_prefork:notice] [pid 1:tid 1] AH00163: Apache/2.4.61 (Debian) PHP/8.2.21 configured -- resuming normal operations
2024-07-27T18:36:16.370904163Z [Sat Jul 27 18:36:16.370725 2024] [core:notice] [pid 1:tid 1] AH00094: Command line: 'apache2 -D FOREGROUND'

These are the environment variables inside the container using the command printenv:

image

nikosdion commented 3 months ago

As per line 6 of the .env.docker.dist file:

To use this file, copy it to .env.docker and edit it.

alebak commented 3 months ago

I still don't understand, is it dispensable for Panopticon to have the .env file inside the root directory of the project? Supposedly for platforms like CapRover, Portainer and other Swarm or Kubernetes based solutions, the secrets that do the same as the .env file.

This is equivalent to an .env file, otherwise, I would have to persist that file.

image

nikosdion commented 3 months ago

OK, now I get it. You want to completely replace any kind of configuration (either config.php or .env) with environment variables passed to the container context by the container runtime. This is not currently possible.

There are a few complications.

The initial run of the container needs to be detected by the container entry point file (assets/docker-entrypoint.sh) so your database tables can be set up and populated – including creating your admin user. Right now, it checks if the config.php file exists in the container. We'd have to create a different CLI command just for this purpose.

The third party library we use for environment variables parsing only supports reading from files. We'd have to modify our Configuration repository to also check if the environment itself defines configuration values, merge them into the repository, and make the repository read-only.

The problem here is that if there is no configuration file (neither config.php, nor .env) how do we know the application is configured? Checking if there are any PANOPTICON_* environment variables is not enough; after all, you need to at the very least provide the database connection information before you even set up the application. And since we cannot write back to the environment configuration be it a .env.docker or the container platform configuration we cannot use a configuration variable to do that.

This has to be a pretty damn accurate way to do it because if it fails your installation is either never initialised (false positive) or always has its data overwritten on restart (false positive).

Moreover, we have to POSITIVELY know if you are using environment variables for configuration because in this case we MUST hide the configuration GUI as there's no way to persist configuration changes – since the configuration is defined outside the application container!

Forcing people to always use environment variables for containerized Panopticon is not a great idea either. This is mass distributed software, and most people using it expect to have a configuration GUI. Using environment variables to configure it caters for a niche, not for the mainstream.

So, the only way I can see this happening is this:

We would have to add another environment variable in .env.docker named something like PANOPTICON_USING_ENV which would indicate that you want to use environment variables instead of a config.php file.

When PANOPTICON_USING_ENV is set to 1 the entry point file would have to do the following on each startup:

Moreover, when PANOPTICON_USING_ENV is set to 1, the configuration repository would have to have an extra step where it reads the configuration from environment variables, without even checking for .env or config.php files. The downside is that regardless of whether you've configured anything or not the application would not show you the configuration GUI since the configuration repository is most definitely in a read-only state.

I can definitely do that, and hopefully not break anything in your use case, as long as you transcribe any configuration changes you had made in config.php into environment variables. It would definitely not break anything for people already using containerized Panopticon using the current scheme of a config.php file inside the container itself.

Do you think that would work for your use case?

alebak commented 3 months ago

Hi @nikosdion,

Thank you for taking this issue into account and taking care of it. I think that the solution you propose can work and I am willing to do the corresponding tests in a pre-production environment and give you feedback.

In order not to mess up this thread too much with something that may not quite correspond, I was recently implementing Mautic and they have 2 important things: 1. they have a separate project called docker-mautic to handle everything related to Docker and containers, and, 2. they use an environment variable called DOCKER_MAUTIC_ROLE that they use to deploy the image in a certain mode either web, cron or worker.

Just a thought. 😃

nikosdion commented 3 months ago

What you asked in this issue is now available on the main branch, and I have updated the documentation to explain what you need to do, including how to build your own images. You need to use what I describe as the Environment configuration mode.

Now, about the other things.

Some context is in order. This is mass distributed software. The vast majority of its users want to set it up using the same level of minimal / basic technical know-how necessary to set up a FOSS PHP CMS. As a result, I have to make certain choices as I have already explained in the Philosophy page.

The best I could do is give you software which can run either as a monolith (like these aforementioned CMS), or more modular. The way it's implemented, it can indeed do both. That was a major design goal from the get-go.

You don't need container roles. Each container (or installation on a server) can perform any role you want it to perform. If you disable CRON jobs but expose the web server you have a frontend-only container. If you have CRON jobs but disable the web server (or just don't expose its ports) you have a worker-only container. Just make sure to share the same volumes and have identical configurations in both types of containers.

If you want to optimise the memory and performance of each container you can override the image's entrypoint in a custom image build. A custom image build which is trivial to do because everything is in a single repository.

If you have a use case which you can't figure out how to implement, you can ask in the Discussions. I only decline changes if they against the philosophy or architecture of the software i.e. if you're asking for a different product with different goals, or if what you are asking would break the use cases of many other users of the software. Give me your use case, and I'll see if there's a sensible way to implement it, like I did in this issue.