Fix broken deployment when served using HTTP behind a HTTPs proxy
undergroundwires opened this issue · 3 comments
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.
If anyone is interested in getting this working before the official solution is there. Here's my workaround:
Click here to expand and see
- Create
patch-seafile.Dockerfile
:
FROM python:3.11
WORKDIR /var/app
COPY patch.py .
CMD [ "python", "./patch.py"]
- Create
patch.py
:
# 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()
- Run the container along with official seafile image, e.g. if you're using docker-compose in
docker-compose.yml
:
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
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
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.