Compare commits

...
18 Commits
Author SHA1 Message Date
github-actions[bot] dce8beaa1b Update Tailscale to v1.98.10 2026-07-29 06:32:18 +00:00
Weston Blieden b70d664f91 fix: use Mo3he vendor name in ROOT manifests to pass schema validation 2026-07-29 08:15:03 +02:00
Weston Blieden 9ea88ccd0d docs: extend verified OS range to 13 (intro + roadmap) 2026-07-24 13:06:32 +02:00
Weston Blieden f79f631d95 docs: note verified on AXIS OS 13 (13.0.0, aarch64) 2026-07-24 13:03:13 +02:00
Weston Blieden 835ccff82f docs: add Advertise Routes (Subnet Router) to README config table 2026-07-21 19:44:51 +02:00
Weston Blieden 92262bd16c Update vendor to moshe@mohome.net and vendorId for ACAP signing
Packages are now signed with the Axis ACAP signing service. Document the
signing change and the upgrade steps (back up config and uninstall the old
version to avoid the "Vendor ID in manifest does not match" install error)
in the README and changelog.
2026-07-21 19:35:05 +02:00
github-actions[bot] 948c201ea3 Update Tailscale to v1.98.9 2026-07-21 03:39:55 +00:00
Weston Blieden 3730609abe docs: standardize README (badges, disclaimer, compatibility, sections, links, AXIS OS naming) 2026-07-17 10:11:52 +02:00
Weston BliedenandGitHub b06dbc0059 Update sponsorship links and badge styles in README 2026-07-16 13:32:38 +02:00
Weston Blieden 7d32827567 Fix invalid MD060 config value (disable rule) 2026-07-08 10:04:45 +02:00
Weston Blieden 970055051d Point super-linter at repo .markdownlint.yaml (honor shared config) 2026-07-08 09:47:50 +02:00
Weston Blieden 216ae1ebf9 Add super-linter (markdown/yaml/json/dockerfile/shell); fix lint findings 2026-07-08 09:40:14 +02:00
Weston Blieden e2daee6519 Add CHANGELOG.md generated from release history
Keep a Changelog-style summary of every released version with its date and a
link to the full GitHub release notes.
2026-07-07 20:56:09 +02:00
Weston Blieden 2a8dccfc05 Add CONTRIBUTING.md and shared lint configs
Add a contributor guide, and copy the shared .clang-format and .markdownlint.yaml
so linting is consistent across the ACAP repos.
2026-07-07 20:44:46 +02:00
Weston Blieden 02dda93272 Fix markdownlint MD034/MD040 in notices and security docs
Wrap bare URLs and the contact email in angle brackets, and add a language to
the license-text code fences, so the shared markdown lint passes.
2026-07-07 20:35:24 +02:00
Weston Blieden 0331f8d8c5 Keep LICENSE as pure BSD 3-Clause text for license detection
Move the third-party pointer out of LICENSE (it lives in THIRD_PARTY_NOTICES.md)
so GitHub's license detection recognizes the BSD 3-Clause license.
2026-07-07 20:02:57 +02:00
Weston Blieden f3d649aa92 Update security contact email to moshe@mohome.net 2026-07-07 19:53:15 +02:00
Weston Blieden bddcdf7de8 Standardize licensing and repo hygiene
- Relicense wrapper code to BSD 3-Clause (SPDX-detectable); the previous
  LICENSE combined the wrapper license with third-party notices.
- Move upstream attributions into THIRD_PARTY_NOTICES.md (nothing dropped).
- Add SECURITY.md with a private disclosure process.
2026-07-07 19:47:25 +02:00
23 changed files with 677 additions and 303 deletions
+102
View File
@@ -0,0 +1,102 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 8
UseTab: Never
...
+11
View File
@@ -0,0 +1,11 @@
DEFAULT_BRANCH=origin/main
LINTER_RULES_PATH=/
VALIDATE_ALL_CODEBASE=true
IGNORE_GITIGNORED_FILES=true
YAML_CONFIG_FILE=.yamllint.yaml
MARKDOWN_CONFIG_FILE=.markdownlint.yaml
VALIDATE_DOCKERFILE_HADOLINT=true
VALIDATE_JSON=true
VALIDATE_MARKDOWN=true
VALIDATE_SHELL_SHFMT=true
VALIDATE_YAML=true
+22
View File
@@ -0,0 +1,22 @@
---
name: Lint
on: push
jobs:
Build:
name: Lint code base
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup Environment
run: cat .github/super-linter.env >> "$GITHUB_ENV"
- name: Lint code base
uses: super-linter/super-linter/slim@v8
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+8
View File
@@ -0,0 +1,8 @@
---
# Enforce error-level Dockerfile correctness. Warnings/info are advisory: the
# ACAP cross-compile Dockerfiles use accepted patterns (cd in RUN, ARG-templated
# FROM tags hadolint cannot resolve, optional pipefail).
failure-threshold: error
ignored:
# Pin versions in 'apt-get install' - the SDK base image is already pinned.
- DL3008
+11
View File
@@ -0,0 +1,11 @@
---
# Line length (disabled: long lines in tables, URLs and prose are acceptable)
MD013: false
# Allow inline HTML (e.g. <img> logos and badges in READMEs)
MD033: false
# Allow blank lines inside blockquotes
MD028: false
# First line in a file should be a top-level heading
MD041: false
# Table column style (disabled; the previous "padded" value was invalid)
MD060: false
+2
View File
@@ -0,0 +1,2 @@
rules:
line-length: disable
+153
View File
@@ -0,0 +1,153 @@
# Changelog
All notable changes to this project are documented here. Each version
links to its full release notes on GitHub.
The format is based on [Keep a Changelog](https://keepachangelog.com/).
## [1.98.9-Signed] - 2026-07-21 - Tailscale VPN 1.98.9 (Signed)
- Packages are now signed with the Axis ACAP signing service and install
normally on AXIS OS 12.10 and later.
- Vendor updated to `moshe@mohome.net` with the registered vendor ID.
- `root` and `acap3` variants remain unsigned (manifest schema v1.x).
- Upgrading from an earlier unsigned version can fail with "Couldn't
install: app" (device log: "Vendor ID in manifest does not match the
vendor ID of the previous version"). Back up your config, uninstall the
old version, then install this one.
## [1.98.8-2] - 2026-07-03 - Tailscale VPN 1.98.8-2
## [1.98.8-subnet-routing] - 2026-07-01 - Tailscale VPN 1.98.8 - Subnet Routing
## [1.98.8] - 2026-06-30 - Tailscale VPN 1.98.8
## [1.98.4-statusfix] - 2026-06-16
## [1.98.4-dns-routes] - 2026-06-10 - Tailscale VPN v1.98.4 - Accept DNS & Routes toggles
## [1.98.4] - 2026-06-02 - Tailscale VPN 1.98.4
## [1.98.3] - 2026-05-22 - Tailscale VPN 1.98.3
## [1.98.2] - 2026-05-19 - Tailscale VPN 1.98.2
## [1.96.4-dns-routes] - 2026-05-12 - Tailscale VPN v1.96.4 - Accept DNS & Routes toggles
## [1.96.4-r3] - 2026-04-17 - Tailscale VPN v1.96.4-r3
## [1.96.4-r2] - 2026-04-17
## [1.96.4-proxy] - 2026-04-14 - Tailscale VPN 1.96.4 - Proxy Support
## [1.96.4] - 2026-03-28 - Tailscale VPN 1.96.4
## [1.96.2] - 2026-03-19 - Tailscale VPN 1.96.2
## [1.94.2] - 2026-02-26 - Tailscale VPN 1.94.2
## [1.94.1] - 2026-01-28 - Tailscale VPN 1.94.1
## [1.92.5] - 2026-01-07 - Tailscale VPN 1.92.5
## [1.92.3] - 2025-12-17 - Tailscale VPN 1.92.3
## [1.92.1] - 2025-12-15 - Tailscale VPN 1.92.1
## [1.90.9] - 2025-11-26 - Tailscale VPN 1.90.9
## [1.90.8] - 2025-11-20 - Tailscale VPN 1.90.8
## [1.90.6] - 2025-11-03 - Tailscale VPN 1.90.6
## [1.90.3] - 2025-10-28 - Tailscale VPN 1.90.3
## [1.90.2] - 2025-10-27 - Tailscale VPN 1.90.2
## [1.90.1] - 2025-10-23 - Tailscale VPN 1.90.1
## [1.88.3] - 2025-09-29 - Tailscale VPN 1.88.3
## [1.88.1] - 2025-09-15 - Tailscale VPN 1.88.1
## [1.86.2] - 2025-08-27 - Tailscale VPN 1.86.2
## [1.84.0] - 2025-05-26
## [1.82.0] - 2025-04-11
## [1.80.3] - 2025-03-24
## [1.78.1] - 2025-01-13
## [1.76.1] - 2024-10-24
## [1.72.1] - 2024-08-26
## [1.68.1] - 2024-06-27
## [1.62.0] - 2024-03-23
## [1.60.0] - 2024-02-21
## [1.56.1] - 2024-01-17
## [1.54.0] - 2023-11-28
## [1.52.0] - 2023-11-01
## [1.50.1] - 2023-10-16
## [148.2] - 2023-09-13 - Version 1.48.2
## [1.44.0] - 2023-07-04
## [138.4] - 2023-04-17 - V1.38.4
## [1.34.0] - 2022-12-19
[1.98.8-2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.8-2
[1.98.8-subnet-routing]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.8-subnet-routing
[1.98.8]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.8
[1.98.4-statusfix]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.4-statusfix
[1.98.4-dns-routes]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.4-dns-routes
[1.98.4]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.4
[1.98.3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.3
[1.98.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.98.2
[1.96.4-dns-routes]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.4-dns-routes
[1.96.4-r3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.4-r3
[1.96.4-r2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.4-r2
[1.96.4-proxy]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.4-proxy
[1.96.4]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.4
[1.96.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.96.2
[1.94.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.94.2
[1.94.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.94.1
[1.92.5]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.92.5
[1.92.3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.92.3
[1.92.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.92.1
[1.90.9]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.9
[1.90.8]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.8
[1.90.6]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.6
[1.90.3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.3
[1.90.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.2
[1.90.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.90.1
[1.88.3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.88.3
[1.88.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.88.1
[1.86.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.86.2
[1.84.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.84.0
[1.82.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.82.0
[1.80.3]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.80.3
[1.78.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.78.1
[1.76.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.76.1
[1.72.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.72.1
[1.68.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.68.1
[1.62.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.62.0
[1.60.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.60.0
[1.56.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.56.1
[1.54.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.54.0
[1.52.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.52.0
[1.50.1]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.50.1
[148.2]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.148.2
[1.44.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.1.44.0
[138.4]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v.138.4
[1.34.0]: https://github.com/Mo3he/Axis_Cam_Tailscale/releases/tag/v1.34.0
+14 -14
View File
@@ -13,13 +13,13 @@ All types of contributions are encouraged and valued. See the [Table of contents
- [I have a question](#i-have-a-question)
- [I want to contribute](#i-want-to-contribute)
- [Reporting bugs](#reporting-bugs)
- [Before submitting a bug report](#before-submitting-a-bug-report)
- [How do I submit a good bug report?](#how-do-i-submit-a-good-bug-report)
- [Suggesting enhancements](#suggesting-enhancements)
- [Before Submitting an Enhancement](#before-submitting-an-enhancement)
- [How do I submit a good enhancement suggestion?](#how-do-i-submit-a-good-enhancement-suggestion)
- [Your first code contribution](#your-first-code-contribution)
- [Reporting bugs](#reporting-bugs)
- [Before submitting a bug report](#before-submitting-a-bug-report)
- [How do I submit a good bug report?](#how-do-i-submit-a-good-bug-report)
- [Suggesting enhancements](#suggesting-enhancements)
- [Before Submitting an Enhancement](#before-submitting-an-enhancement)
- [How do I submit a good enhancement suggestion?](#how-do-i-submit-a-good-enhancement-suggestion)
- [Your first code contribution](#your-first-code-contribution)
## I have a question
@@ -46,13 +46,13 @@ A good bug report shouldn't leave others needing to chase you up for more inform
- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker][issues_bugs].
- Also make sure to search the internet to see if users outside of the GitHub community have discussed the issue.
- Collect information about the bug:
- Axis device model
- Axis device firmware version
- Stack trace
- OS and version (Windows, Linux, macOS, x86, ARM)
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant
- Possibly your input and the output
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
- Axis device model
- Axis device firmware version
- Stack trace
- OS and version (Windows, Linux, macOS, x86, ARM)
- Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant
- Possibly your input and the output
- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
#### How do I submit a good bug report?
+2 -4
View File
@@ -1,8 +1,6 @@
BSD 3-Clause License
Copyright (c) 2020 Tailscale & AUTHORS.
Copyright (c) 2022 Weston Blieden (ACAP packaging and wrapper code)
All rights reserved.
Copyright (c) 2022, Weston Blieden
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -27,4 +25,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+175 -173
View File
@@ -1,73 +1,114 @@
# Tailscale ACAP for Axis Cameras
[![Release](https://img.shields.io/github/v/release/Mo3he/Axis_Cam_Tailscale?style=flat)](https://github.com/Mo3he/Axis_Cam_Tailscale/releases)
[![License](https://img.shields.io/github/license/Mo3he/Axis_Cam_Tailscale?style=flat)](LICENSE)
[![Downloads](https://img.shields.io/github/downloads/Mo3he/Axis_Cam_Tailscale/total?label=Downloads&color=blue&style=flat)](https://github.com/Mo3he/Axis_Cam_Tailscale/releases)
[![Build](https://github.com/Mo3he/Axis_Cam_Tailscale/actions/workflows/build.yml/badge.svg)](https://github.com/Mo3he/Axis_Cam_Tailscale/actions/workflows/build.yml)
[![Super-Linter](https://github.com/Mo3he/Axis_Cam_Tailscale/actions/workflows/super-linter.yml/badge.svg)](https://github.com/Mo3he/Axis_Cam_Tailscale/actions/workflows/super-linter.yml)
[![Sponsor](https://img.shields.io/badge/Sponsor%20My%20Work-EA4AAA?style=flat&logo=github&logoColor=white)](https://github.com/sponsors/Mo3he)
[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-FFDD00?style=flat&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/mo3he)
This repository provides an **ACAP package** that installs the
[Tailscale VPN client](https://tailscale.com/) on Axis cameras, for secure remote
access without extra hardware or complex network configuration.
**[Visit the Homepage](https://mo3he.github.io/Axis_Cam_Tailscale/)**
This repository provides an **ACAP package** that installs the [Tailscale VPN client](https://tailscale.com/) on Axis cameras.
> **Disclaimer:** Independent, community-developed ACAP package. Not an official
> Axis product and not affiliated with, endorsed by, or supported by Axis
> Communications AB or Tailscale Inc. Use at your own risk.
- Secure remote access to cameras
- Easy to install via EAP package
- Works on **Axis OS 10.12+** (non-root version, verified across 10.12–12.10)
- Works on **legacy Axis OS 9.x / 10.x** via the ACAP 3 variant
- Based on **WireGuard VPN** technology
[![Releases](https://img.shields.io/github/v/release/Mo3he/Axis_Cam_Tailscale)](https://github.com/Mo3he/Axis_Cam_Tailscale/releases)
[![License](https://img.shields.io/github/license/Mo3he/Axis_Cam_Tailscale)](LICENSE)
![Total Downloads](https://img.shields.io/github/downloads/Mo3he/Axis_Cam_Tailscale/total?style=flat&label=Downloads&color=blue)
[![Sponsor](https://img.shields.io/badge/sponsor-%E2%9D%A4-lightgrey?logo=github)](https://github.com/sponsors/Mo3he)
[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-orange?style=flat&logo=buy-me-a-coffee)](https://www.buymeacoffee.com/mo3he)
> **Disclaimer:** This is an independent, community-developed ACAP package and is not an official Axis Communications product. It is not affiliated with, endorsed by, or supported by Axis Communications AB. Use it at your own risk. For official Axis software, visit axis.com
> **Tailscale Notice:** Tailscale is a product of Tailscale Inc. This package independently redistributes the Tailscale binaries under the [BSD 3-Clause License](LICENSE) and is not affiliated with, endorsed by, or supported by Tailscale Inc. For the official Tailscale client, visit [tailscale.com](https://tailscale.com).
---
> **Tailscale Notice:** Tailscale is a product of Tailscale Inc. This package
> independently redistributes the Tailscale binaries under the
> [BSD 3-Clause License](LICENSE) and is not affiliated with, endorsed by, or
> supported by Tailscale Inc. For the official Tailscale client, visit
> [tailscale.com](https://tailscale.com).
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Settings](#settings)
- [Proxy Support](#proxy-support)
- [Accessing Tailnet Services from the Camera](#accessing-tailnet-services-from-the-camera)
- [Updating Tailscale](#updating-tailscale)
- [Purpose](#purpose)
- [Useful Links](#useful-links)
- [Compatibility](#compatibility)
- [Roadmap](#roadmap)
- [Star History](#star-history)
- [Support](#support)
- [Overview](#overview)
- [Compatibility](#compatibility)
- [Installation](#installation)
- [Configuration](#configuration)
- [Ports & security](#ports--security)
- [Accessing Tailnet services from the camera](#accessing-tailnet-services-from-the-camera)
- [Updating Tailscale](#updating-tailscale)
- [Build from source](#build-from-source)
- [Roadmap](#roadmap)
- [Links](#links)
- [License](#license)
---
## Overview
Adding a VPN client directly to the camera enables secure remote access without
additional hardware or complex network configuration, through Tailscale's
lightweight WireGuard-based tunnel.
- Secure remote access to cameras.
- Easy to install via EAP package.
- Works on **AXIS OS 10.12+** (non-root version, verified across 10.12–13).
- Works on **legacy AXIS OS 9.x / 10.x** via the ACAP 3 variant.
- Based on **WireGuard VPN** technology.
Tailscale ACAP runs **without root privileges** in userspace networking mode,
making it compatible with AXIS OS 10.12+. For **full kernel networking**, use the
**ROOT** version (AXIS OS 10.12–11.x only; AXIS OS 12 and later removed root
access for third-party applications). Learn more:
[How Tailscale Works](https://tailscale.com/blog/how-tailscale-works/).
## Compatibility
| Build | AXIS OS | Architecture | Notes |
|---|---|---|---|
| ACAP 4 (native SDK) | 10.12 – 13 | aarch64 | Standard, userspace networking |
| ACAP 4 (native SDK) | 10.12 – 13 | armv7hf | Standard, userspace networking |
| ACAP 4 root | 10.12 – 11.x | aarch64 | Full kernel networking (not on OS 12+) |
| ACAP 4 root | 10.12 – 11.x | armv7hf | Full kernel networking (not on OS 12+) |
| ACAP 3 (legacy SDK) | 9.x – 10.x | armv7hf | Legacy cameras |
> Most cameras use the standard **ACAP 4** build. The **root** builds add
> kernel-level networking but only run on AXIS OS 10.12–11.x (AXIS OS 12+ removed
> root access for ACAPs). Use the **ACAP 3** build only on legacy cameras that
> don't support ACAP 4 (AXIS OS 9–10).
**Verified on AXIS OS 13** (13.0.0, aarch64).
## Installation
Get the **prebuilt `.eap` file** from the [Releases page](https://github.com/Mo3he/Axis_Cam_Tailscale/releases).
> **Signed packages:** Release `.eap` files are signed with the Axis ACAP
> signing service and install normally on AXIS OS 12.10 and later.
>
> **Upgrading from an earlier version?** The signing vendor changed, so
> installing over a previously installed unsigned build can fail with
> **"Couldn't install: app"** (device log: *"Vendor ID in manifest does not
> match the vendor ID of the previous version"*). To upgrade: back up your app
> configuration, **uninstall** the old version, then install the signed one.
1. Log into your Axis camera.
2. Go to **Apps → Add App**.
3. Upload the `.eap` file.
Get the **prebuilt `.eap` file** from the
[Releases page](https://github.com/Mo3he/Axis_Cam_Tailscale/releases).
1. Log into your Axis camera.
2. Go to **Apps -> Add App**.
3. Upload the `.eap` file.
Once installed:
- Start the app.
- Click **Open** to view logs and get your Tailscale authentication URL.
- On uninstall, all changes/files are removed.
- Start the app.
- Click **Open** to view logs and get your Tailscale authentication URL.
- On uninstall, all changes/files are removed.
> You'll need a [Tailscale account](https://tailscale.com/) to authenticate.
---
## Configuration
## Usage
The app runs a C-based parameter bridge that reads settings from the ACAP
parameter store and launches Tailscale. View logs and connection status via the
**Open** button in the app, and authenticate using the provided URL or by
pre-entering an auth key in **Settings**. Parameter changes (ports, server URL,
auth key) are applied automatically without reinstalling the app.
- Runs a C-based parameter bridge (compiled via ACAP SDK 1.15.1) that reads settings from the ACAP parameter store and launches Tailscale.
- View logs and connection status via the **Open** button in the app.
- Authenticate using the provided URL, or pre-enter an auth key in **Settings**.
- Change the **Custom Server URL** in Settings to use a self-hosted [Headscale](https://headscale.net/) control server.
- Parameter changes (ports, server URL, auth key) are applied automatically without needing to reinstall the app.
---
## Settings
All parameters are configurable via the web UI (**Open → Settings** card) and take effect immediately without reinstalling:
All parameters are configurable via the web UI (**Open -> Settings** card) and
take effect immediately:
| Parameter | Default | Description |
|---|---|---|
@@ -75,179 +116,140 @@ All parameters are configurable via the web UI (**Open → Settings** card) and
| Auth Key | *(empty)* | Pre-authentication key (`tskey-auth-...`). Cleared automatically after first successful connection. Leave blank to authenticate via browser. |
| HTTP Proxy Port | `8080` | Port for the outbound HTTP/HTTPS proxy. |
| SOCKS5 Proxy Port | `1080` | Port for the outbound SOCKS5 proxy. |
| Accept DNS | `off` | Passes `--accept-dns=true` to `tailscale up`. Allows the tailnet to push DNS settings to the camera. Off by default to avoid overriding the camera's DNS configuration. Not available on `armv7hf_acap3`. |
| Accept Routes | `off` | Passes `--accept-routes=true` to `tailscale up`. Allows the camera to use subnet routes advertised by other nodes in the tailnet. Not available on `armv7hf_acap3`. |
| Accept DNS | `off` | Passes `--accept-dns=true` to `tailscale up`. Allows the tailnet to push DNS settings to the camera. Not available on `armv7hf_acap3`. |
| Accept Routes | `off` | Passes `--accept-routes=true` to `tailscale up`. Allows the camera to use subnet routes advertised by other nodes. Not available on `armv7hf_acap3`. |
| Advertise Routes (Subnet Router) | *(empty)* | Comma-separated CIDRs (e.g. `192.168.1.0/24,10.0.0.0/8`) this camera will route for the tailnet, turning it into a subnet router. Approve the routes in the Tailscale admin console after saving. Leave blank to disable. |
---
## Ports & security
All non-ROOT variants expose two local proxy endpoints that route outbound
traffic through the Tailscale tunnel. The ports are configurable via **Settings
-> HTTP Proxy Port / SOCKS5 Proxy Port**.
All non-ROOT variants expose two local proxy endpoints that route outbound traffic through the Tailscale tunnel. The ports are configurable via **Settings → HTTP Proxy Port / SOCKS5 Proxy Port** in the web UI.
### HTTP CONNECT Proxy — `http://127.0.0.1:8080` (default)
Routes HTTP and HTTPS traffic. Set this wherever an HTTP/HTTPS proxy field is available on the camera:
| Location | Field | Value |
| Proxy | Default address | Routes |
|---|---|---|
| System → Network → Global proxies | HTTP proxy | `http://127.0.0.1:<port>` |
| System → Network → Global proxies | HTTPS proxy | `http://127.0.0.1:<port>` |
| System → MQTT → Broker | HTTP proxy | `http://127.0.0.1:<port>` |
| System → MQTT → Broker | HTTPS proxy | `http://127.0.0.1:<port>` |
| HTTP CONNECT | `http://127.0.0.1:8080` | HTTP and HTTPS traffic |
| SOCKS5 | `127.0.0.1:1080` | Any SOCKS5-aware app or service |
### SOCKS5 Proxy — `127.0.0.1:1080` (default)
Set the HTTP CONNECT proxy wherever an HTTP/HTTPS proxy field is available on the
camera (System -> Network -> Global proxies; System -> MQTT -> Broker). For
SOCKS5-aware apps, set their proxy to `127.0.0.1:<port>`.
For ACAP apps or services that support SOCKS5, set their proxy to `127.0.0.1:<port>`.
> **Security:** the proxies bind to **loopback only** (`127.0.0.1`), so they are
> not exposed on the camera's network interface, the least-exposed of the VPN
> ACAPs. The active proxy addresses are shown in the **Proxy Configuration** card
> of the web UI. If you change a port that is already in use, the app logs an
> error and exits rather than silently falling back.
> The active proxy addresses are always shown in the **Proxy Configuration** card of the web UI.
## Accessing Tailnet services from the camera
> If you change a port that is already in use by another process, the app will log an error and exit rather than silently falling back to a different port.
---
## Accessing Tailnet Services from the Camera
There is an important asymmetry to understand. Making the camera **reachable from** the tailnet (browsing to it, VAPIX, SSH from another tailnet node) works on every build. The harder direction is the camera **reaching out to** a tailnet peer, for example mounting an SMB/CIFS network share hosted on another node. How well this works depends on which build you use.
### Why the build matters
There is an important asymmetry. Making the camera **reachable from** the tailnet
(browsing to it, VAPIX, SSH from another tailnet node) works on every build. The
harder direction is the camera **reaching out to** a tailnet peer, for example
mounting an SMB/CIFS share hosted on another node. How well this works depends on
the build:
| Build | Networking mode | Camera-initiated access to tailnet peers |
|---|---|---|
| Non-root (`aarch64`, `armv7hf`) and `armv7hf_acap3` | `--tun=userspace-networking` (no kernel `tailscale0` interface) | Only through the local **SOCKS5 / HTTP proxies**, and only for **proxy-aware** apps. Firmware system services (the SMB share client, NTP, etc.) are proxy-unaware, so they **cannot** reach a peer's `100.x` Tailscale IP directly. |
| Non-root (`aarch64`, `armv7hf`) and `armv7hf_acap3` | `--tun=userspace-networking` (no kernel `tailscale0`) | Only through the local **SOCKS5 / HTTP proxies**, and only for **proxy-aware** apps. Firmware system services (SMB client, NTP, etc.) are proxy-unaware and **cannot** reach a peer's `100.x` IP directly. |
| **ROOT** (`aarch64_root`, `armv7hf_root`) | Kernel networking with a real `tailscale0` interface | Peer `100.x` IPs are routable at the OS level, so firmware services **can** connect directly. Enable **Accept Routes** to also reach subnets behind other nodes. |
In short: on non-root builds the proxies cover apps that know how to use a proxy, but a system feature like "add network share" opens a raw socket that never touches the tunnel. The ROOT build is the clean way to let the camera *consume* tailnet services.
### Plan B: reverse-SSH tunnel
> **Requires root on the camera.** Port 445 is privileged, so binding it needs a root-capable build (e.g. developer certificates installed).
If you cannot use the ROOT build but still need the camera to mount a share on a machine that is on your tailnet, you can make the remote share appear **local** to the camera with a reverse SSH tunnel. Because the destination becomes `127.0.0.1`, the proxy-unaware SMB client never has to route over the tailnet.
> **Requires root on the camera.** Port 445 is privileged, so binding it needs a
> root-capable build (e.g. developer certificates installed).
From a computer that has both the share and tailnet access to the camera:
If you cannot use the ROOT build but still need the camera to mount a share on a
machine that is on your tailnet, make the remote share appear **local** to the
camera with a reverse SSH tunnel. Because the destination becomes `127.0.0.1`, the
proxy-unaware SMB client never has to route over the tailnet.
```bash
# Forward the camera's local port 445 back to the SMB share on this machine
ssh -R 445:localhost:445 root@<camera-tailscale-ip>
```
Then, in the camera's **System → Storage → Add network share** dialog, use `127.0.0.1` as the share host and connect.
---
Then, in **System -> Storage -> Add network share**, use `127.0.0.1` as the share
host and connect.
## Updating Tailscale
- New `.eap` files are auto-built and released **weekly** (if a new Tailscale version is available).
- To update, simply install the new `.eap` over the existing one.
- New `.eap` files are auto-built and released **weekly** (if a new Tailscale
version is available).
- To update, simply install the new `.eap` over the existing one.
### Manual update (advanced)
Replace the binaries in `common/app/lib/` (shared by `aarch64`, `armv7hf`, and their ROOT variants) or `arm_acap3/app/lib/` (legacy variant, kept separate):
Replace the binaries in `common/app/lib/` (shared by `aarch64`, `armv7hf`, and
their ROOT variants) or `arm_acap3/app/lib/` (legacy variant, kept separate):
- `tailscale`
- `tailscaled`
Download the latest versions: [Tailscale static builds](https://pkgs.tailscale.com/stable/#static)
Download the latest versions:
[Tailscale static builds](https://pkgs.tailscale.com/stable/#static).
#### Build locally
## Build from source
The Tailscale binaries are not stored in git, so first download them (see [Manual update](#manual-update-advanced) above) and place them in `common/app/lib/` — or `arm_acap3/app/lib/` for the legacy variant.
The Tailscale binaries are not stored in git, so first download them (see
[Manual update](#manual-update-advanced)) and place them in `common/app/lib/`, or
`arm_acap3/app/lib/` for the legacy variant.
All variants build from the **repository root**, pointing at the variant's own `Dockerfile`:
All variants build from the **repository root**, pointing at the variant's own
`Dockerfile`:
```bash
docker build -f aarch64/Dockerfile --tag <package_name> .
docker cp $(docker create <package_name>):/opt/app ./build
```
(Same for the others — just swap in `arm/Dockerfile`, `aarch64_ROOT/Dockerfile`, `arm_ROOT/Dockerfile`, or `arm_acap3/Dockerfile`.)
---
## Good News
Tailscale ACAP can now run **without root privileges**, making it compatible with **Axis OS 10.12+** — verified working across Axis OS 10.12, 11.11, and 12.10.
- Runs in **user space networking mode**.
For **full kernel networking**, use the **ROOT** version. Note: ROOT mode requires Axis OS 10.12–11.x — Axis OS 12 and later removed root access for third-party applications.
### Legacy camera support (Axis OS 9.x / 10.x)
An **ACAP 3** variant (`armv7hf_acap3`) is available for older cameras that do not support ACAP 4 / Axis OS 11+. It uses the same userspace networking mode and web UI, built against the ACAP SDK 3.5 toolchain.
---
## Purpose
Adding a VPN client directly to the camera enables:
- Secure remote access without additional hardware or complex network configuration.
- Easy setup through Tailscale’s lightweight WireGuard-based tunnel.
Learn more: [How Tailscale Works](https://tailscale.com/blog/how-tailscale-works/)
---
## Useful Links
- [Tailscale](https://tailscale.com/)
- [Tailscale GitHub](https://github.com/tailscale/tailscale)
- [WireGuard](https://www.wireguard.com/)
- [Axis Communications](https://www.axis.com/)
---
## Compatibility
The Tailscale ACAP is compatible with Axis cameras with **ARM** and **AARCH64**-based SoCs.
| Variant | Architecture | Axis OS | Notes |
|---|---|---|---|
| `aarch64` | AArch64 | 10.12 – 13 (ACAP 4) | Standard, userspace networking, configurable proxy ports |
| `armv7hf` | ARMv7 | 10.12 – 13 (ACAP 4) | Standard, userspace networking, configurable proxy ports |
| `aarch64_root` | AArch64 | 10.12 – 11.x (ACAP 4) | Full kernel networking (root) — not supported on OS 12+ |
| `armv7hf_root` | ARMv7 | 10.12 – 11.x (ACAP 4) | Full kernel networking (root) — not supported on OS 12+ |
| `armv7hf_acap3` | ARMv7 | **9.x – 10.x** | Legacy cameras, ACAP SDK 3 |
> Not sure which variant to use? Check **System → Properties → Firmware version** on your camera. Axis OS 12+ → use the standard variant (`aarch64` or `armv7hf`). Axis OS 10.12–11.x → standard variant works too, or ROOT if you need kernel networking. Axis OS 9.x → use `armv7hf_acap3`.
>
> The standard variant's floor was verified by live-testing the same build on Axis OS 10.12.300, 11.11.212, and 12.10.68 — it is not limited to 11.11+ as earlier releases implied. The ROOT variant was also verified on Axis OS 10.12.300 with genuine kernel networking confirmed over SSH (processes running as `root`, a real `tailscale0` kernel interface present, and `ip_forward` correctly toggling on when subnet routes are advertised) — Axis OS 10.x ran third-party apps as root by default, before the privilege sandboxing introduced later, so ROOT was never actually limited to 11.11+.
You can verify your device details using the following command:
```bash
curl --anyauth "*" -u <username>:<password> <device_ip>/axis-cgi/basicdeviceinfo.cgi --data '{"apiVersion":"1.0","context":"Client defined request ID","method":"getAllProperties"}'
```
> Replace `<device_ip>`, `<username>`, and `<password>` with your device credentials.
> Enclose your password in quotes `' '` if it contains special characters.
---
(Same for the others: just swap in `arm/Dockerfile`, `aarch64_ROOT/Dockerfile`,
`arm_ROOT/Dockerfile`, or `arm_acap3/Dockerfile`.)
## Roadmap
### AXIS OS 13 Preparation
AXIS OS 13 (scheduled for September 2026) introduces several breaking changes that affect all ACAP applications. The following items are required to maintain compatibility. See the full [AXIS OS 13 breaking changes](https://www.axis.com/for-developers/news/AXIS-OS-13-breaking-changes) announcement for details.
AXIS OS 13 (scheduled for September 2026) introduces several breaking changes that
affect all ACAP applications. See the full
[AXIS OS 13 breaking changes](https://www.axis.com/for-developers/news/AXIS-OS-13-breaking-changes)
announcement for details.
- [x] **Recompile for 64-bit time (Y2038)** - AXIS OS 13 switches to a 64-bit time interface. All ACAP apps must be recompiled against the updated SDK. Cameras with incompatible apps installed will roll back the OS upgrade rather than proceed. Done for the standard `aarch64`/`armv7hf` builds (now built against ACAP Native SDK 12.10.0); the ROOT variants intentionally stay on the older SDK since Axis OS 12+ never supports root third-party apps, so they can never reach OS 13 regardless.
- [x] **Migrate to Manifest Schema v2** - The `manifest.json` must use Manifest Schema v2, including an explicit declaration of compatible AXIS OS versions, to satisfy the new signing and compatibility requirements. Done for `aarch64`/`armv7hf` (schema 2.0.0, `compatibleOsVersions` declared); verified this does not break installability on older firmware (OS 10.12–12.10 all tested and working) before promoting it as the standard build.
- [x] **Audit for executable stack usage** - Any ACAP compiled with an executable stack must be recompiled to comply with the new security restrictions in AXIS OS 13. Checked all compiled binaries (`param_bridge` for `aarch64`/`armv7hf`, both standard and ROOT, plus the bundled `tailscale`/`tailscaled` Go binaries) via `objdump`'s `GNU_STACK` program header — all report `flags rw-` (no executable stack) on every architecture and variant.
- [x] **Verify web UI works over HTTPS** - AXIS OS 13 enforces HTTPS-only connections by default. The bundled web UI must be tested to confirm it functions correctly under this constraint. Verified live: the page and every endpoint it calls (`param.cgi` GET/update, the `reverseProxy` settings API GET/POST, `applications/list.cgi`, `systemlog.cgi`, the restart trigger) all work correctly over HTTPS. The UI only ever issues relative-path requests (no hardcoded `http://` fetch targets), so it inherits the page's own protocol with no mixed-content risk.
- [ ] **Sign the ACAP via the Axis ACAP Portal** - AXIS OS 13 removes the ability to install unsigned applications in production environments. The app must be submitted and signed through the official Axis ACAP Portal to remain installable. Deferred for now — the manifest's `vendorId` is a placeholder value, not yet a portal-registered one.
- [x] **Recompile for 64-bit time (Y2038)** - Done for the standard
`aarch64`/`armv7hf` builds (now built against ACAP Native SDK 12.10.0); the
ROOT variants intentionally stay on the older SDK since AXIS OS 12+ never
supports root third-party apps.
- [x] **Migrate to Manifest Schema v2** - Done for `aarch64`/`armv7hf` (schema
2.0.0, `compatibleOsVersions` declared); verified installability on OS
10.12–13.
- [x] **Audit for executable stack usage** - All compiled binaries report
`flags rw-` (no executable stack) on every architecture and variant.
- [x] **Verify web UI works over HTTPS** - Verified live; the UI only issues
relative-path requests, so it inherits the page's protocol with no
mixed-content risk.
- [x] **Sign the ACAP via the Axis ACAP Portal** - Done; `aarch64`/`armv7hf`
packages are signed with the Axis ACAP signing service. The `root` and
`acap3` variants use manifest schema v1.x and are distributed unsigned.
### General Improvements
- [x] **Accept DNS from tailnet toggle** - Add an opt-in setting to the settings page that passes `--accept-dns=true` to `tailscale up`. Defaults to off to prevent Tailscale from overriding `resolv.conf` on cameras that don't need MagicDNS.
- [x] **Accept routes toggle** - Add an opt-in setting that passes `--accept-routes=true` to `tailscale up`, allowing the camera to use subnet routes advertised by other nodes in the tailnet.
- [ ] **Switch to tiny-tailscale binaries** - Evaluate replacing the bundled `tailscale` and `tailscaled` binaries with [tiny-tailscale](https://github.com/iamromulan/tiny-tailscale) builds. These combine both into a single binary, strip unused features, and are significantly smaller (~43% reduction), reducing install size and memory footprint across all architectures.
- [x] **Accept DNS from tailnet toggle** - Opt-in setting passing
`--accept-dns=true` to `tailscale up` (defaults off).
- [x] **Accept routes toggle** - Opt-in setting passing `--accept-routes=true`.
- [ ] **Switch to tiny-tailscale binaries** - Evaluate replacing the bundled
`tailscale`/`tailscaled` with [tiny-tailscale](https://github.com/iamromulan/tiny-tailscale)
builds (single binary, ~43% smaller).
---
## Links
## Star History
- [Tailscale](https://tailscale.com/)
- [Tailscale GitHub](https://github.com/tailscale/tailscale)
- [WireGuard](https://www.wireguard.com/)
- [Axis Communications](https://www.axis.com/)
[![Star History Chart](https://api.star-history.com/svg?repos=Mo3he/Axis_Cam_Tailscale&type=Date)](https://www.star-history.com/#Mo3he/Axis_Cam_Tailscale&Date)
## License
---
## Support
If you like this project and want to support my work:
[Sponsor Me](https://github.com/sponsors/Mo3he)
The packaging code in this repository is licensed under BSD 3-Clause (see
[LICENSE](LICENSE)); this also covers the redistributed Tailscale binaries
(upstream Tailscale is BSD 3-Clause). Bundled upstream components are listed in
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
+23
View File
@@ -0,0 +1,23 @@
# Security Policy
This is an independent, community-developed ACAP package, provided on a
best-effort basis. It is not an official Axis Communications product.
## Reporting a vulnerability
Please report security issues privately rather than in a public issue:
- Use GitHub's "Report a vulnerability" (Security > Advisories) to open a
private advisory, or
- email <moshe@mohome.net>.
Include the affected version (or `.eap` filename), camera model / Axis OS
version, a description and its impact, and reproduction steps if available. You
can expect an acknowledgement within a reasonable time; please avoid public
disclosure until a fix is released.
## Scope
Reports about this ACAP's own wrapper code, configuration handling, and default
settings are in scope. Vulnerabilities in bundled upstream projects should also
be reported to their respective upstream projects.
+42
View File
@@ -0,0 +1,42 @@
# Third-Party Notices
This ACAP package redistributes the Tailscale client. The ACAP's own wrapper
code is licensed separately (see `LICENSE`, BSD 3-Clause).
## Tailscale
- Copyright (c) 2020 Tailscale & AUTHORS
- Project: <https://github.com/tailscale/tailscale>
- License: BSD 3-Clause
Tailscale is a product of Tailscale Inc. This package independently
redistributes the Tailscale binaries and is not affiliated with, endorsed by, or
supported by Tailscale Inc. For the official Tailscale client, visit
<https://tailscale.com>.
```text
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
+2 -2
View File
@@ -1,5 +1,5 @@
To build, from main directory
docker build --tag aarch64 .
docker build --tag aarch64 .
docker cp $(docker create aarch64):/opt/app ./build
docker cp $(docker create aarch64):/opt/app ./build
+3 -3
View File
@@ -4,10 +4,10 @@
"setup": {
"appName": "Tailscale_VPN",
"friendlyName": "Tailscale VPN",
"vendor": "Mo3he",
"vendorId": "5741c1fb91",
"vendor": "moshe@mohome.net",
"vendorId": "70ee172dd9",
"vendorUrl": "https://github.com/Mo3he/Axis_Cam_Tailscale",
"version": "1.98.8",
"version": "1.98.10",
"architecture": "aarch64",
"runMode": "respawn",
"compatibleOsVersions": [
+2 -2
View File
@@ -1,5 +1,5 @@
To build, from main directory
docker build --tag aarch64 .
docker build --tag aarch64 .
docker cp $(docker create aarch64):/opt/app ./build
docker cp $(docker create aarch64):/opt/app ./build
+1 -1
View File
@@ -12,7 +12,7 @@
},
"vendorUrl": "https://github.com/Mo3he/Axis_Cam_Tailscale",
"runMode": "respawn",
"version": "1.98.8",
"version": "1.98.10",
"architecture": "aarch64"
},
"configuration": {
+2 -2
View File
@@ -1,5 +1,5 @@
To build from main directory
docker build --tag arm .
docker build --tag arm .
docker cp $(docker create arm):/opt/app ./build
docker cp $(docker create arm):/opt/app ./build
+3 -3
View File
@@ -4,10 +4,10 @@
"setup": {
"appName": "Tailscale_VPN",
"friendlyName": "Tailscale VPN",
"vendor": "Mo3he",
"vendorId": "5741c1fb91",
"vendor": "moshe@mohome.net",
"vendorId": "70ee172dd9",
"vendorUrl": "https://github.com/Mo3he/Axis_Cam_Tailscale",
"version": "1.98.8",
"version": "1.98.10",
"architecture": "armv7hf",
"runMode": "respawn",
"compatibleOsVersions": [
+2 -2
View File
@@ -1,5 +1,5 @@
To build from main directory
docker build --tag arm .
docker build --tag arm .
docker cp $(docker create arm):/opt/app ./build
docker cp $(docker create arm):/opt/app ./build
+1 -1
View File
@@ -12,7 +12,7 @@
},
"vendorUrl": "https://github.com/Mo3he/Axis_Cam_Tailscale",
"runMode": "respawn",
"version": "1.98.8",
"version": "1.98.10",
"architecture": "armv7hf"
},
"configuration": {
+23 -23
View File
@@ -16,19 +16,19 @@ logger -t "Tailscale_VPN" "Starting tailscaled daemon"
# Log to file (not piped through logger) -- avoids extra logger process holding
# tailscaled stdout open, which prevents our wait loop from detecting exit
"$APP_DIR/lib/tailscaled" \
--state="$STATE_DIR/tailscaled.state" \
--socket="$STATE_DIR/tailscaled.sock" \
--socks5-server=localhost:1055 \
--outbound-http-proxy-listen=localhost:8080 \
--tun=userspace-networking \
>> "$STATE_DIR/tailscaled.log" 2>&1 &
--state="$STATE_DIR/tailscaled.state" \
--socket="$STATE_DIR/tailscaled.sock" \
--socks5-server=localhost:1055 \
--outbound-http-proxy-listen=localhost:8080 \
--tun=userspace-networking \
>>"$STATE_DIR/tailscaled.log" 2>&1 &
TAILSCALED_PID=$!
# Wait for socket to appear (up to 15 seconds)
i=0
while [ $i -lt 15 ] && [ ! -S "$STATE_DIR/tailscaled.sock" ]; do
sleep 1
i=$((i + 1))
sleep 1
i=$((i + 1))
done
logger -t "Tailscale_VPN" "Connecting to Tailscale network"
@@ -37,9 +37,9 @@ logger -t "Tailscale_VPN" "Connecting to Tailscale network"
# cameras with limited RAM (e.g. 222 MB).
# Capture output so we can extract auth URL and log it to syslog for the web UI.
UP_OUT=$("$APP_DIR/lib/tailscale" \
--socket="$STATE_DIR/tailscaled.sock" \
up --hostname="$(hostname)" --timeout=10s 2>&1) || true
echo "$UP_OUT" >> "$STATE_DIR/tailscaled.log"
--socket="$STATE_DIR/tailscaled.sock" \
up --hostname="$(hostname)" --timeout=10s 2>&1) || true
echo "$UP_OUT" >>"$STATE_DIR/tailscaled.log"
# If an auth URL was returned, log it so the web UI can show it
AUTH_URL=$(echo "$UP_OUT" | grep -o 'https://login\.tailscale\.com/[^ ]*' | head -1)
@@ -48,7 +48,7 @@ AUTH_URL=$(echo "$UP_OUT" | grep -o 'https://login\.tailscale\.com/[^ ]*' | head
# Log IP and version into syslog so the web UI details panel can populate
TS_IP=$("$APP_DIR/lib/tailscale" --socket="$STATE_DIR/tailscaled.sock" ip -4 2>/dev/null | head -1)
TS_VER=$("$APP_DIR/lib/tailscale" --socket="$STATE_DIR/tailscaled.sock" version 2>/dev/null | head -1)
[ -n "$TS_IP" ] && logger -t "Tailscale_VPN" "Tailscale IP: $TS_IP"
[ -n "$TS_IP" ] && logger -t "Tailscale_VPN" "Tailscale IP: $TS_IP"
[ -n "$TS_VER" ] && logger -t "Tailscale_VPN" "Tailscale version: $TS_VER"
logger -t "Tailscale_VPN" "Tailscale VPN is running"
@@ -63,19 +63,19 @@ logger -t "Tailscale_VPN" "SOCKS5 proxy: 127.0.0.1:1055"
STATUS_FILE="$STATE_DIR/status.json"
publish_status() {
if "$APP_DIR/lib/tailscale" --socket="$STATE_DIR/tailscaled.sock" status --json > "$STATUS_FILE.tmp" 2>/dev/null; then
mv "$STATUS_FILE.tmp" "$STATUS_FILE" 2>/dev/null
chmod 644 "$STATUS_FILE" 2>/dev/null
else
rm -f "$STATUS_FILE.tmp" 2>/dev/null
fi
if "$APP_DIR/lib/tailscale" --socket="$STATE_DIR/tailscaled.sock" status --json >"$STATUS_FILE.tmp" 2>/dev/null; then
mv "$STATUS_FILE.tmp" "$STATUS_FILE" 2>/dev/null
chmod 644 "$STATUS_FILE" 2>/dev/null
else
rm -f "$STATUS_FILE.tmp" 2>/dev/null
fi
}
# Remove stale status on stop so the UI does not show a connected node after exit.
cleanup() {
rm -f "$STATUS_FILE" 2>/dev/null
[ -n "$TAILSCALED_PID" ] && kill "$TAILSCALED_PID" 2>/dev/null
exit 0
rm -f "$STATUS_FILE" 2>/dev/null
[ -n "$TAILSCALED_PID" ] && kill "$TAILSCALED_PID" 2>/dev/null
exit 0
}
trap cleanup TERM INT
@@ -83,8 +83,8 @@ trap cleanup TERM INT
# status fresh. This keeps the parent Tailscale_VPN (C launcher) in the process
# table so pidof finds it and the camera web UI shows "Running" instead of "Stopped".
while kill -0 "$TAILSCALED_PID" 2>/dev/null; do
publish_status
sleep 5
publish_status
sleep 5
done
rm -f "$STATUS_FILE" 2>/dev/null
+1 -1
View File
@@ -3,7 +3,7 @@ MENUNAME="Tailscale VPN"
VENDOR="Mo3he"
APPMAJORVERSION=1
APPMINORVERSION=98
APPMICROVERSION=8
APPMICROVERSION=10
APPTYPE=armv7hf
APPNAME=Tailscale_VPN
APPOPTS=""
+72 -72
View File
@@ -27,48 +27,48 @@ ACCEPT_ROUTES="false"
ADVERTISE_ROUTES=""
if [ -f "$STATE_DIR/params.conf" ]; then
. "$STATE_DIR/params.conf"
. "$STATE_DIR/params.conf"
fi
if [ "$VARIANT" = "root" ]; then
logger -t "Tailscale_VPN" "Starting (root mode): custom_server=${CUSTOM_SERVER:-(default)}"
logger -t "Tailscale_VPN" "Starting (root mode): custom_server=${CUSTOM_SERVER:-(default)}"
else
logger -t "Tailscale_VPN" "Starting: http_port=$CONF_HTTP socks_port=$CONF_SOCKS custom_server=${CUSTOM_SERVER:-(default)}"
logger -t "Tailscale_VPN" "Starting: http_port=$CONF_HTTP socks_port=$CONF_SOCKS custom_server=${CUSTOM_SERVER:-(default)}"
# Check whether a TCP port is already bound
is_port_in_use() {
local port=$1
local hex_port
hex_port=$(printf '%04X' "$port")
grep -q ":${hex_port} " /proc/net/tcp 2>/dev/null && return 0
grep -q ":${hex_port} " /proc/net/tcp6 2>/dev/null && return 0
return 1
}
# Check whether a TCP port is already bound
is_port_in_use() {
local port=$1
local hex_port
hex_port=$(printf '%04X' "$port")
grep -q ":${hex_port} " /proc/net/tcp 2>/dev/null && return 0
grep -q ":${hex_port} " /proc/net/tcp6 2>/dev/null && return 0
return 1
}
if is_port_in_use "$CONF_HTTP"; then
logger -t "Tailscale_VPN" "ERROR: HTTP proxy port $CONF_HTTP is already in use. Change it in Settings."
exit 1
fi
if is_port_in_use "$CONF_SOCKS"; then
logger -t "Tailscale_VPN" "ERROR: SOCKS5 port $CONF_SOCKS is already in use. Change it in Settings."
exit 1
fi
if is_port_in_use "$CONF_HTTP"; then
logger -t "Tailscale_VPN" "ERROR: HTTP proxy port $CONF_HTTP is already in use. Change it in Settings."
exit 1
fi
if is_port_in_use "$CONF_SOCKS"; then
logger -t "Tailscale_VPN" "ERROR: SOCKS5 port $CONF_SOCKS is already in use. Change it in Settings."
exit 1
fi
fi
logger -t "Tailscale_VPN" "Starting tailscaled daemon"
if [ "$VARIANT" = "root" ]; then
$TAILSCALED_PATH \
--state="$STATE_DIR/tailscaled.state" \
--socket=$SOCKET_PATH \
>/dev/null 2>&1 &
$TAILSCALED_PATH \
--state="$STATE_DIR/tailscaled.state" \
--socket=$SOCKET_PATH \
>/dev/null 2>&1 &
else
$TAILSCALED_PATH \
--state="$STATE_DIR/tailscaled.state" \
--socket=$SOCKET_PATH \
--socks5-server=localhost:$CONF_SOCKS \
--outbound-http-proxy-listen=localhost:$CONF_HTTP \
--tun=userspace-networking \
>/dev/null 2>&1 &
$TAILSCALED_PATH \
--state="$STATE_DIR/tailscaled.state" \
--socket=$SOCKET_PATH \
--socks5-server=localhost:$CONF_SOCKS \
--outbound-http-proxy-listen=localhost:$CONF_HTTP \
--tun=userspace-networking \
>/dev/null 2>&1 &
fi
TAILSCALED_PID=$!
@@ -77,19 +77,19 @@ sleep 2
TAILSCALE_CMD="$TAILSCALE_PATH --socket=$SOCKET_PATH up --reset --hostname=$(hostname)"
if [ -n "$CUSTOM_SERVER" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
TAILSCALE_CMD="$TAILSCALE_CMD --login-server $CUSTOM_SERVER"
fi
if [ -n "$AUTH_KEY" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
TAILSCALE_CMD="$TAILSCALE_CMD --authkey $AUTH_KEY"
fi
if [ "$ACCEPT_DNS" = "true" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
TAILSCALE_CMD="$TAILSCALE_CMD --accept-dns=true"
fi
if [ "$ACCEPT_ROUTES" = "true" ]; then
TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
TAILSCALE_CMD="$TAILSCALE_CMD --accept-routes=true"
fi
# Advertise LAN subnets so this camera acts as a subnet router. Comma-separated
@@ -99,11 +99,11 @@ fi
# forward packets between the tailnet and the LAN, so enable IP forwarding.
# Routes must still be approved in the Tailscale admin console either way.
if [ -n "$ADVERTISE_ROUTES" ]; then
if [ "$VARIANT" = "root" ]; then
echo 1 > /proc/sys/net/ipv4/ip_forward 2>/dev/null || true
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true
fi
TAILSCALE_CMD="$TAILSCALE_CMD --advertise-routes=$ADVERTISE_ROUTES"
if [ "$VARIANT" = "root" ]; then
echo 1 >/proc/sys/net/ipv4/ip_forward 2>/dev/null || true
echo 1 >/proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true
fi
TAILSCALE_CMD="$TAILSCALE_CMD --advertise-routes=$ADVERTISE_ROUTES"
fi
# Run `tailscale up` in the background and act on its outcome. If the node needs
@@ -115,27 +115,27 @@ fi
# for it from here, because in POSIX sh `wait` only works on children of the
# current shell — a subshell waiting on the parent's child returns 127.
{
eval "$TAILSCALE_CMD"
up_exit=$?
if [ "$up_exit" -eq 0 ]; then
if [ "$VARIANT" = "root" ]; then
logger -t "Tailscale_VPN" "Tailscale VPN is running (root mode)"
else
logger -t "Tailscale_VPN" "Tailscale VPN is running"
fi
# Auth succeeded with a one-time auth key — signal param_bridge to clear it
if [ -n "$AUTH_KEY" ]; then
: > "$STATE_DIR/authkey_clear"
fi
else
logger -t "Tailscale_VPN" "ERROR: tailscale up failed (exit $up_exit)"
fi
eval "$TAILSCALE_CMD"
up_exit=$?
if [ "$up_exit" -eq 0 ]; then
if [ "$VARIANT" = "root" ]; then
logger -t "Tailscale_VPN" "Tailscale VPN is running (root mode)"
else
logger -t "Tailscale_VPN" "Tailscale VPN is running"
fi
# Auth succeeded with a one-time auth key — signal param_bridge to clear it
if [ -n "$AUTH_KEY" ]; then
: >"$STATE_DIR/authkey_clear"
fi
else
logger -t "Tailscale_VPN" "ERROR: tailscale up failed (exit $up_exit)"
fi
} &
TAILSCALE_UP_PID=$!
if [ "$VARIANT" != "root" ]; then
logger -t "Tailscale_VPN" "HTTP/HTTPS proxy: http://127.0.0.1:$CONF_HTTP"
logger -t "Tailscale_VPN" "SOCKS5 proxy: 127.0.0.1:$CONF_SOCKS"
logger -t "Tailscale_VPN" "HTTP/HTTPS proxy: http://127.0.0.1:$CONF_HTTP"
logger -t "Tailscale_VPN" "SOCKS5 proxy: 127.0.0.1:$CONF_SOCKS"
fi
# Publish tailscale's real backend state as JSON for the web UI to consume.
@@ -145,19 +145,19 @@ fi
STATUS_FILE="$APP_DIR/html/status.json"
publish_status() {
if "$TAILSCALE_PATH" --socket="$SOCKET_PATH" status --json > "$STATUS_FILE.tmp" 2>/dev/null; then
mv "$STATUS_FILE.tmp" "$STATUS_FILE" 2>/dev/null
chmod 644 "$STATUS_FILE" 2>/dev/null
else
rm -f "$STATUS_FILE.tmp" 2>/dev/null
fi
if "$TAILSCALE_PATH" --socket="$SOCKET_PATH" status --json >"$STATUS_FILE.tmp" 2>/dev/null; then
mv "$STATUS_FILE.tmp" "$STATUS_FILE" 2>/dev/null
chmod 644 "$STATUS_FILE" 2>/dev/null
else
rm -f "$STATUS_FILE.tmp" 2>/dev/null
fi
}
status_loop() {
while true; do
publish_status
sleep 5
done
while true; do
publish_status
sleep 5
done
}
status_loop &
STATUS_LOOP_PID=$!
@@ -166,11 +166,11 @@ STATUS_LOOP_PID=$!
# stop/restart so param_bridge (which signals this script) leaves no orphans or
# stale state.
cleanup() {
[ -n "$STATUS_LOOP_PID" ] && kill "$STATUS_LOOP_PID" 2>/dev/null
[ -n "$TAILSCALE_UP_PID" ] && kill "$TAILSCALE_UP_PID" 2>/dev/null
[ -n "$TAILSCALED_PID" ] && kill "$TAILSCALED_PID" 2>/dev/null
rm -f "$STATUS_FILE" 2>/dev/null
exit 0
[ -n "$STATUS_LOOP_PID" ] && kill "$STATUS_LOOP_PID" 2>/dev/null
[ -n "$TAILSCALE_UP_PID" ] && kill "$TAILSCALE_UP_PID" 2>/dev/null
[ -n "$TAILSCALED_PID" ] && kill "$TAILSCALED_PID" 2>/dev/null
rm -f "$STATUS_FILE" 2>/dev/null
exit 0
}
trap cleanup TERM INT