Merge pull request #189 from junkurihara/pkg-readme

Feat: Jenkins CI/CD build scripts and Readme
This commit is contained in:
Jun Kurihara 2024-09-19 11:27:52 +09:00 committed by GitHub
commit b8deb8ae82
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 571 additions and 0 deletions

0
.build/.gitignore vendored Normal file
View file

10
.build/DEB/control Normal file
View file

@ -0,0 +1,10 @@
Package: rpxy
Version: @BUILD_VERSION@-1
Maintainer: Jun Kurihara <kurihara@ieee.org>
Homepage: https://github.com/junkurihara/rust-rpxy
Architecture: amd64
Depends: systemd
Recommends: rpxy-webui
Priority: optional
Section: base
Description: A simple and ultrafast reverse-proxy serving multiple domain names with TLS termination, written in Rust

35
.build/DEB/postinst Normal file
View file

@ -0,0 +1,35 @@
#!/bin/sh
set -e
# Source debconf library
. /usr/share/debconf/confmodule
# Create rpxy user if it doesn't exist
if ! getent passwd rpxy > /dev/null; then
adduser --system --group --no-create-home --shell /usr/sbin/nologin rpxy
fi
# Set correct ownership for config directory
if [ -d /etc/rpxy ]; then
chown -R rpxy:rpxy /etc/rpxy
fi
# Reload systemd, enable and start the service
if [ "$1" = "configure" ] || [ "$1" = "abort-upgrade" ] || [ "$1" = "abort-deconfigure" ] || [ "$1" = "abort-remove" ] ; then
deb-systemd-helper unmask rpxy.service >/dev/null || true
if deb-systemd-helper --quiet was-enabled rpxy.service; then
deb-systemd-helper enable rpxy.service >/dev/null || true
else
deb-systemd-helper update-state rpxy.service >/dev/null || true
fi
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
if [ -n "$2" ]; then
deb-systemd-invoke try-restart rpxy.service >/dev/null || true
else
deb-systemd-invoke start rpxy.service >/dev/null || true
fi
fi
fi
exit 0

22
.build/DEB/postrm Normal file
View file

@ -0,0 +1,22 @@
#!/bin/sh
set -e
if [ "$1" = "purge" ]; then
# Remove the rpxy user
if getent passwd rpxy >/dev/null; then
deluser --quiet --system rpxy >/dev/null || true
fi
# Remove config directory
rm -rf /etc/rpxy
# Remove systemd service state
deb-systemd-helper purge rpxy.service >/dev/null || true
deb-systemd-helper unmask rpxy.service >/dev/null || true
fi
if [ -d /run/systemd/system ]; then
systemctl --system daemon-reload >/dev/null || true
fi
exit 0

8
.build/DEB/prerm Normal file
View file

@ -0,0 +1,8 @@
#!/bin/sh
set -e
if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
deb-systemd-invoke stop rpxy.service >/dev/null || true
fi
exit 0

208
.build/Jenkinsfile vendored Normal file
View file

@ -0,0 +1,208 @@
pipeline {
agent none
environment {
// Define common variables used throughout the pipeline
REPO_URL = 'https://github.com/junkurihara/rust-rpxy.git'
BINARY_NAME = 'rpxy'
// BUILD_VERSION is not set because it will be extracted from Cargo.toml in the first step
// BUILD_VERSION = ''
}
stages {
stage('Prepare Build Environment') {
agent {
kubernetes {
inheritFrom 'default'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: rust-cargo
image: rust:slim
command:
- cat
tty: true
"""
}
}
steps {
container('rust-cargo') {
// Install git
sh 'apt-get update && apt-get -y install git --no-install-recommends'
// Clone and Prepare Repository
sh "git clone ${REPO_URL}"
dir('rust-rpxy') {
sh """
# Update submodule URLs to HTTPS (allows cloning without SSH keys)
sed -i 's|git@github.com:|https://github.com/|g' .gitmodules
# Initialize and update submodules
git submodule update --init
"""
// Extract BUILD_VERSION from Cargo.toml
script {
// Extract version from Cargo.toml and set it as an environment variable
def buildVersion = sh(script: 'grep "^version" Cargo.toml | sed \'s/version = "\\([0-9.]*\\)"/\\1/\'', returnStdout: true).trim()
if (buildVersion) {
env.BUILD_VERSION = buildVersion
echo "Using extracted version: ${env.BUILD_VERSION}"
} else {
error "Version not found in Cargo.toml"
}
}
// Build the binary
sh 'cargo build --release'
// Prepare and stash files
sh """
# Move binary to workspace root for easier access
mv target/release/${BINARY_NAME} ..
# Move necessary files for packaging
mv .build/DEB/* ..
mv .build/RPM/* ..
mv .build/rpxy* ..
mv .build/config.toml ..
mv README.md ..
mv LICENSE ..
"""
}
// Stash files for use in later stages
stash includes: "${BINARY_NAME}", name: "binary"
stash includes: "control, postinst, prerm, postrm, rpxy-start.sh", name: "deb-files"
stash includes: "${BINARY_NAME}.spec", name: "rpm-files"
stash includes: "rpxy.service, config.toml", name: "service-file"
stash includes: "LICENSE, README.md", name: "docs"
// Archive the binary as an artifact
archiveArtifacts artifacts: "${BINARY_NAME}", allowEmptyArchive: false, fingerprint: true
}
}
}
stage('Build RPM Package') {
agent {
kubernetes {
inheritFrom 'default'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: rpm-build
image: rockylinux:9
command:
- cat
tty: true
"""
}
}
steps {
container('rpm-build') {
// Prepare the RPM build environment
unstash 'binary'
unstash 'rpm-files'
unstash 'service-file'
unstash 'docs'
// Install necessary tools for RPM building
sh 'dnf update -y && dnf install -y rpmdevtools tar'
// Create the RPM package
sh """
# Create RPM build directory structure
mkdir -p rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
mkdir -p ${BINARY_NAME}-${BUILD_VERSION}
# Move files to the appropriate locations
mv ${BINARY_NAME} ${BINARY_NAME}.service LICENSE README.md config.toml ${BINARY_NAME}-${BUILD_VERSION}/
tar -czf rpmbuild/SOURCES/${BINARY_NAME}-${BUILD_VERSION}.tar.gz ${BINARY_NAME}-${BUILD_VERSION}/
mv ${BINARY_NAME}.spec rpmbuild/SPECS/
# Update spec file with correct version and source
sed -i 's/@BUILD_VERSION@/${BUILD_VERSION}/; s/@Source0@/${BINARY_NAME}-${BUILD_VERSION}.tar.gz/' rpmbuild/SPECS/${BINARY_NAME}.spec
# Build the RPM package
rpmbuild --define "_topdir ${WORKSPACE}/rpmbuild" --define "_version ${BUILD_VERSION}" -bb rpmbuild/SPECS/${BINARY_NAME}.spec
# Move RPM to root for archiving
mv rpmbuild/RPMS/x86_64/${BINARY_NAME}-${BUILD_VERSION}-1.el9.x86_64.rpm .
"""
// Archive the RPM package
archiveArtifacts artifacts: "${BINARY_NAME}-${BUILD_VERSION}-1.el9.x86_64.rpm", allowEmptyArchive: false, fingerprint: true
}
}
}
stage('Build DEB Package') {
agent {
kubernetes {
inheritFrom 'default'
yaml """
apiVersion: v1
kind: Pod
spec:
containers:
- name: debian-build
image: debian:stable-slim
command:
- cat
tty: true
"""
}
}
steps {
container('debian-build') {
// Prepare the DEB build environment
unstash 'binary'
unstash 'deb-files'
unstash 'service-file'
unstash 'docs'
// Install necessary tools for DEB building
sh 'apt-get update && apt-get install -y dpkg-dev --no-install-recommends'
// Create the DEB package
sh """
# Define DEB package directory
DEB_DIR=${BINARY_NAME}_${BUILD_VERSION}-1_amd64
# Create directory structure for DEB package
bash -c \"mkdir -p \$DEB_DIR/{DEBIAN,usr/{bin,local/bin,share/doc/${BINARY_NAME}},etc/{systemd/system,${BINARY_NAME}/acme_registry}}\"
# Move files to appropriate locations
mv postinst prerm postrm \$DEB_DIR/DEBIAN/
chmod 755 \$DEB_DIR/DEBIAN/postinst
chmod 755 \$DEB_DIR/DEBIAN/prerm
chmod 755 \$DEB_DIR/DEBIAN/postrm
mv rpxy-start.sh \$DEB_DIR/usr/local/bin/
chmod 0755 \$DEB_DIR/usr/local/bin/rpxy-start.sh
mv ${BINARY_NAME} \$DEB_DIR/usr/bin/
mv rpxy.service \$DEB_DIR/etc/systemd/system/
mv LICENSE README.md \$DEB_DIR/usr/share/doc/${BINARY_NAME}/
mv config.toml \$DEB_DIR/etc/${BINARY_NAME}/
mv control \$DEB_DIR/DEBIAN/
# Update control file with correct version
sed -i 's/@BUILD_VERSION@/${BUILD_VERSION}/' \$DEB_DIR/DEBIAN/control
# Build the DEB package
dpkg-deb --build --root-owner-group \$DEB_DIR
"""
// Archive the DEB package
archiveArtifacts artifacts: "${BINARY_NAME}_${BUILD_VERSION}-1_amd64.deb", allowEmptyArchive: false, fingerprint: true
}
}
}
}
}

78
.build/RPM/rpxy.spec Normal file
View file

@ -0,0 +1,78 @@
Name: rpxy
Version: @BUILD_VERSION@
Release: 1%{?dist}
Summary: A simple and ultrafast reverse-proxy serving multiple domain names with TLS termination, written in Rust
License: MIT
URL: https://github.com/junkurihara/rust-rpxy
Source0: @Source0@
BuildArch: x86_64
Requires: systemd
%description
This rpm installs rpxy into /usr/bin and sets up a systemd service.
# Prep section: Unpack the source
%prep
%autosetup
# Install section: Copy files to their destinations
%install
rm -rf %{buildroot}
# Create necessary directories
mkdir -p %{buildroot}%{_bindir}
mkdir -p %{buildroot}%{_sysconfdir}/systemd/system
mkdir -p %{buildroot}%{_sysconfdir}/rpxy/acme_registry
mkdir -p %{buildroot}%{_docdir}/rpxy
# Copy files
cp rpxy %{buildroot}%{_bindir}/
cp rpxy.service %{buildroot}%{_sysconfdir}/systemd/system/
cp config.toml %{buildroot}%{_sysconfdir}/rpxy/
cp LICENSE README.md %{buildroot}%{_docdir}/rpxy/
# Clean section: Remove buildroot
%clean
rm -rf %{buildroot}
# Pre-install script
%pre
# Create the rpxy user if it does not exist
if ! getent passwd rpxy >/dev/null; then
useradd -r -s /sbin/nologin -d / -c "rpxy system user" rpxy
fi
# Post-install script
%post
# Set ownership of config file to rpxy user
chown -R rpxy:rpxy %{_sysconfdir}/rpxy
# Reload systemd, enable and start rpxy service
%systemd_post rpxy.service
# Pre-uninstall script
%preun
%systemd_preun rpxy.service
# Post-uninstall script
%postun
%systemd_postun_with_restart rpxy.service
# Only remove user and config on full uninstall
if [ $1 -eq 0 ]; then
# Remove rpxy user
userdel rpxy
# Remove the configuration directory if it exists
[ -d %{_sysconfdir}/rpxy ] && rm -rf %{_sysconfdir}/rpxy
fi
# Files section: List all files included in the package
%files
%license %{_docdir}/rpxy/LICENSE
%doc %{_docdir}/rpxy/README.md
%{_sysconfdir}/systemd/system/rpxy.service
%attr(755, rpxy, rpxy) %{_bindir}/rpxy
%attr(644, rpxy, rpxy) %config(noreplace) %{_sysconfdir}/rpxy/config.toml

94
.build/config.toml Normal file
View file

@ -0,0 +1,94 @@
########################################
# #
# rust-rxpy configuration #
# #
########################################
###################################
# Global settings #
###################################
# Both or either one of http/https ports must be specified
listen_port = 80
listen_port_tls = 443
# Optional: If your https is listening on a custom port like 8443
# When you specify this, the server sends a redirection response 301 with specified port to the client for plaintext http request.
# Otherwise, the server sends 301 with the same port as `listen_port_tls`.
# disabled means http -> https and enabled means http -> https:<port>
# https_redirection_port = 443
# Optional for h2 and http1.1
tcp_listen_backlog = 1024
# Optional for h2 and http1.1
max_concurrent_streams = 100
# Optional. Counted in total for http1.1, 2, 3
max_clients = 512
# Optional: Listen [::]
listen_ipv6 = false
# Optional: App that serves all plaintext http request by referring to HOSTS or request header
# execpt for configured application.
# Note that this is only for http.
# Note that nothing is served for requests via https since secure channel cannot be
# established for unconfigured server_name, and they are always rejected by checking SNI.
# default_app = 'another_localhost'
###################################
# Backend settings #
###################################
[apps]
######################################################################
## Registering a backend app served by a domain name "localhost"
[apps.localhost]
server_name = 'localhost' # Domain name
reverse_proxy = [{ upstream = [{ location = 'localhost:8080' }] }]
# Optional: TLS setting. if https_port is specified and tls is true above, either of this must be given.
#tls = { https_redirection = true, tls_cert_path = '/certs/server.crt', tls_cert_key_path = '/certs/server.key' }
#tls = { https_redirection = true, acme = true }
############################################
# For more settings check: #
# https://github.com/junkurihara/rust-rpxy #
############################################
###################################
# Experimantal settings #
###################################
[experimental]
# Higly recommend not to be true. If true, you ignore RFC. if not specified, it is always false.
# This might be required to be true when a certificate is used by multiple backend hosts, especially in case where a TLS connection is re-used.
# We should note that this strongly depends on the client implementation.
ignore_sni_consistency = false
# Force connection handling timeout regardless of the connection status, i.e., idle or not.
# 0 represents an infinite timeout. [default: 0]
# Note that idel and header read timeouts are always specified independently of this.
connection_handling_timeout = 0 # sec
# If this specified, h3 is enabled
[experimental.h3]
alt_svc_max_age = 3600 # sec
request_max_body_size = 65536 # bytes
max_concurrent_connections = 10000
max_concurrent_bidistream = 100
max_concurrent_unistream = 100
max_idle_timeout = 10 # secs. 0 represents an infinite timeout.
# WARNING: If a peer or its network path malfunctions or acts maliciously, an infinite idle timeout can result in permanently hung futures!
# If this specified, file cache feature is enabled
[experimental.cache]
cache_dir = '/tmp/rpxy/.cache' # optional. default is "./cache" relative to the current working directory
max_cache_entry = 1000 # optional. default is 1k
max_cache_each_size = 65535 # optional. default is 64k
max_cache_each_size_on_memory = 4096 # optional. default is 4k if 0, it is always file cache.
# ACME settings. Unless specified, ACME is disabled.
[experimental.acme]
dir_url = "https://acme-v02.api.letsencrypt.org/directory"
email = "test@example.com"
registry_path = "/etc/rpxy/acme_registry"

85
.build/rpxy-start.sh Normal file
View file

@ -0,0 +1,85 @@
#!/bin/sh
set -e
CACHE_DIR="/tmp/rpxy/.cache"
CONFIG_DIR="/etc/rpxy"
CONFIG_FILE="$CONFIG_DIR/config.toml"
WEBUI_CONFIG="/var/www/rpxy-webui/storage/app/config.toml"
COMMENT_MARKER="# IMPORTANT: DEACTIVATED This config is deactivated because rpxy-webui is installed"
setup_directories() {
# Check if systemd is available
if [ -d /run/systemd/system ]; then
# Use systemd RuntimeDirectory if available
if [ -d /run/rpxy ]; then
RUNTIME_DIR="/run/rpxy"
# If not available use PrivateTmp
elif [ -d /tmp/systemd-private-*/tmp ]; then
RUNTIME_DIR=$(find /tmp/systemd-private-*/tmp -type d -name "rpxy" 2>/dev/null | head -n 1)
fi
# Create subdirectory for cache
CACHE_DIR="$RUNTIME_DIR/.cache"
# Ensure the cache directory exists as it could get deleted on system restart
mkdir -p "$CACHE_DIR"
chown rpxy:rpxy "$CACHE_DIR" # not recursively because parent folder is managed by systemd
chmod 700 "$CACHE_DIR"
else
# Fallback to linux tmp directory if no systemd is found
RUNTIME_DIR="/tmp/rpxy"
CACHE_DIR="$RUNTIME_DIR/.cache"
# Ensure the cache directory exists as it could get deleted on system restart
mkdir -p "$CACHE_DIR"
chown -R rpxy:rpxy "$RUNTIME_DIR"
chmod 700 "$CACHE_DIR"
fi
echo "Using runtime directory: $RUNTIME_DIR"
echo "Using cache directory: $CACHE_DIR"
}
# Check if rpxy-webui is installed
is_package_installed() {
if command -v rpm >/dev/null 2>&1; then
rpm -q "$1" >/dev/null 2>&1
elif command -v dpkg-query >/dev/null 2>&1; then
dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q "install ok installed"
else
echo "Neither rpm nor dpkg-query found. Cannot verify installation status of rpxy-webui package." >&2
return 1
fi
}
# Create the config file if it doesn't exist
ensure_config_exists() {
mkdir -p "$CONFIG_DIR"
[ -f "$CONFIG_FILE" ] || echo "# Standard rpxy Konfigurationsdatei" > "$CONFIG_FILE"
}
add_comment_to_config() {
if ! grep -q "^$COMMENT_MARKER" "$CONFIG_FILE"; then
sed -i "1i$COMMENT_MARKER\n" "$CONFIG_FILE"
fi
}
remove_comment_from_config() {
sed -i "/^$COMMENT_MARKER/d" "$CONFIG_FILE"
}
main() {
setup_directories
ensure_config_exists
if is_package_installed rpxy-webui; then
echo "rpxy-webui is installed. Starting rpxy with rpxy-webui"
add_comment_to_config
exec /usr/bin/rpxy -w -c "$WEBUI_CONFIG"
else
echo "rpxy-webui is not installed. Starting with default config"
remove_comment_from_config
exec /usr/bin/rpxy -c "$CONFIG_FILE"
fi
}
main "$@"

23
.build/rpxy.service Normal file
View file

@ -0,0 +1,23 @@
[Unit]
Description=rpxy system service
Documentation=https://github.com/junkurihara/rust-rpxy
After=network.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/local/bin/rpxy-start.sh
Restart=on-failure
RestartSec=5
User=rpxy
Group=rpxy
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
RuntimeDirectory=rpxy
RuntimeDirectoryMode=0750
[Install]
WantedBy=multi-user.target

View file

@ -24,6 +24,8 @@ By default, `rpxy` provides the *TLS connection sanitization* by correctly bindi
## Installing/Building an Executable Binary of `rpxy`
### Building from Source
You can build an executable binary yourself by checking out this Git repository.
```bash
@ -45,6 +47,12 @@ Then you have an executive binary `rust-rpxy/target/release/rpxy`.
Note that we do not have an option of installation via [`crates.io`](https://crates.io/), i.e., `cargo install`, at this point since some dependencies are not published yet. Alternatively, you can use docker image (see below) as the easiest way for `amd64` environment.
### Package Installation for Linux (RPM/DEB)
You can found the Jenkins CI/CD build scripts for `rpxy` in the [./build](./build) directory.
Prebuilt packages for Linux RPM and DEB are available at [https://rpxy.gamerboy59.dev](https://rpxy.gamerboy59.dev), provided by [@Gamerboy59](https://github.com/Gamerboy59).
## Usage
`rpxy` always refers to a configuration file in TOML format, e.g., `config.toml`. You can find an example of the configuration file, `config-example.toml`, in this repository.