haiwen / seafile-docker

A Docker image for Seafile server
Other
536 stars 181 forks source link

Fix broken deployment when served using HTTP behind a HTTPs proxy #326

Open undergroundwires opened 1 year ago

undergroundwires commented 1 year ago

Using Seafile on HTTP mode and having a HTTP proxy on front of it does not work.

Following PRs solve this issue: #325 and #324, this issue organizes these PRs.

Community has come up with own solutions such as ggogel/seafile-containerized to support container best-practices such as allowing this kind of scenario, however this is an important feature/bug fix that can be and should be supported in the official Docker image.

undergroundwires commented 1 year ago

If anyone is interested in getting this working before the official solution is there. Here's my workaround:

Click here to expand and see 1. Create `patch-seafile.Dockerfile`: ```Dockerfile FROM python:3.11 WORKDIR /var/app COPY patch.py . CMD [ "python", "./patch.py"] ``` 2. Create `patch.py`: ```python3 # This scripts is workaround to get HTTP working for Seafile docker, see https://github.com/haiwen/seafile-docker/issues/326. # It's here until following PRs are merged: # - "Allow specifying FILE_SERVER_ROOT", https://github.com/haiwen/seafile-docker/pull/324 # - "Add: enable .well-known/acme-challenge when https", https://github.com/haiwen/seafile-docker/pull/325 import datetime import os import logging import re from time import sleep SEAFILE_DATA_DIR='/seafile-data' def main(): setup_logger() logging.info('Running script.') fix_file_server_root() fix_nginx_configuration() logging.info('Completed running script.') def setup_logger(): logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[ logging.FileHandler("debug.log"), logging.StreamHandler() ] ) def fix_file_server_root(): # "Allow specifying FILE_SERVER_ROOT", https://github.com/haiwen/seafile-docker/pull/324 logging.info('Fixing FILE_SERVER_ROOT configuration') if is_https(): logging.info('Skipping because https is desired.') return seafile_conf_file=f'{SEAFILE_DATA_DIR}/seafile/conf/seahub_settings.py' content = read_config_file(seafile_conf_file) if 'FILE_SERVER_ROOT = "https' in content: logging.info('Skipping because FILE_SERVER_ROOT is already set to HTTPS.') return save_backup(seafile_conf_file, content) content = content.replace('FILE_SERVER_ROOT = "http', 'FILE_SERVER_ROOT = "https') save_new_content(seafile_conf_file, content) cache_file=f'{SEAFILE_DATA_DIR}/seafile/conf/seahub_settings.pyc' # https://manual.seafile.com/config/seahub_settings_py/#note if os.path.isfile(cache_file): logging.error(f'Deleting cache file {cache_file} so changes take effect.') os.remove(cache_file) def fix_nginx_configuration(): # Fixes "Add: enable .well-known/acme-challenge when https", https://github.com/haiwen/seafile-docker/pull/325 logging.info('Fixing nginx configuration') if is_https(): logging.info('Skipping because https is desired.') return nginx_conf_file = f"{SEAFILE_DATA_DIR}/nginx/conf/seafile.nginx.conf" logging.info(f'Fixing nginx configuration in ${nginx_conf_file}') content = read_config_file(nginx_conf_file) if 'For letsencrypt' not in content: logging.info('Skipping because letsencrypt is not configured') return save_backup(nginx_conf_file, content) pattern = re.compile(r"^\s*# For letsencrypt[\S\s]*\;\s*\}", re.MULTILINE) content = pattern.sub('', content) save_new_content(nginx_conf_file, content) def save_new_content(file_path: str, content: str): if not os.path.isfile(file_path): logging.error(f'File {file_path} does not exist.') logging.info(f'Saving new configuration:\n\n---\n{content}\n---') with open(file_path, 'w') as file: file.write(content) logging.info(f'Saved new configuration to {file_path}.') def save_backup(original_file_path: str, original_content: str): timestamp = (datetime.datetime.utcnow().strftime("%m%d%y-%H%M%S")) backup_file_name=f"{original_file_path}.backup.{timestamp}" with open(backup_file_name, 'w') as file: file.write(original_content) logging.info(f'Saved original file as backup file: {backup_file_name}') def read_config_file(file_path: str) -> str: if not os.path.isfile(file_path): wait_in_seconds=1 logging.info(f'File {file_path} does not exist, might not be created yet, waiting for {wait_in_seconds} seconds.') sleep(wait_in_seconds) return read_config_file(file_path) with open(file_path, 'r') as file: content = file.read() logging.info(f'Current configuration ({file_path}):\n\n---\n{content}\n---') return content def is_https(): return get_conf('SEAFILE_SERVER_LETSENCRYPT', 'false').lower() == 'true' def get_conf(key: str, default=None): key = key.upper() return os.environ.get(key, default) main() ``` 3. Run the container along with official seafile image, e.g. if you're using docker-compose in `docker-compose.yml`: ```yaml seafile: image: seafileltd/seafile-mc:latest volumes: - {YOUR-LOCAL-SEAFILE-DATA-DIR}:/shared SEAFILE_SERVER_LETSENCRYPT: false # ... # Add this: patch-seafile: build: context: ./ dockerfile: patch-seafile.Dockerfile environment: SEAFILE_SERVER_LETSENCRYPT: false volumes: - {YOUR-LOCAL-SEAFILE-DATA-DIR}:/seafile-data ```
kirisakow commented 1 week ago

nice workaround @undergroundwires!

however, I'm a little surprised you didn't include a depends: directive to the patch service to make sure it doesn't fire before the seafile-* services

sdsys-ch commented 1 week ago

nice workaround @undergroundwires!

however, I'm a little surprised you didn't include a depends: directive to the patch service to make sure it doesn't fire before the seafile-* services

Since depends on: is only ensuring service order, this might not do what you expect. You could add a health check to the seafile container and add that as a condition to the patch service. Since seafile can take a very long time to be ready (chmodding the files in case of "run as user", e.g.), that's the safer alternative, I believe, but correct me if I'm wrong.