-
Notifications
You must be signed in to change notification settings - Fork 0
fix(entrypoint): bash the user script #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
📝 WalkthroughWalkthroughThe Estimated code review effort🎯 2 (Simple) | ⏱️ ~8 minutes
Pre-merge checks and finishing touches✅ Passed checks (2 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 1 file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
bin/entrypoint (1)
28-30: Consider adding error handling for the user startup script.The entrypoint continues to launch OpenVPN regardless of whether the user startup script succeeds or fails. This could lead to unexpected behavior if the user script performs critical setup steps.
Consider checking the exit code and optionally failing fast on errors:
# Execute user startup script if it exists if [[ -e ${USER_STARTUP_SCRIPT} ]]; then bash ${USER_STARTUP_SCRIPT} + USER_SCRIPT_EXIT=$? + if [[ ${USER_SCRIPT_EXIT} -ne 0 ]]; then + echo "ERROR: User startup script failed with exit code ${USER_SCRIPT_EXIT}" >&2 + exit ${USER_SCRIPT_EXIT} + fi fiAlternatively, if you want to log errors but continue anyway:
# Execute user startup script if it exists if [[ -e ${USER_STARTUP_SCRIPT} ]]; then bash ${USER_STARTUP_SCRIPT} + if [[ $? -ne 0 ]]; then + echo "WARNING: User startup script exited with error code $?" >&2 + fi fi
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
bin/entrypoint(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: cubic · AI code reviewer
| if [[ -e ${USER_STARTUP_SCRIPT} ]]; then | ||
| chmod a+x ${USER_STARTUP_SCRIPT} | ||
| ${USER_STARTUP_SCRIPT} | ||
| bash ${USER_STARTUP_SCRIPT} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Script executed:
#!/bin/bash
# Explore repository structure and find relevant files
echo "=== Repository structure ==="
git ls-files | head -30
echo -e "\n=== Searching for entrypoint-related files ==="
fd -t f "entrypoint" 2>/dev/null
echo -e "\n=== Checking bin/entrypoint file size ==="
wc -l bin/entrypoint 2>/dev/null || echo "File not found in expected location"Repository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Repository structure ===
.github/CODEOWNERS
.github/dependabot.yml
.github/workflows/ci-docker.yml
.github/workflows/conventional-commits.yml
.github/workflows/publish.yml
Dockerfile
LICENSE
README.md
bin/entrypoint
=== Searching for entrypoint-related files ===
bin/entrypoint
=== Checking bin/entrypoint file size ===
37 bin/entrypoint
</shell_result>
Script executed:
#!/bin/bash
# Read the complete bin/entrypoint file
echo "=== Contents of bin/entrypoint ==="
cat -n bin/entrypoint
echo -e "\n=== Searching for USER_STARTUP_SCRIPT documentation ==="
rg -n "USER_STARTUP_SCRIPT" --type md
echo -e "\n=== Searching for entrypoint-user mentions ==="
rg -n "entrypoint-user"
echo -e "\n=== README.md content ==="
cat README.mdRepository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Contents of bin/entrypoint ===
1 #!/bin/bash
2
3 CONFIG_DIR=/etc/openvpn
4
5 USER_STARTUP_SCRIPT=${USER_STARTUP_SCRIPT:-/usr/local/bin/entrypoint-user.sh}
6
7 ENABLE_NAT=${ENABLE_NAT:-1}
8 NAT_SOURCE=${NAT_SOURCE:-10.8.0.0/24}
9 NAT_DEVICE=${NAT_DEVICE:-eth0}
10
11 DEBUG=${DEBUG:-0}
12
13 # Create device for tun interfaces
14 mkdir -p /dev/net
15 if [ ! -c /dev/net/tun ]; then
16 mknod /dev/net/tun c 10 200
17 fi
18
19 if [[ $ENABLE_NAT = 1 ]]; then
20 iptables -t nat -A POSTROUTING -s ${NAT_SOURCE} -o ${NAT_DEVICE} -j MASQUERADE
21 # Basic kill switch: Drop forwarded traffic by default, allow only VPN-related
22 iptables -P FORWARD DROP
23 iptables -A FORWARD -i tun+ -o ${NAT_DEVICE} -j ACCEPT
24 iptables -A FORWARD -i ${NAT_DEVICE} -o tun+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
25 fi
26
27 # Execute user startup script if it exists
28 if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
29 bash ${USER_STARTUP_SCRIPT}
30 fi
31
32 # Redirect output to /dev/null unless in debug mode
33 if [[ $DEBUG = 0 ]]; then
34 exec &>/dev/null
35 fi
36
37 exec openvpn --config ${CONFIG_DIR}/openvpn.conf --cd ${CONFIG_DIR} $@
=== Searching for USER_STARTUP_SCRIPT documentation ===
README.md:14:but the location can be overridden with the `USER_STARTUP_SCRIPT` environment variable
=== Searching for entrypoint-user mentions ===
README.md:13:The image provides for the ability to provide a custom startup script. It looks for a user script at `/usr/local/bin/entrypoint-user.sh` by default,
bin/entrypoint:5:USER_STARTUP_SCRIPT=${USER_STARTUP_SCRIPT:-/usr/local/bin/entrypoint-user.sh}
=== README.md content ===
# docker-openvpn
Simple OpenVPN image with updated version, optimized for privacy-focused VPN services.
## Using the image
There is no default config provided by the image, so you'll need to provide your own.
```
docker run -d -n openvpn -v /path/to/openvpn.conf:/etc/openvpn/openvpn.conf ghcr.io/blinklabs-io/openvpn --config /etc/openvpn/openvpn.conf
```
The image provides for the ability to provide a custom startup script. It looks for a user script at `/usr/local/bin/entrypoint-user.sh` by default,
but the location can be overridden with the `USER_STARTUP_SCRIPT` environment variable
## Privacy and Security Recommendations
For a no-log, privacy-focused setup:
### OpenVPN Configuration
Use these options in your `openvpn.conf` for strong encryption and no logging:
```conf
# Disable logging
log /dev/null
verb 0
# Strong ciphers
cipher AES-256-GCM
auth SHA256
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
tls-version-min 1.2
# Privilege drop
user nobody
group nogroup
# Other privacy settings
persist-key
persist-tun
```
### Docker Run Options
- Use Docker secrets for certificates/keys: `--secret mykey=/path/to/key`
- Run with necessary capabilities only: `--cap-add=NET_ADMIN` (avoid `--privileged`)
- For Kubernetes (Helm), use `securityContext` to limit privileges.
### Maintenance
- Rebuild images regularly to pull security updates from Debian repos.
- Scan for vulnerabilities with tools like Trivy (automated via GitHub Actions).
- Test for leaks using services like ipleak.net while connected.
**Warning**: Running in privileged mode increases security risks—use only when necessary.
</shell_result>
Script executed:
#!/bin/bash
# Check git history for bin/entrypoint
echo "=== Recent commits touching bin/entrypoint ==="
git log --oneline -20 -- bin/entrypoint 2>/dev/null || echo "No git history available"
echo -e "\n=== Show changes to line 29 ==="
git log -p -S "bash.*USER_STARTUP_SCRIPT" -- bin/entrypoint 2>/dev/null | head -100 || echo "No detailed history available"
echo -e "\n=== Git blame for line 29 ==="
git blame -L 29,29 bin/entrypoint 2>/dev/null || echo "No blame info available"
echo -e "\n=== Check current branch ==="
git branch -a 2>/dev/null | head -10
git log --oneline -5 2>/dev/nullRepository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Recent commits touching bin/entrypoint ===
6fcc967 fix(entrypoint): bash the user script
=== Show changes to line 29 ===
=== Git blame for line 29 ===
^6fcc967 (Chris Gianelloni 2025-11-26 16:07:13 -0500 29) bash ${USER_STARTUP_SCRIPT}
=== Check current branch ===
* (HEAD detached at FETCH_HEAD)
coderabbit_19
main
remotes/origin/HEAD -> origin/main
remotes/origin/main
6fcc967 fix(entrypoint): bash the user script
</shell_result>
Script executed:
#!/bin/bash
# Show the full diff of this commit
echo "=== Full diff of commit 6fcc967 ==="
git show 6fcc967 --no-patch
echo -e "\n=== Full diff content ==="
git show 6fcc967 -- bin/entrypointRepository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Full diff of commit 6fcc967 ===
commit 6fcc967b511b2ae36d609814261776f0c6b4f4b9
Author: Chris Gianelloni <wolf31o2@blinklabs.io>
Date: Wed Nov 26 16:07:13 2025 -0500
fix(entrypoint): bash the user script
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
=== Full diff content ===
commit 6fcc967b511b2ae36d609814261776f0c6b4f4b9
Author: Chris Gianelloni <wolf31o2@blinklabs.io>
Date: Wed Nov 26 16:07:13 2025 -0500
fix(entrypoint): bash the user script
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
diff --git a/bin/entrypoint b/bin/entrypoint
new file mode 100644
index 0000000..a9773e3
--- /dev/null
+++ b/bin/entrypoint
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+CONFIG_DIR=/etc/openvpn
+
+USER_STARTUP_SCRIPT=${USER_STARTUP_SCRIPT:-/usr/local/bin/entrypoint-user.sh}
+
+ENABLE_NAT=${ENABLE_NAT:-1}
+NAT_SOURCE=${NAT_SOURCE:-10.8.0.0/24}
+NAT_DEVICE=${NAT_DEVICE:-eth0}
+
+DEBUG=${DEBUG:-0}
+
+# Create device for tun interfaces
+mkdir -p /dev/net
+if [ ! -c /dev/net/tun ]; then
+ mknod /dev/net/tun c 10 200
+fi
+
+if [[ $ENABLE_NAT = 1 ]]; then
+ iptables -t nat -A POSTROUTING -s ${NAT_SOURCE} -o ${NAT_DEVICE} -j MASQUERADE
+ # Basic kill switch: Drop forwarded traffic by default, allow only VPN-related
+ iptables -P FORWARD DROP
+ iptables -A FORWARD -i tun+ -o ${NAT_DEVICE} -j ACCEPT
+ iptables -A FORWARD -i ${NAT_DEVICE} -o tun+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+fi
+
+# Execute user startup script if it exists
+if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
+ bash ${USER_STARTUP_SCRIPT}
+fi
+
+# Redirect output to /dev/null unless in debug mode
+if [[ $DEBUG = 0 ]]; then
+ exec &>/dev/null
+fi
+
+exec openvpn --config ${CONFIG_DIR}/openvpn.conf --cd ${CONFIG_DIR} $@
</shell_result>
Script executed:
#!/bin/bash
# Check if entrypoint exists in any previous commits
echo "=== Check if bin/entrypoint exists in parent commits ==="
git log --all --full-history -- bin/entrypoint | grep -c "commit" || echo "Only 1 commit (this is the first)"
echo -e "\n=== Show parent commit ==="
git log --oneline -5
echo -e "\n=== Verify this is the initial commit for this file ==="
git log --follow --all -- bin/entrypoint | tail -20Repository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Check if bin/entrypoint exists in parent commits ===
6
=== Show parent commit ===
6fcc967 fix(entrypoint): bash the user script
=== Verify this is the initial commit for this file ===
feat: run optional user startup script (#3)
Signed-off-by: Aurora Gaffney <aurora@blinklabs.io>
commit 579e0f7554398789439380b8c5d1cb26356ce05e
Author: Aurora Gaffney <aurora@blinklabs.io>
Date: Sat May 10 08:45:38 2025 -0400
feat: support for configuring iptables masquerading for NAT (#2)
Signed-off-by: Aurora Gaffney <aurora@blinklabs.io>
commit 363b9ca7d2882ee55ac26927c6e405b1423d0f6b
Author: Aurora Gaffney <aurora@blinklabs.io>
Date: Fri May 2 14:17:56 2025 -0400
feat: initial image (#1)
Signed-off-by: Aurora Gaffney <aurora@blinklabs.io>
</shell_result>
Script executed:
#!/bin/bash
# Get the previous version before the bash change
echo "=== Show previous version of bin/entrypoint ==="
git show 6fcc967^:bin/entrypoint 2>/dev/null || echo "Could not get previous version"
echo -e "\n=== Show diff between previous and current ==="
git diff 6fcc967^ 6fcc967 -- bin/entrypointRepository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 128
stdout:
=== Show previous version of bin/entrypoint ===
Could not get previous version
=== Show diff between previous and current ===
stderr:
fatal: bad revision '6fcc967^'
</shell_result>
Script executed:
#!/bin/bash
# Check full history of changes to bin/entrypoint
echo "=== Full git log with patches for bin/entrypoint ==="
git log -p --all -- bin/entrypoint | head -200
echo -e "\n=== Check origin/main to see full history ==="
git log --oneline origin/main -- bin/entrypoint 2>/dev/null | head -10Repository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Full git log with patches for bin/entrypoint ===
=== Check origin/main to see full history ===
b9144cb fix: enhance OpenVPN image security and privacy (#16)
8e4b3c1 feat: hide logs by default (#4)
533bc7c feat: run optional user startup script (#3)
579e0f7 feat: support for configuring iptables masquerading for NAT (#2)
363b9ca feat: initial image (#1)
</shell_result>
Script executed:
#!/bin/bash
# Get the version from origin/main (before this PR)
echo "=== Version from origin/main HEAD ==="
git show origin/main:bin/entrypoint 2>/dev/null | cat -n
echo -e "\n=== Compare: lines 27-30 from origin/main ==="
git show origin/main:bin/entrypoint 2>/dev/null | sed -n '27,30p'
echo -e "\n=== Compare: current version lines 27-30 ==="
sed -n '27,30p' bin/entrypointRepository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Version from origin/main HEAD ===
1 #!/bin/bash
2
3 CONFIG_DIR=/etc/openvpn
4
5 USER_STARTUP_SCRIPT=${USER_STARTUP_SCRIPT:-/usr/local/bin/entrypoint-user.sh}
6
7 ENABLE_NAT=${ENABLE_NAT:-1}
8 NAT_SOURCE=${NAT_SOURCE:-10.8.0.0/24}
9 NAT_DEVICE=${NAT_DEVICE:-eth0}
10
11 DEBUG=${DEBUG:-0}
12
13 # Create device for tun interfaces
14 mkdir -p /dev/net
15 if [ ! -c /dev/net/tun ]; then
16 mknod /dev/net/tun c 10 200
17 fi
18
19 if [[ $ENABLE_NAT = 1 ]]; then
20 iptables -t nat -A POSTROUTING -s ${NAT_SOURCE} -o ${NAT_DEVICE} -j MASQUERADE
21 # Basic kill switch: Drop forwarded traffic by default, allow only VPN-related
22 iptables -P FORWARD DROP
23 iptables -A FORWARD -i tun+ -o ${NAT_DEVICE} -j ACCEPT
24 iptables -A FORWARD -i ${NAT_DEVICE} -o tun+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
25 fi
26
27 # Execute user startup script if it exists
28 if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
29 chmod a+x ${USER_STARTUP_SCRIPT}
30 ${USER_STARTUP_SCRIPT}
31 fi
32
33 # Redirect output to /dev/null unless in debug mode
34 if [[ $DEBUG = 0 ]]; then
35 exec &>/dev/null
36 fi
37
38 exec openvpn --config ${CONFIG_DIR}/openvpn.conf --cd ${CONFIG_DIR} $@
=== Compare: lines 27-30 from origin/main ===
# Execute user startup script if it exists
if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
chmod a+x ${USER_STARTUP_SCRIPT}
${USER_STARTUP_SCRIPT}
=== Compare: current version lines 27-30 ===
# Execute user startup script if it exists
if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
bash ${USER_STARTUP_SCRIPT}
fi
</shell_result>
Script executed:
#!/bin/bash
# Check the PR/commit message more closely and look for related issues
echo "=== Full commit message ==="
git show 6fcc967
echo -e "\n=== Check if there are any related PRs or issues mentioned ==="
git log --all --grep="entrypoint\|startup" --oneline 2>/dev/null | head -20Repository: blinklabs-io/docker-openvpn
<shell_result>
Repository: blinklabs-io/docker-openvpn
Exit code: 0
stdout:
=== Full commit message ===
commit 6fcc967b511b2ae36d609814261776f0c6b4f4b9
Author: Chris Gianelloni <wolf31o2@blinklabs.io>
Date: Wed Nov 26 16:07:13 2025 -0500
fix(entrypoint): bash the user script
Signed-off-by: Chris Gianelloni <wolf31o2@blinklabs.io>
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..300b511
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,5 @@
+# Blink Labs
+#
+* @blinklabs-io/core @blinklabs-io/ops
+*.md @blinklabs-io/core @blinklabs-io/docs @blinklabs-io/pms
+LICENSE @blinklabs-io/core @blinklabs-io/pms
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..4fcaebb
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,15 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "docker"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/ci-docker.yml b/.github/workflows/ci-docker.yml
new file mode 100644
index 0000000..cc312fc
--- /dev/null
+++ b/.github/workflows/ci-docker.yml
@@ -0,0 +1,34 @@
+name: Docker CI
+
+on:
+ pull_request:
+ branches: ['main']
+ paths: ['Dockerfile','.github/workflows/ci-docker.yml']
+
+env:
+ REGISTRY: ghcr.io
+ IMAGE_NAME: blinklabs-io/openvpn
+
+permissions:
+ contents: read
+
+jobs:
+ docker:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 https://github.com/actions/checkout/releases/tag/v6.0.0
+ - name: qemu
+ uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 https://github.com/docker/setup-qemu-action/releases/tag/v3.7.0
+ - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 https://github.com/docker/setup-buildx-action/releases/tag/v3.11.1
+ - id: meta
+ uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 https://github.com/docker/metadata-action/releases/tag/v5.9.0
+ with:
+ images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
+ - name: build
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 https://github.com/docker/build-push-action/releases/tag/v6.18.0
+ with:
+ context: .
+ push: false
+ platforms: linux/amd64,linux/arm64
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
diff --git a/.github/workflows/conventional-commits.yml b/.github/workflows/conventional-commits.yml
new file mode 100644
index 0000000..829821f
--- /dev/null
+++ b/.github/workflows/conventional-commits.yml
@@ -0,0 +1,17 @@
+# The below is pulled from upstream and slightly modified
+# https://github.com/webiny/action-conventional-commits/blob/master/README.md#usage
+
+name: Conventional Commits
+
+on:
+ pull_request:
+
+jobs:
+ build:
+ name: Conventional Commits
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 https://github.com/actions/checkout/releases/tag/v6.0.0
+ - uses: webiny/action-conventional-commits@8bc41ff4e7d423d56fa4905f6ff79209a78776c7 # v1.3.0 https://github.com/webiny/action-conventional-commits/releases/tag/v1.3.0
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 0000000..093bb14
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,108 @@
+name: publish
+
+on:
+ push:
+ branches: ['main']
+ tags:
+ - 'v*.*.*'
+ schedule:
+ # Weekly on Mondays at 00:00 UTC
+ - cron: '0 0 * * 1'
+
+concurrency: ${{ github.ref }}
+
+jobs:
+ build-and-push-image:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+ security-events: write
+ steps:
+ - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 https://github.com/actions/checkout/releases/tag/v6.0.0
+ - name: qemu
+ uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 https://github.com/docker/setup-qemu-action/releases/tag/v3.7.0
+ - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 https://github.com/docker/setup-buildx-action/releases/tag/v3.11.1
+ - name: Login to Docker Hub
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 https://github.com/docker/login-action/releases/tag/v3.6.0
+ with:
+ username: blinklabs
+ password: ${{ secrets.DOCKER_PASSWORD }} # uses token
+ - name: Login to GHCR
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 https://github.com/docker/login-action/releases/tag/v3.6.0
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+ - id: meta
+ uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0 https://github.com/docker/metadata-action/releases/tag/v5.9.0
+ with:
+ images: |
+ blinklabs/openvpn
+ ghcr.io/blinklabs-io/openvpn
+ tags: |
+ # version
+ type=match,pattern=v(.*),group=1
+ # branch
+ type=ref,event=branch
+ - name: Extract first tag
+ run: |
+ FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -n1 | rev | cut -d: -f1 | rev)
+ echo "FIRST_TAG=$FIRST_TAG" >> $GITHUB_ENV
+ - name: push
+ uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 https://github.com/docker/build-push-action/releases/tag/v6.18.0
+ with:
+ context: .
+ push: true
+ platforms: linux/amd64,linux/arm64
+ tags: ${{ steps.meta.outputs.tags }}
+ labels: ${{ steps.meta.outputs.labels }}
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # v0.33.1
+ with:
+ scan-type: 'image'
+ scan-ref: 'ghcr.io/blinklabs-io/openvpn:${{ env.FIRST_TAG }}'
+ format: 'sarif'
+ output: 'trivy-results-${{ env.FIRST_TAG }}.sarif'
+ ignore-unfixed: true
+ severity: 'HIGH,CRITICAL'
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5
+ if: always()
+ with:
+ sarif_file: 'trivy-results-${{ env.FIRST_TAG }}.sarif'
+ # Update Docker Hub from README
+ - name: Docker Hub Description
+ uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0 https://github.com/peter-evans/dockerhub-description/releases/tag/v5.0.0
+ with:
+ username: blinklabs
+ password: ${{ secrets.DOCKER_PASSWORD }}
+ repository: blinklabs/openvpn
+ readme-filepath: ./README.md
+ short-description: "Simple OpenVPN image"
+
+ github-release:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ needs: [build-and-push-image]
+ steps:
+ - run: "echo \"RELEASE_TAG=${GITHUB_REF#refs/tags/}\" >> $GITHUB_ENV"
+ - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 https://github.com/actions/github-script/releases/tag/v8.0.0
+ if: startsWith(github.ref, 'refs/tags/')
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ try {
+ await github.rest.repos.createRelease({
+ draft: false,
+ generate_release_notes: true,
+ name: process.env.RELEASE_TAG,
+ owner: context.repo.owner,
+ prerelease: false,
+ repo: context.repo.repo,
+ tag_name: process.env.RELEASE_TAG,
+ });
+ } catch (error) {
+ core.setFailed(error.message);
+ }
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..e117be9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,19 @@
+FROM debian:bookworm-slim AS base
+
+COPY bin/ /usr/local/bin
+
+RUN apt-get update \
+ && apt-get dist-upgrade -y \
+# Install OpenVPN (latest 2.6.x from Debian repos; rebuild image periodically for security updates)
+ && apt-get install -y --no-install-recommends openvpn iptables \
+ && apt-get purge -y --auto-remove cron rsyslog \
+ && rm -rf /var/log/* \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/* \
+ && chmod +x /usr/local/bin/*
+
+HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 CMD pgrep -f openvpn || exit 1
+
+EXPOSE 1194/udp
+
+ENTRYPOINT ["/usr/local/bin/entrypoint"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..9b37ae8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Blink Labs Software
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..adce85c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,52 @@
+# docker-openvpn
+
+Simple OpenVPN image with updated version, optimized for privacy-focused VPN services.
+
+## Using the image
+
+There is no default config provided by the image, so you'll need to provide your own.
+
+```
+docker run -d -n openvpn -v /path/to/openvpn.conf:/etc/openvpn/openvpn.conf ghcr.io/blinklabs-io/openvpn --config /etc/openvpn/openvpn.conf
+```
+
+The image provides for the ability to provide a custom startup script. It looks for a user script at `/usr/local/bin/entrypoint-user.sh` by default,
+but the location can be overridden with the `USER_STARTUP_SCRIPT` environment variable
+
+## Privacy and Security Recommendations
+
+For a no-log, privacy-focused setup:
+
+### OpenVPN Configuration
+Use these options in your `openvpn.conf` for strong encryption and no logging:
+```conf
+# Disable logging
+log /dev/null
+verb 0
+
+# Strong ciphers
+cipher AES-256-GCM
+auth SHA256
+tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
+tls-version-min 1.2
+
+# Privilege drop
+user nobody
+group nogroup
+
+# Other privacy settings
+persist-key
+persist-tun
+```
+
+### Docker Run Options
+- Use Docker secrets for certificates/keys: `--secret mykey=/path/to/key`
+- Run with necessary capabilities only: `--cap-add=NET_ADMIN` (avoid `--privileged`)
+- For Kubernetes (Helm), use `securityContext` to limit privileges.
+
+### Maintenance
+- Rebuild images regularly to pull security updates from Debian repos.
+- Scan for vulnerabilities with tools like Trivy (automated via GitHub Actions).
+- Test for leaks using services like ipleak.net while connected.
+
+**Warning**: Running in privileged mode increases security risks—use only when necessary.
diff --git a/bin/entrypoint b/bin/entrypoint
new file mode 100644
index 0000000..a9773e3
--- /dev/null
+++ b/bin/entrypoint
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+CONFIG_DIR=/etc/openvpn
+
+USER_STARTUP_SCRIPT=${USER_STARTUP_SCRIPT:-/usr/local/bin/entrypoint-user.sh}
+
+ENABLE_NAT=${ENABLE_NAT:-1}
+NAT_SOURCE=${NAT_SOURCE:-10.8.0.0/24}
+NAT_DEVICE=${NAT_DEVICE:-eth0}
+
+DEBUG=${DEBUG:-0}
+
+# Create device for tun interfaces
+mkdir -p /dev/net
+if [ ! -c /dev/net/tun ]; then
+ mknod /dev/net/tun c 10 200
+fi
+
+if [[ $ENABLE_NAT = 1 ]]; then
+ iptables -t nat -A POSTROUTING -s ${NAT_SOURCE} -o ${NAT_DEVICE} -j MASQUERADE
+ # Basic kill switch: Drop forwarded traffic by default, allow only VPN-related
+ iptables -P FORWARD DROP
+ iptables -A FORWARD -i tun+ -o ${NAT_DEVICE} -j ACCEPT
+ iptables -A FORWARD -i ${NAT_DEVICE} -o tun+ -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
+fi
+
+# Execute user startup script if it exists
+if [[ -e ${USER_STARTUP_SCRIPT} ]]; then
+ bash ${USER_STARTUP_SCRIPT}
+fi
+
+# Redirect output to /dev/null unless in debug mode
+if [[ $DEBUG = 0 ]]; then
+ exec &>/dev/null
+fi
+
+exec openvpn --config ${CONFIG_DIR}/openvpn.conf --cd ${CONFIG_DIR} $@
=== Check if there are any related PRs or issues mentioned ===
6fcc967 fix(entrypoint): bash the user script
533bc7c feat: run optional user startup script (#3)
</shell_result>
Now I have complete visibility. Let me generate the final rewritten review comment based on verification:
Breaking change confirmed: Forcing bash now ignores script shebangs and removes permission handling.
The change from chmod a+x && ${USER_STARTUP_SCRIPT} to bash ${USER_STARTUP_SCRIPT} breaks existing deployments where the user startup script uses a non-bash interpreter (e.g., #!/bin/sh, #!/usr/bin/env python). Direct execution respects the shebang line; bash invocation ignores it and forces bash interpretation.
While this removes the chmod dependency (helpful in some containerized environments), it silently breaks non-bash scripts. Additionally, the commit message ("fix(entrypoint): bash the user script") suggests this was intentional, but:
- Documentation doesn't specify the bash requirement — README.md mentions the feature but doesn't state scripts must be bash-compatible.
- No error handling — User script failures are silently ignored; execution continues to openvpn regardless of success/failure.
Recommendations:
- Update README.md to clearly document that
USER_STARTUP_SCRIPTmust be bash-compatible or use bash syntax. - Add error handling to fail fast if the user script exits with an error:
bash ${USER_STARTUP_SCRIPT} || exit 1
- Consider if the original approach (direct execution with chmod) could be improved with fallback logic instead of forcing bash.
Summary by cubic
Run the user startup script with bash instead of executing it directly. This prevents failures when the script isn’t executable or lacks a shebang and ensures consistent shell behavior.
Written for commit 6fcc967. Summary will update automatically on new commits.
Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.