Compare commits

...
10 Commits
Author SHA1 Message Date
xixu-me 36881a4099 fix(actions): avoid status event fan-out 2026-08-18 11:29:42 +08:00
xixu-me 4e36f1c3d7 fix(actions): retry Dependabot merge after checks 2026-08-18 11:25:30 +08:00
xixu-me 6cd49f4aac fix(ci): evaluate all Dependabot pull requests 2026-08-14 18:15:04 +08:00
xixu-me 038c22bdd2 ci: trigger Dependabot auto-merge from workflow runs 2026-07-03 23:34:38 +08:00
xixu-me 07eff4199c ci: tolerate protected Dependabot workflow updates 2026-07-03 23:14:50 +08:00
xixu-me 967e22081f ci: add Dependabot auto merge workflow 2026-07-03 23:04:07 +08:00
xixu-me b40e11bd50 Refactor setup.sh and add config templates
Refactored setup.sh for modularity, maintainability, and improved logging. Moved Nginx and Xray configuration to template files under src/config, and added a parameterized HTML portfolio template under src/www. This change enables easier customization and automation of the setup process.
2025-12-13 18:47:02 +08:00
xixu-me 0fc6281c03 Update OS requirements in README
Changed the requirements section to specify support for both Debian and Ubuntu 64-bit systems instead of only Debian 10+.
2025-11-16 14:52:29 +08:00
xixu-me 71813aacc5 Update README for clarity and terminology
Revised references to 'Nginx' and 'X' to 'nginx' and 'X proxy' for consistency and clarity. Improved descriptions and instructions to better reflect the setup process.
2025-11-15 15:15:07 +08:00
xixu-me a297d6a27b Fix copyright notice formatting in README.md 2025-10-12 18:02:01 +08:00
7 changed files with 735 additions and 435 deletions

No files matched your search

+200
View File
@@ -0,0 +1,200 @@
name: Dependabot Auto Merge
on:
check_suite:
types: [completed]
workflow_run:
workflows:
- "CodeQL"
types:
- completed
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
cancel-in-progress: false
permissions:
contents: write
pull-requests: write
checks: read
statuses: read
jobs:
merge:
name: Auto-merge Dependabot PRs
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Merge Dependabot PRs when checks pass
uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const successfulCheckConclusions = new Set(["success", "skipped", "neutral"]);
const successfulStatusStates = new Set(["success"]);
const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const latestBy = (items, keyOf, timeOf) => {
const latest = new Map();
for (const item of items) {
const key = keyOf(item);
const itemTime = new Date(timeOf(item) || 0).getTime();
const existing = latest.get(key);
const existingTime = existing ? new Date(timeOf(existing) || 0).getTime() : -1;
if (!existing || itemTime >= existingTime) {
latest.set(key, item);
}
}
return [...latest.values()];
};
const findCandidatePulls = async () => {
const pulls = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: "open",
per_page: 100,
});
return pulls.filter((pr) => pr.user?.login === "dependabot[bot]");
};
const getMergeablePullRequest = async (pull_number) => {
for (let attempt = 1; attempt <= 6; attempt += 1) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
if (pr.mergeable !== null) {
return pr;
}
core.info("PR #" + pull_number + " mergeability is still being computed; retry " + attempt + "/6.");
await wait(5000);
}
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number });
return pr;
};
const getSignalState = async (sha) => {
const checkRuns = await github.paginate(github.rest.checks.listForRef, {
owner,
repo,
ref: sha,
per_page: 100,
});
const statuses = await github.paginate(github.rest.repos.listCommitStatusesForRef, {
owner,
repo,
ref: sha,
per_page: 100,
});
const latestChecks = latestBy(
checkRuns.filter((run) => run.name !== "Dependabot Auto Merge"),
(run) => (run.app?.slug || "unknown") + ":" + run.name,
(run) => run.completed_at || run.started_at || run.created_at,
);
const latestStatuses = latestBy(statuses, (status) => status.context, (status) => status.updated_at || status.created_at);
const pendingChecks = latestChecks.filter((run) => run.status !== "completed");
const failedChecks = latestChecks.filter(
(run) => run.status === "completed" && !successfulCheckConclusions.has(String(run.conclusion || "").toLowerCase()),
);
const failedStatuses = latestStatuses.filter((status) => !successfulStatusStates.has(String(status.state || "").toLowerCase()));
return {
totalSignals: latestChecks.length + latestStatuses.length,
pendingChecks,
failedChecks,
failedStatuses,
};
};
const { data: repository } = await github.rest.repos.get({ owner, repo });
const mergeMethods = [];
if (repository.allow_merge_commit) mergeMethods.push("merge");
if (repository.allow_squash_merge) mergeMethods.push("squash");
if (repository.allow_rebase_merge) mergeMethods.push("rebase");
if (mergeMethods.length === 0) {
core.info("This repository has no enabled pull request merge methods.");
return;
}
const pulls = await findCandidatePulls();
if (pulls.length === 0) {
core.info("No open Dependabot PRs to evaluate.");
return;
}
for (const candidate of pulls) {
const pull_number = candidate.number;
const pr = await getMergeablePullRequest(pull_number);
if (pr.user?.login !== "dependabot[bot]") {
core.info("PR #" + pull_number + " is no longer a Dependabot PR.");
continue;
}
if (pr.state !== "open" || pr.draft) {
core.info("PR #" + pull_number + " is not an open, ready PR.");
continue;
}
if (pr.mergeable !== true) {
core.info("PR #" + pull_number + " is not currently mergeable.");
continue;
}
const signalState = await getSignalState(pr.head.sha);
if (signalState.totalSignals === 0) {
core.info("PR #" + pull_number + " has no checks or statuses yet; skipping.");
continue;
}
if (signalState.pendingChecks.length > 0) {
core.info("PR #" + pull_number + " still has pending checks: " + signalState.pendingChecks.map((run) => run.name).join(", ") + ".");
continue;
}
if (signalState.failedChecks.length > 0 || signalState.failedStatuses.length > 0) {
const failedChecks = signalState.failedChecks.map((run) => run.name + "=" + run.conclusion).join(", ");
const failedStatuses = signalState.failedStatuses.map((status) => status.context + "=" + status.state).join(", ");
core.info("PR #" + pull_number + " is not green. Checks: " + (failedChecks || "none") + ". Statuses: " + (failedStatuses || "none") + ".");
continue;
}
let merged = false;
let lastError = null;
for (const merge_method of mergeMethods) {
try {
await github.rest.pulls.merge({ owner, repo, pull_number, merge_method });
core.info("Merged Dependabot PR #" + pull_number + " with " + merge_method + ".");
merged = true;
break;
} catch (error) {
lastError = error;
if (error.status === 403 || error.status === 405 || error.status === 409) {
core.info("Cannot merge PR #" + pull_number + " with " + merge_method + ": " + error.message);
continue;
}
throw error;
}
}
if (!merged) {
core.info("PR #" + pull_number + " could not be merged: " + (lastError?.message || "unknown error") + ".");
continue;
}
if (pr.head.repo?.full_name === owner + "/" + repo) {
try {
await github.rest.git.deleteRef({ owner, repo, ref: "heads/" + pr.head.ref });
core.info("Deleted branch " + pr.head.ref + ".");
} catch (error) {
core.info("Could not delete branch " + pr.head.ref + ": " + error.message);
}
}
}
+7 -7
View File
@@ -1,12 +1,12 @@
# X-WebUI
A comprehensive setup script for deploying a secure server environment with Nginx, Docker, X, and Open WebUI.
A comprehensive setup script for deploying a secure server environment with nginx, Docker, X proxy, and Open WebUI.
## Overview
This repository contains a bash script that automates the setup of a complete server environment on a Debian system. The script sets up:
- Nginx web server
- nginx web server
- SSL/TLS certificates via acme.sh
- Docker and Docker Compose
- Open WebUI (running in Docker)
@@ -15,7 +15,7 @@ This repository contains a bash script that automates the setup of a complete se
## Requirements
- Debian 10+ 64-bit system
- Debian/Ubuntu 64-bit system
- Sudo privileges
- Domain name pointing to your server
- Inbound traffic on TCP ports 80 and 443 from 0.0.0.0/0 allowed
@@ -38,7 +38,7 @@ Replace the following:
- `<username>`: Your login username
- `<domain>`: Your domain name (must be pointed to this server)
- `<id>`: A unique ID for the X configuration
- `<id>`: A unique ID for the X proxy configuration
If you encounter the following error:
@@ -56,7 +56,7 @@ sudo apt update && sudo apt install -y curl bash
### Web Server
- Configures Nginx
- Configures nginx
- Sets up automatic HTTPS redirection
- Implements proper security headers
@@ -73,7 +73,7 @@ sudo apt update && sudo apt install -y curl bash
### Proxy Configuration
- Installs and configures X
- Installs and configures X proxy
- Implements secure TLS settings
- Configures proper routing rules
@@ -99,6 +99,6 @@ This script implements several security best practices:
## License
Copyright &copy; [Xi Xu](https://xi-xu.me). All rights reserved.
Copyright &copy; [Xi Xu](https://xi-xu.me)
Licensed under the [GPL-3.0](LICENSE) license.
+192 -428
View File
@@ -1,440 +1,204 @@
#!/bin/bash
# Check if all required parameters are provided
# ==============================================================================
# Setup Script for x-webui
# ==============================================================================
# Exit immediately if a command exits with a non-zero status
set -euo pipefail
# ------------------------------------------------------------------------------
# Constants and Variables
# ------------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATE_DIR="$SCRIPT_DIR/src/config"
HTML_DIR="$SCRIPT_DIR/src/www"
# ------------------------------------------------------------------------------
# Helper Functions
# ------------------------------------------------------------------------------
log_info() {
echo -e "${GREEN}[INFO] $(date '+%Y-%m-%d %H:%M:%S'): $1${NC}"
}
log_warn() {
echo -e "${YELLOW}[WARN] $(date '+%Y-%m-%d %H:%M:%S'): $1${NC}"
}
log_error() {
echo -e "${RED}[ERROR] $(date '+%Y-%m-%d %H:%M:%S'): $1${NC}"
}
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "Please run as root (use sudo)"
exit 1
fi
}
install_dependencies() {
log_info "Installing required packages..."
apt-get update -y
apt-get install -y cron nginx ca-certificates curl gnupg lsb-release gettext-base
}
configure_nginx_initial() {
log_info "Configuring Nginx (Initial)..."
# Clean up default
if [ -f /var/www/html/index.nginx-debian.html ]; then
rm /var/www/html/index.nginx-debian.html
fi
# Set permissions
chown -R "$USERNAME:$USERNAME" /var/www
# Generate index.html from template
log_info "Generating portfolio for user: $USERNAME"
sed "s/{{USERNAME}}/$USERNAME/g" "$HTML_DIR/index.html" > /var/www/html/index.html
# Generate Nginx config
export DOMAIN
envsubst '${DOMAIN}' < "$TEMPLATE_DIR/nginx.conf.template" > /etc/nginx/nginx.conf
systemctl reload nginx
}
setup_acme() {
log_info "Setting up ACME for SSL..."
if [ ! -d "/home/$USERNAME/.acme.sh" ]; then
curl https://get.acme.sh | sh
fi
# Access as the user
sudo -u "$USERNAME" /home/$USERNAME/.acme.sh/acme.sh --upgrade --auto-upgrade
sudo -u "$USERNAME" /home/$USERNAME/.acme.sh/acme.sh --set-default-ca --server letsencrypt
sudo -u "$USERNAME" /home/$USERNAME/.acme.sh/acme.sh --issue -d "$DOMAIN" -w /var/www/html --keylength ec-256 --force
}
install_docker() {
log_info "Installing Docker..."
install -m 0755 -d /etc/apt/keyrings
if [ ! -f /etc/apt/keyrings/docker.asc ]; then
curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
fi
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
}
install_open_webui() {
log_info "Installing Open WebUI..."
docker pull ghcr.io/open-webui/open-webui:main
# Check if container exists
if [ "$(docker ps -aq -f name=open-webui)" ]; then
docker rm -f open-webui
fi
docker run -d -p 8888:8080 -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main
docker update --restart=unless-stopped open-webui
}
install_xray() {
log_info "Installing Xray..."
bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
}
setup_certificates() {
log_info "Setting up certificates..."
CERT_DIR="/home/$USERNAME/cert"
sudo -u "$USERNAME" mkdir -p "$CERT_DIR"
sudo -u "$USERNAME" /home/$USERNAME/.acme.sh/acme.sh --install-cert -d "$DOMAIN" --ecc --fullchain-file "$CERT_DIR/x.crt" --key-file "$CERT_DIR/x.key"
chmod +r "$CERT_DIR/x.key"
# Create renewal script
cat > "$CERT_DIR/cert-renew.sh" <<EOF
#!/bin/bash
/home/$USERNAME/.acme.sh/acme.sh --install-cert -d $DOMAIN --ecc --fullchain-file $CERT_DIR/x.crt --key-file $CERT_DIR/x.key
echo "X Certificates Renewed"
chmod +r $CERT_DIR/x.key
echo "Read Permission Granted for Private Key"
systemctl restart xray
echo "X Restarted"
EOF
chmod +x "$CERT_DIR/cert-renew.sh"
chown "$USERNAME:$USERNAME" "$CERT_DIR/cert-renew.sh"
# Cron job
(crontab -l 2>/dev/null; echo "0 1 1 * * bash $CERT_DIR/cert-renew.sh") | crontab -
}
configure_xray() {
log_info "Configuring Xray..."
export ID
export USERNAME
envsubst '${ID} ${USERNAME}' < "$TEMPLATE_DIR/xray.json.template" > /usr/local/etc/xray/config.json
systemctl start xray
systemctl enable xray
}
configure_system() {
log_info "Optimizing system settings..."
cat > /etc/sysctl.d/99-custom.conf <<'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
sysctl --system
}
configure_nginx_final() {
log_info "Finalizing Nginx configuration..."
export DOMAIN
envsubst '${DOMAIN}' < "$TEMPLATE_DIR/nginx_final.conf.template" > /etc/nginx/nginx.conf
systemctl restart nginx
}
# ------------------------------------------------------------------------------
# Main Execution
# ------------------------------------------------------------------------------
# Check arguments
if [ "$#" -ne 3 ]; then
echo "Usage: $0 <username> <domain> <id>"
exit 1
fi
# Assign parameters to variables
USERNAME="$1"
DOMAIN="$2"
ID="$3"
# Install required packages
sudo apt install cron nginx ca-certificates curl -y
check_root
install_dependencies
configure_nginx_initial
setup_acme
install_docker
install_open_webui
install_xray
setup_certificates
configure_xray
configure_system
configure_nginx_final
# Configure web server permissions and files
sudo chown -R "$USERNAME:$USERNAME" /var/www
rm /var/www/html/index.nginx-debian.html
# Create index.html
cat >/var/www/html/index.html <<'EOF'
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>John Doe - Professional Portfolio</title>
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--background: #f8f9fa;
--text: #2c3e50;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: var(--text);
background-color: var(--background);
}
header {
background-color: var(--primary);
color: white;
padding: 2rem 0;
text-align: center;
}
nav {
background-color: var(--secondary);
padding: 1rem 0;
}
nav ul {
list-style: none;
display: flex;
justify-content: center;
gap: 2rem;
}
nav a {
color: white;
text-decoration: none;
font-weight: 500;
}
nav a:hover {
text-decoration: underline;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.hero {
text-align: center;
padding: 4rem 0;
}
.projects {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 3rem 0;
}
.project-card {
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.skills {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin: 2rem 0;
}
.skill-tag {
background: var(--secondary);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.9rem;
}
footer {
background-color: var(--primary);
color: white;
text-align: center;
padding: 2rem 0;
margin-top: 4rem;
}
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: 1rem;
}
input,
textarea {
width: 100%;
padding: 0.5rem;
margin-top: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background-color: var(--secondary);
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
opacity: 0.9;
}
</style>
</head>
<body>
<header>
<h1>John Doe</h1>
<p>Full Stack Developer</p>
</header>
<nav>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<main class="container">
<section id="about" class="hero">
<h2>About Me</h2>
<p>
Passionate full-stack developer with 5+ years of experience
building scalable web applications. I specialize in modern
JavaScript frameworks and cloud architecture.
</p>
</section>
<section id="projects">
<h2>Featured Projects</h2>
<div class="projects">
<div class="project-card">
<h3>E-commerce Platform</h3>
<p>
A full-featured e-commerce solution built with React
and Node.js, featuring real-time inventory
management and secure payment processing.
</p>
</div>
<div class="project-card">
<h3>Task Management App</h3>
<p>
A collaborative task management application using
Vue.js and Firebase, with real-time updates and team
collaboration features.
</p>
</div>
<div class="project-card">
<h3>Analytics Dashboard</h3>
<p>
A responsive analytics dashboard built with D3.js
and Express, providing real-time data visualization
and reporting capabilities.
</p>
</div>
</div>
</section>
<section id="skills">
<h2>Skills</h2>
<div class="skills">
<span class="skill-tag">JavaScript</span>
<span class="skill-tag">React</span>
<span class="skill-tag">Node.js</span>
<span class="skill-tag">Python</span>
<span class="skill-tag">SQL</span>
<span class="skill-tag">AWS</span>
<span class="skill-tag">Docker</span>
<span class="skill-tag">Git</span>
</div>
</section>
<section id="contact">
<h2>Contact Me</h2>
<form class="contact-form">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required />
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea
id="message"
name="message"
rows="5"
required
></textarea>
</div>
<button type="submit">Send Message</button>
</form>
</section>
</main>
<footer><p>&copy; 2025 John Doe. All rights reserved.</p></footer>
</body>
</html>
EOF
# Initial nginx configuration
sudo tee /etc/nginx/nginx.conf >/dev/null <<EOF
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
server {
listen 80;
server_name $DOMAIN;
root /var/www/html;
index index.html;
}
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
EOF
sudo systemctl reload nginx
# Install and configure acme.sh
curl https://get.acme.sh | sh
~/.acme.sh/acme.sh --upgrade --auto-upgrade
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
~/.acme.sh/acme.sh --issue -d "$DOMAIN" -w /var/www/html --keylength ec-256 --force
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
# Install Docker
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
# Install Open WebUI
sudo docker pull ghcr.io/open-webui/open-webui:main
sudo docker run -d -p 8888:8080 -v open-webui:/app/backend/data --name open-webui ghcr.io/open-webui/open-webui:main
sudo docker update --restart=unless-stopped open-webui
# Install X
sudo bash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install
# Setup certificates
mkdir ~/cert
~/.acme.sh/acme.sh --install-cert -d "$DOMAIN" --ecc --fullchain-file ~/cert/x.crt --key-file ~/cert/x.key
chmod +r ~/cert/x.key
# Create certificate renewal script
cat >~/cert/cert-renew.sh <<EOF
#!/bin/bash
/home/$USERNAME/.acme.sh/acme.sh --install-cert -d $DOMAIN --ecc --fullchain-file /home/$USERNAME/cert/x.crt --key-file /home/$USERNAME/cert/x.key
echo "X Certificates Renewed"
chmod +r /home/$USERNAME/cert/x.key
echo "Read Permission Granted for Private Key"
sudo systemctl restart xray
echo "X Restarted"
EOF
chmod +x ~/cert/cert-renew.sh
# Setup cron job
crontab -l >temp_cron
echo "0 1 1 * * bash /home/$USERNAME/cert/cert-renew.sh" >>temp_cron
crontab temp_cron
rm temp_cron
# Configure X
sudo tee /usr/local/etc/xray/config.json >/dev/null <<EOF
{
"dns": {
"servers": ["https+local://1.1.1.1/dns-query", "localhost"]
},
"routing": {
"rules": [
{
"ip": ["geoip:private"],
"outboundTag": "block"
},
{
"ip": ["geoip:cn"],
"outboundTag": "block"
}
]
},
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "$ID",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": 8888
}
]
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"rejectUnknownSni": true,
"alpn": "http/1.1",
"minVersion": "1.2",
"certificates": [
{
"certificateFile": "/home/$USERNAME/cert/x.crt",
"keyFile": "/home/$USERNAME/cert/x.key"
}
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
],
"policy": {
"levels": {
"0": {
"handshake": 2,
"connIdle": 150
}
}
}
}
EOF
# Start and enable X
sudo systemctl start xray
sudo systemctl enable xray
# Configure system settings
sudo tee /etc/sysctl.conf >/dev/null <<'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
# Final nginx configuration
sudo tee /etc/nginx/nginx.conf >/dev/null <<EOF
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
server {
listen 80;
server_name $DOMAIN;
return 301 https://\$http_host\$request_uri;
}
# server {
# listen 8888;
# root /var/www/html;
# index index.html;
# add_header Strict-Transport-Security "max-age=63072000" always;
# }
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
EOF
# Restart services and system
sudo systemctl restart nginx
sudo reboot
log_info "Setup complete! The system will now reboot."
reboot
+27
View File
@@ -0,0 +1,27 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
server {
listen 80;
server_name ${DOMAIN};
root /var/www/html;
index index.html;
}
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
+32
View File
@@ -0,0 +1,32 @@
user www-data;
worker_processes auto;
pid /run/nginx.pid;
error_log /var/log/nginx/error.log;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
server {
listen 80;
server_name ${DOMAIN};
return 301 https://$http_host$request_uri;
}
# server {
# listen 8888;
# root /var/www/html;
# index index.html;
# add_header Strict-Transport-Security "max-age=63072000" always;
# }
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
+69
View File
@@ -0,0 +1,69 @@
{
"dns": {
"servers": ["https+local://1.1.1.1/dns-query", "localhost"]
},
"routing": {
"rules": [
{
"ip": ["geoip:private"],
"outboundTag": "block"
},
{
"ip": ["geoip:cn"],
"outboundTag": "block"
}
]
},
"inbounds": [
{
"port": 443,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "${ID}",
"flow": "xtls-rprx-vision"
}
],
"decryption": "none",
"fallbacks": [
{
"dest": 8888
}
]
},
"streamSettings": {
"security": "tls",
"tlsSettings": {
"rejectUnknownSni": true,
"alpn": "http/1.1",
"minVersion": "1.2",
"certificates": [
{
"certificateFile": "/home/${USERNAME}/cert/x.crt",
"keyFile": "/home/${USERNAME}/cert/x.key"
}
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
},
{
"protocol": "blackhole",
"tag": "block"
}
],
"policy": {
"levels": {
"0": {
"handshake": 2,
"connIdle": 150
}
}
}
}
+208
View File
@@ -0,0 +1,208 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{USERNAME}} - Professional Portfolio</title>
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--background: #f8f9fa;
--text: #2c3e50;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
line-height: 1.6;
color: var(--text);
background-color: var(--background);
}
header {
background-color: var(--primary);
color: white;
padding: 2rem 0;
text-align: center;
}
nav {
background-color: var(--secondary);
padding: 1rem 0;
}
nav ul {
list-style: none;
display: flex;
justify-content: center;
gap: 2rem;
}
nav a {
color: white;
text-decoration: none;
font-weight: 500;
}
nav a:hover {
text-decoration: underline;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
.hero {
text-align: center;
padding: 4rem 0;
}
.projects {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 3rem 0;
}
.project-card {
background: white;
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.skills {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin: 2rem 0;
}
.skill-tag {
background: var(--secondary);
color: white;
padding: 0.5rem 1rem;
border-radius: 20px;
font-size: 0.9rem;
}
footer {
background-color: var(--primary);
color: white;
text-align: center;
padding: 2rem 0;
margin-top: 4rem;
}
.contact-form {
max-width: 600px;
margin: 0 auto;
}
.form-group {
margin-bottom: 1rem;
}
input,
textarea {
width: 100%;
padding: 0.5rem;
margin-top: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
background-color: var(--secondary);
color: white;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
opacity: 0.9;
}
</style>
</head>
<body>
<header>
<h1>{{USERNAME}}</h1>
<p>Full Stack Developer</p>
</header>
<nav>
<ul>
<li><a href="#about">About</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
<main class="container">
<section id="about" class="hero">
<h2>About Me</h2>
<p>
Passionate full-stack developer with 5+ years of experience
building scalable web applications. I specialize in modern
JavaScript frameworks and cloud architecture.
</p>
</section>
<section id="projects">
<h2>Featured Projects</h2>
<div class="projects">
<div class="project-card">
<h3>E-commerce Platform</h3>
<p>
A full-featured e-commerce solution built with React
and Node.js, featuring real-time inventory
management and secure payment processing.
</p>
</div>
<div class="project-card">
<h3>Task Management App</h3>
<p>
A collaborative task management application using
Vue.js and Firebase, with real-time updates and team
collaboration features.
</p>
</div>
<div class="project-card">
<h3>Analytics Dashboard</h3>
<p>
A responsive analytics dashboard built with D3.js
and Express, providing real-time data visualization
and reporting capabilities.
</p>
</div>
</div>
</section>
<section id="skills">
<h2>Skills</h2>
<div class="skills">
<span class="skill-tag">JavaScript</span>
<span class="skill-tag">React</span>
<span class="skill-tag">Node.js</span>
<span class="skill-tag">Python</span>
<span class="skill-tag">SQL</span>
<span class="skill-tag">AWS</span>
<span class="skill-tag">Docker</span>
<span class="skill-tag">Git</span>
</div>
</section>
<section id="contact">
<h2>Contact Me</h2>
<form class="contact-form">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required />
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="message">Message:</label>
<textarea
id="message"
name="message"
rows="5"
required
></textarea>
</div>
<button type="submit">Send Message</button>
</form>
</section>
</main>
<footer><p>&copy; 2025 {{USERNAME}}. All rights reserved.</p></footer>
</body>
</html>