Compare commits

...
20 Commits
Author SHA1 Message Date
ilike2burnthing fe5e1e8cea Update CHANGELOG.md 2026-09-12 02:30:09 +01:00
ilike2burnthing 93125d6ea6 Bump version 3.5.2 (#1778) 2026-09-12 02:23:16 +01:00
ilike2burnthing cdb8748734 Update build_package.py 2026-09-12 02:20:22 +01:00
ilike2burnthing c6eb8f5323 Bump version 3.5.1 (#1777) 2026-09-12 01:15:38 +01:00
ilike2burnthing cecf130c65 Bump Chromium 2026-09-12 01:07:30 +01:00
Br1an 3ae649ae20 Fix cookies being retrieved before waitInSeconds delay (#1692) 2026-08-25 07:10:08 +01:00
ilike2burnthing 833bfca77b Update tests_sites.py 2026-08-25 06:45:20 +01:00
ilike2burnthing e0fac5030d Bump requirements 2026-08-25 06:38:22 +01:00
ilike2burnthing e263039eaa Update README.md 2026-08-25 06:20:36 +01:00
ilike2burnthing b5f92e5e57 Update LICENSE 2026-08-25 06:18:51 +01:00
ilike2burnthing 24e7893da5 bump pyinstaller 2026-08-25 06:17:10 +01:00
ilike2burnthing a4370cc0a0 release.yml: bump actions 2026-08-25 06:09:18 +01:00
ilike2burnthing c4621e40a7 autotag.yml: bump actions 2026-08-25 06:05:23 +01:00
ilike2burnthing 63f48e17ee release-docker.yml: bump actions 2026-08-25 06:03:51 +01:00
Prodan Denis bc4d136fa7 fixed multiple buttons bug for tabs_till_verify (#1677) 2026-08-25 05:30:39 +01:00
Aki 716451bc30 Make the challenge wait timeout configurable (#1766) 2026-08-25 05:17:00 +01:00
ilike2burnthing 0f05ed8fc9 Update port examples & add warning. resolves #1746 2026-07-16 01:04:54 +01:00
ilike2burnthing 237faf1730 Update bug_report.yml 2026-07-02 19:28:15 +01:00
ilike2burnthing b21642624b Typo fix 2026-06-05 17:50:12 +01:00
ilike2burnthing 79154abcf4 Disable breaking Local Network Access Checks popup 2026-06-03 00:58:01 +01:00
15 changed files with 86 additions and 62 deletions
-2
View File
@@ -48,8 +48,6 @@ body:
- FlareSolverr User-Agent (see log traces or / endpoint):
- Are you using a VPN: [yes/no]
- Are you using a Proxy: [yes/no]
- Are you using Captcha Solver: [yes/no]
- If using captcha solver, which one:
- URL to test this issue:
render: markdown
validations:
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Auto tag
uses: Klemensas/action-autotag@stable
+7 -7
View File
@@ -18,14 +18,14 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Downcase repo
run: echo REPOSITORY=$(echo ${{ github.repository }} | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
${{ env.REPOSITORY }},enable=${{ github.event_name != 'pull_request' }}
@@ -37,27 +37,27 @@ jobs:
latest=auto
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
- name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GH_PAT }}
- name: Build and push
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
+6 -6
View File
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -24,7 +24,7 @@ jobs:
echo "EOF" >> $GITHUB_OUTPUT
- name: Create release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
with:
body: ${{ steps.github_changelog.outputs.changelog }}
env:
@@ -39,24 +39,24 @@ jobs:
os: [ubuntu-22.04, windows-latest]
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v6
uses: actions/setup-python@v7
with:
python-version: "3.11"
- name: Build artifacts
run: |
python -m pip install -r requirements.txt
python -m pip install pyinstaller==6.20.0
python -m pip install pyinstaller==6.22.2
cd src
python build_package.py
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
with:
files: ./dist/flaresolverr_*
env:
+8
View File
@@ -1,5 +1,13 @@
# Changelog
## v3.5.2 (2026/09/12)
* Update build_package.py
* Disable breaking Local Network Access Checks popup
* Make the challenge wait timeout configurable. Thanks @aki-ks
* Fixed multiple buttons bug for tabs_till_verify. Thanks @denis-svg
* Fix cookies being retrieved before waitInSeconds delay. Thanks @Br1an67
* Bump dependencies & Chromium
## v3.5.0 (2026/05/26)
* Add formatting to log file
* Resolve turnstile captcha. Thanks @denis-svg
+5 -5
View File
@@ -67,17 +67,17 @@ ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/usr/local/bin/python", "-u", "/app/flaresolverr.py"]
# Local build
# docker build -t ngosang/flaresolverr:3.5.0 .
# docker run -p 8191:8191 ngosang/flaresolverr:3.5.0
# docker build -t ngosang/flaresolverr:3.5.2 .
# docker run -p 8191:8191 ngosang/flaresolverr:3.5.2
# Multi-arch build
# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# docker buildx create --use
# docker buildx build -t ngosang/flaresolverr:3.5.0 --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 .
# docker buildx build -t ngosang/flaresolverr:3.5.2 --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64/v8 .
# add --push to publish in DockerHub
# Test multi-arch build
# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
# docker buildx create --use
# docker buildx build -t ngosang/flaresolverr:3.5.0 --platform linux/arm/v7 --load .
# docker run -p 8191:8191 --platform linux/arm/v7 ngosang/flaresolverr:3.5.0
# docker buildx build -t ngosang/flaresolverr:3.5.2 --platform linux/arm/v7 --load .
# docker run -p 8191:8191 --platform linux/arm/v7 ngosang/flaresolverr:3.5.2
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2025 Diego Heras (ngosang / ngosang@hotmail.es)
Copyright (c) 2026 Diego Heras (ngosang / ngosang@hotmail.es)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+24 -21
View File
@@ -35,7 +35,7 @@ already included within the image.
Docker images are available in:
- GitHub Registry => https://github.com/orgs/FlareSolverr/packages/container/package/flaresolverr
- GitHub Registry => https://github.com/FlareSolverr/FlareSolverr/pkgs/container/flaresolverr
- DockerHub => https://hub.docker.com/r/flaresolverr/flaresolverr
Supported architectures are:
@@ -58,7 +58,7 @@ If you prefer the `docker cli` execute the following command:
```bash
docker run -d \
--name=flaresolverr \
-p 8191:8191 \
-p 127.0.0.1:8191:8191 \
-e LOG_LEVEL=info \
--restart unless-stopped \
ghcr.io/flaresolverr/flaresolverr:latest
@@ -67,13 +67,15 @@ docker run -d \
**Command Prompt or Powershell**
```cmd
docker run -d --name=flaresolverr -p 8191:8191 -e LOG_LEVEL=info --restart unless-stopped ghcr.io/flaresolverr/flaresolverr:latest
docker run -d --name=flaresolverr -p 127.0.0.1:8191:8191 -e LOG_LEVEL=info --restart unless-stopped ghcr.io/flaresolverr/flaresolverr:latest
```
If your host OS is Debian, make sure `libseccomp2` version is 2.5.x. You can check the version with `sudo apt-cache policy libseccomp2`
and update the package with `sudo apt install libseccomp2=2.5.1-1~bpo10+1` or `sudo apt install libseccomp2=2.5.1-1+deb11u1`.
Remember to restart the Docker daemon and the container after the update.
DO NOT expose FlareSolverr to the internet, as it can be abused.
### Precompiled binaries
> **Warning**
@@ -277,24 +279,25 @@ This works like `request.get`, with the addition of the postData parameter. Note
## Environment variables
| Name | Default | Notes |
| ------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| LOG_LEVEL | info | Verbosity of the logging. Use `LOG_LEVEL=debug` for more information. |
| LOG_FILE | none | Path to capture log to file. Example: `/config/flaresolverr.log`. |
| LOG_HTML | false | Only for debugging. If `true` all HTML that passes through the proxy will be logged to the console in `debug` level. |
| PROXY_URL | none | URL for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `http://127.0.0.1:8080`. |
| PROXY_USERNAME | none | Username for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `testuser`. |
| PROXY_PASSWORD | none | Password for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `testpass`. |
| CAPTCHA_SOLVER | none | Captcha solving method. It is used when a captcha is encountered. See the Captcha Solvers section. |
| TZ | UTC | Timezone used in the logs and the web browser. Example: `TZ=Europe/London`. |
| LANG | none | Language used in the web browser. Example: `LANG=en_GB`. |
| HEADLESS | true | Only for debugging. To run the web browser in headless mode or visible. |
| DISABLE_MEDIA | false | To disable loading images, CSS, and other media in the web browser to save network bandwidth. |
| TEST_URL | https://www.google.com | FlareSolverr makes a request on start to make sure the web browser is working. You can change that URL if it is blocked in your country. |
| PORT | 8191 | Listening port. You don't need to change this if you are running on Docker. |
| HOST | 0.0.0.0 | Listening interface. You don't need to change this if you are running on Docker. |
| PROMETHEUS_ENABLED | false | Enable Prometheus exporter. See the Prometheus section below. |
| PROMETHEUS_PORT | 8192 | Listening port for Prometheus exporter. See the Prometheus section below. |
| Name | Default | Notes |
|----------------------| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| LOG_LEVEL | info | Verbosity of the logging. Use `LOG_LEVEL=debug` for more information. |
| LOG_FILE | none | Path to capture log to file. Example: `/config/flaresolverr.log`. |
| LOG_HTML | false | Only for debugging. If `true` all HTML that passes through the proxy will be logged to the console in `debug` level. |
| PROXY_URL | none | URL for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `http://127.0.0.1:8080`. |
| PROXY_USERNAME | none | Username for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `testuser`. |
| PROXY_PASSWORD | none | Password for proxy. Will be overwritten by `request` or `sessions` proxy, if used. Example: `testpass`. |
| CAPTCHA_SOLVER | none | Captcha solving method. It is used when a captcha is encountered. See the Captcha Solvers section. |
| TZ | UTC | Timezone used in the logs and the web browser. Example: `TZ=Europe/London`. |
| LANG | none | Language used in the web browser. Example: `LANG=en_GB`. |
| HEADLESS | true | Only for debugging. To run the web browser in headless mode or visible. |
| DISABLE_MEDIA | false | To disable loading images, CSS, and other media in the web browser to save network bandwidth. |
| BROWSER_WAIT_TIMEOUT | 1 | Seconds to wait for the web browser to reach an expected page state on each attempt. Increase it on slow hosts or slow websites. |
| TEST_URL | https://www.google.com | FlareSolverr makes a request on start to make sure the web browser is working. You can change that URL if it is blocked in your country. |
| PORT | 8191 | Listening port. You don't need to change this if you are running on Docker. |
| HOST | 0.0.0.0 | Listening interface. You don't need to change this if you are running on Docker. |
| PROMETHEUS_ENABLED | false | Enable Prometheus exporter. See the Prometheus section below. |
| PROMETHEUS_PORT | 8192 | Listening port for Prometheus exporter. See the Prometheus section below. |
Environment variables are set differently depending on the operating system. Some examples:
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "flaresolverr",
"version": "3.5.0",
"version": "3.5.2",
"description": "Proxy server to bypass Cloudflare protection",
"author": "Diego Heras (ngosang / ngosang@hotmail.es)",
"license": "MIT"
+7 -7
View File
@@ -1,14 +1,14 @@
bottle==0.13.4
waitress==3.0.2
selenium==4.39.0
selenium==4.47.0
func-timeout==4.3.5
prometheus-client==0.23.1
prometheus-client==0.26.0
# Required by undetected_chromedriver
requests==2.32.5
certifi==2025.11.12
websockets==15.0.1
packaging==25.0
requests==2.34.2
certifi==2026.7.22
websockets==17.0.1
packaging==26.3
# Only required for Linux and macOS
xvfbwrapper==0.2.16; platform_system != "Windows"
xvfbwrapper==0.2.29; platform_system != "Windows"
# Only required for Windows
pefile==2024.8.26; platform_system == "Windows"
+2 -2
View File
@@ -26,7 +26,7 @@ def clean_files():
def download_chromium():
# https://commondatastorage.googleapis.com/chromium-browser-snapshots/index.html?prefix=Linux_x64/
revision = "1522586" if os.name == 'nt' else '1522586'
revision = "1681099" if os.name == 'nt' else '1681097'
arch = 'Win_x64' if os.name == 'nt' else 'Linux_x64'
dl_file = 'chrome-win' if os.name == 'nt' else 'chrome-linux'
dl_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir, 'dist_chrome')
@@ -60,7 +60,7 @@ def download_chromium():
# Give executable permissions for *nix
# file * | grep executable | cut -d: -f1
print("Giving executable permissions...")
execs = ['chrome', 'chrome_crashpad_handler', 'chrome_sandbox', 'chrome-wrapper', 'xdg-mime', 'xdg-settings']
execs = ['chrome', 'chrome_crashpad_handler', 'chrome_sandbox', 'chrome-wrapper']
for exec_file in execs:
exec_path = os.path.join(chrome_path, exec_file)
os.chmod(exec_path, 0o755)
+1
View File
@@ -90,6 +90,7 @@ if __name__ == "__main__":
log_file = os.environ.get('LOG_FILE', None)
log_html = utils.get_config_log_html()
headless = utils.get_config_headless()
browser_wait_timeout = utils.get_config_browser_wait_timeout()
server_host = os.environ.get('HOST', '0.0.0.0')
server_port = int(os.environ.get('PORT', 8191))
+16 -8
View File
@@ -53,7 +53,6 @@ TURNSTILE_SELECTORS = [
"input[name='cf-turnstile-response']"
]
SHORT_TIMEOUT = 1
SESSIONS_STORAGE = SessionsStorage()
@@ -305,10 +304,16 @@ def _get_turnstile_token(driver: WebDriver, tabs: int):
# reset focus
driver.execute_script("""
let old = document.getElementById('__focus_helper');
if (old) old.remove();
let el = document.createElement('button');
el.style.position='fixed';
el.style.top='0';
el.style.left='0';
el.id = '__focus_helper';
el.style.position = 'fixed';
el.style.top = '0';
el.style.left = '0';
el.style.opacity = '0.01';
el.style.pointerEvents = 'none';
document.body.prepend(el);
el.focus();
""")
@@ -422,6 +427,7 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
logging.info("Challenge detected. Selector found: " + selector)
break
browser_wait_timeout = utils.get_config_browser_wait_timeout()
attempt = 0
if challenge_found:
while True:
@@ -430,12 +436,12 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
# wait until the title changes
for title in CHALLENGE_TITLES:
logging.debug("Waiting for title (attempt " + str(attempt) + "): " + title)
WebDriverWait(driver, SHORT_TIMEOUT).until_not(title_is(title))
WebDriverWait(driver, browser_wait_timeout).until_not(title_is(title))
# then wait until all the selectors disappear
for selector in CHALLENGE_SELECTORS:
logging.debug("Waiting for selector (attempt " + str(attempt) + "): " + selector)
WebDriverWait(driver, SHORT_TIMEOUT).until_not(
WebDriverWait(driver, browser_wait_timeout).until_not(
presence_of_element_located((By.CSS_SELECTOR, selector)))
# all elements not found
@@ -453,7 +459,7 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
logging.debug("Waiting for redirect")
# noinspection PyBroadException
try:
WebDriverWait(driver, SHORT_TIMEOUT).until(staleness_of(html_element))
WebDriverWait(driver, browser_wait_timeout).until(staleness_of(html_element))
except Exception:
logging.debug("Timeout waiting for redirect")
@@ -466,7 +472,6 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
challenge_res = ChallengeResolutionResultT({})
challenge_res.url = driver.current_url
challenge_res.status = 200 # todo: fix, selenium not provides this info
challenge_res.cookies = driver.get_cookies()
challenge_res.userAgent = utils.get_user_agent(driver)
challenge_res.turnstile_token = turnstile_token
@@ -482,6 +487,9 @@ def _evil_logic(req: V1RequestBase, driver: WebDriver, method: str) -> Challenge
if req.returnScreenshot:
challenge_res.screenshot = driver.get_screenshot_as_base64()
# Get cookies after all waits to capture cookies set during JavaScript execution
challenge_res.cookies = driver.get_cookies()
res.result = challenge_res
return res
+1 -1
View File
@@ -51,7 +51,7 @@ class TestFlareSolverr(unittest.TestCase):
'<title>Access denied</title>'),
('badasstorrents', 'https://badasstorrents.com/torrents/search/720p/date/desc',
'<title>Latest Torrents - BadassTorrents</title>'),
('bt4g', 'https://bt4g.org/search/2022', '<title>Download 2022 Torrents - BT4G</title>'),
('bt4g', 'https://bt4gprx.com/search?q=2022', '<title>Download 2022 Torrents - BT4G</title>'),
('cinemaz', 'https://cinemaz.to/api/v1/jackett/torrents?in=1&type=0&search=',
'<title>Access denied</title>'),
('epublibre', 'https://epublibre.unblockit.cat/catalogo/index/0/nuevo/todos/sin/todos/--/ajax',
+6
View File
@@ -32,6 +32,10 @@ def get_config_disable_media() -> bool:
return os.environ.get('DISABLE_MEDIA', 'false').lower() == 'true'
def get_config_browser_wait_timeout() -> int:
return int(os.environ.get('BROWSER_WAIT_TIMEOUT', 1))
def get_flaresolverr_version() -> str:
global FLARESOLVERR_VERSION
if FLARESOLVERR_VERSION is not None:
@@ -149,6 +153,8 @@ def get_webdriver(proxy: dict = None) -> WebDriver:
options.add_argument('--disable-gpu-sandbox')
options.add_argument('--ignore-certificate-errors')
options.add_argument('--ignore-ssl-errors')
# disable breaking popup
options.add_argument("--disable-features=LocalNetworkAccessChecks")
language = os.environ.get('LANG', None)
if language is not None: