initial commit
This commit is contained in:
commit
f247a676fd
92
.github/workflows/docker-publish.yml
vendored
Normal file
92
.github/workflows/docker-publish.yml
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
name: Docker Build and Publish
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
# Publish semver tags as releases.
|
||||
tags: [ 'v*.*.*' ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
# Use github.repository as <account>/<repo>
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
REGISTRY: ghcr.io
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
# This is used to complete the identity challenge
|
||||
# with sigstore/fulcio when running outside of PRs.
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Install the cosign tool except on PR
|
||||
# https://github.com/sigstore/cosign-installer
|
||||
- name: Install cosign
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: sigstore/cosign-installer@v3.3.0
|
||||
with:
|
||||
cosign-release: 'v2.1.1'
|
||||
|
||||
# Set up BuildKit Docker container builder to enable modern features
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
# Login against a Docker registry
|
||||
# https://github.com/docker/login-action
|
||||
- name: Log into registry ${{ env.REGISTRY }}
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Extract metadata (tags, labels) for Docker
|
||||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
# Build and push Docker image with Buildx
|
||||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
|
||||
# Sign the resulting Docker image digest except on PRs.
|
||||
# This will only write to the public Rekor transparency log when the Docker
|
||||
# repository is public to avoid leaking data. If you would like to publish
|
||||
# transparency data even for private images, pass --force to cosign below.
|
||||
# https://github.com/sigstore/cosign
|
||||
- name: Sign the published Docker image
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
|
||||
TAGS: ${{ steps.meta.outputs.tags }}
|
||||
DIGEST: ${{ steps.build-and-push.outputs.digest }}
|
||||
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.idea
|
||||
.DS_Store
|
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@ -0,0 +1,15 @@
|
||||
FROM alpine:latest
|
||||
|
||||
LABEL maintainer="Menno van Leeuwen <menno@vleeuwen.me>"
|
||||
LABEL description="A flexible UPnP port forwarding container that handles automatic port mapping and renewal"
|
||||
LABEL repository="https://github.com/vleeuwenmenno/docker-auto-upnp"
|
||||
|
||||
RUN apk --no-cache add \
|
||||
bash \
|
||||
miniupnpc \
|
||||
jq
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Menno van Leeuwen
|
||||
|
||||
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.
|
68
README.md
Normal file
68
README.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Auto UPNP
|
||||
|
||||
A simple Docker container for automatic UPnP port forwarding. This container automatically forwards ports on your router with the use of upnpc.
|
||||
|
||||
## Features
|
||||
|
||||
- JSON-based port configuration
|
||||
- Automatic port mapping renewal
|
||||
- Configurable mapping duration
|
||||
- Built on Alpine Linux for minimal footprint
|
||||
|
||||
## Usage
|
||||
|
||||
### Quick Start
|
||||
|
||||
```yaml
|
||||
services:
|
||||
upnp:
|
||||
image: ghcr.io/vleeuwenmenno/auto-upnp:latest
|
||||
network_mode: host
|
||||
environment:
|
||||
- PORTS=[{"port": 80, "protocol": "tcp"}, {"port": 443, "protocol": "tcp"}]
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
- `PORTS`: JSON array of port mappings (required)
|
||||
- Format: `[{"port": number, "protocol": "tcp|udp"}, ...]`
|
||||
- `UPNP_DURATION`: Renewal interval for port mappings (default: `86400` seconds/24 hours)
|
||||
|
||||
### Example Configurations
|
||||
|
||||
#### Game Server (Satisfactory)
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
PORTS: |
|
||||
[
|
||||
{"port": 7777, "protocol": "udp"},
|
||||
{"port": 15000, "protocol": "udp"},
|
||||
{"port": 15777, "protocol": "udp"}
|
||||
]
|
||||
```
|
||||
|
||||
#### Web Server
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
PORTS: |
|
||||
[
|
||||
{"port": 80, "protocol": "tcp"},
|
||||
{"port": 443, "protocol": "tcp"}
|
||||
]
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
```bash
|
||||
docker build -t auto-upnp .
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a Pull Request.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
26
docker-compose.yml
Normal file
26
docker-compose.yml
Normal file
@ -0,0 +1,26 @@
|
||||
name: auto-upnp
|
||||
services:
|
||||
upnp:
|
||||
# image: ghcr.io/vleeuwenmenno/auto-upnp:latest
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
UPNP_DURATION: 86400 # 24 hours in seconds
|
||||
PORTS: |
|
||||
[
|
||||
{"port": 7777, "protocol": "udp"},
|
||||
{"port": 15000, "protocol": "udp"},
|
||||
{"port": 15777, "protocol": "udp"},
|
||||
{"port": 27015, "protocol": "tcp"},
|
||||
{"port": 27015, "protocol": "udp"},
|
||||
{"port": 27031, "protocol": "udp"},
|
||||
{"port": 27032, "protocol": "udp"},
|
||||
{"port": 27033, "protocol": "udp"},
|
||||
{"port": 27034, "protocol": "udp"},
|
||||
{"port": 27035, "protocol": "udp"},
|
||||
{"port": 27036, "protocol": "tcp"},
|
||||
{"port": 27036, "protocol": "udp"}
|
||||
]
|
79
entrypoint.sh
Normal file
79
entrypoint.sh
Normal file
@ -0,0 +1,79 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Default values
|
||||
DURATION=${UPNP_DURATION:-86400} # 24 hours in seconds
|
||||
REFRESH_INTERVAL=$((DURATION * 80 / 100)) # Refresh at 80% of duration
|
||||
DEFAULT_PORTS='[]' # Empty array as default
|
||||
|
||||
# Function to validate JSON array
|
||||
validate_ports() {
|
||||
if ! echo "$1" | jq empty; then
|
||||
echo "Error: PORTS environment variable must be a valid JSON array"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to add a single port mapping
|
||||
add_port_mapping() {
|
||||
local port=$1
|
||||
local protocol=$2
|
||||
|
||||
echo "Adding mapping for port $port/$protocol..."
|
||||
upnpc -a "" "$port" "$port" "$protocol" "$DURATION"
|
||||
local status=$?
|
||||
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "Successfully mapped port $port/$protocol"
|
||||
else
|
||||
echo "Failed to map port $port/$protocol"
|
||||
fi
|
||||
|
||||
return $status
|
||||
}
|
||||
|
||||
# Function to remove a single port mapping
|
||||
remove_port_mapping() {
|
||||
local port=$1
|
||||
local protocol=$2
|
||||
|
||||
echo "Removing mapping for port $port/$protocol..."
|
||||
upnpc -d "$port" "$protocol"
|
||||
}
|
||||
|
||||
# Function to add all port mappings
|
||||
add_port_mappings() {
|
||||
local ports_json=${PORTS:-$DEFAULT_PORTS}
|
||||
validate_ports "$ports_json"
|
||||
|
||||
echo "Adding/Refreshing port mappings..."
|
||||
|
||||
# Iterate through the JSON array
|
||||
echo "$ports_json" | jq -r '.[] | "\(.port) \(.protocol)"' | while read -r port protocol; do
|
||||
add_port_mapping "$port" "$protocol"
|
||||
done
|
||||
|
||||
# List current mappings
|
||||
echo "Current port mappings:"
|
||||
upnpc -l
|
||||
}
|
||||
|
||||
# Function to remove all port mappings
|
||||
remove_port_mappings() {
|
||||
local ports_json=${PORTS:-$DEFAULT_PORTS}
|
||||
|
||||
echo "Removing all port mappings..."
|
||||
|
||||
# Iterate through the JSON array
|
||||
echo "$ports_json" | jq -r '.[] | "\(.port) \(.protocol)"' | while read -r port protocol; do
|
||||
remove_port_mapping "$port" "$protocol"
|
||||
done
|
||||
}
|
||||
|
||||
# Trap SIGTERM and SIGINT
|
||||
trap "remove_port_mappings; exit 0" TERM INT
|
||||
|
||||
# Main loop
|
||||
while true; do
|
||||
add_port_mappings
|
||||
sleep "$REFRESH_INTERVAL"
|
||||
done
|
Loading…
x
Reference in New Issue
Block a user