Upload 6 files
Browse files- Dockerfile +65 -0
- README.md +118 -11
- nginx.conf +68 -0
- oauth2-proxy-github.cfg +12 -0
- sign_in.html +104 -0
- start.sh +91 -0
Dockerfile
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use a lightweight Debian base for a simplified Linux environment
|
| 2 |
+
FROM debian:bookworm-slim
|
| 3 |
+
|
| 4 |
+
# Set environment variables to avoid interactive prompts during installation
|
| 5 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 6 |
+
ENV HOME=/home/user
|
| 7 |
+
ENV PATH=$HOME/.local/bin:$PATH
|
| 8 |
+
|
| 9 |
+
# Install essential system packages and build tools
|
| 10 |
+
# - sudo: Required for root privileges
|
| 11 |
+
# - build-essential, cmake: Required for compiling software like OpenClaw
|
| 12 |
+
# - curl, wget, git: Basic tools for downloading and version control
|
| 13 |
+
# - vim, nano: Text editors
|
| 14 |
+
# - nginx, netcat-openbsd: Required for Auth Proxy
|
| 15 |
+
RUN apt-get update && apt-get install -y \
|
| 16 |
+
curl \
|
| 17 |
+
wget \
|
| 18 |
+
git \
|
| 19 |
+
sudo \
|
| 20 |
+
vim \
|
| 21 |
+
nano \
|
| 22 |
+
unzip \
|
| 23 |
+
procps \
|
| 24 |
+
net-tools \
|
| 25 |
+
nginx \
|
| 26 |
+
netcat-openbsd \
|
| 27 |
+
build-essential \
|
| 28 |
+
cmake \
|
| 29 |
+
pkg-config \
|
| 30 |
+
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
| 31 |
+
|
| 32 |
+
# Install ttyd (Web Terminal)
|
| 33 |
+
RUN wget https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 -O /usr/bin/ttyd \
|
| 34 |
+
&& chmod +x /usr/bin/ttyd
|
| 35 |
+
|
| 36 |
+
# Install oauth2-proxy
|
| 37 |
+
RUN wget https://github.com/oauth2-proxy/oauth2-proxy/releases/download/v7.6.0/oauth2-proxy-v7.6.0.linux-amd64.tar.gz \
|
| 38 |
+
&& tar -xzf oauth2-proxy-v7.6.0.linux-amd64.tar.gz \
|
| 39 |
+
&& mv oauth2-proxy-v7.6.0.linux-amd64/oauth2-proxy /usr/bin/oauth2-proxy \
|
| 40 |
+
&& chmod +x /usr/bin/oauth2-proxy \
|
| 41 |
+
&& rm -rf oauth2-proxy-v7.6.0.linux-amd64*
|
| 42 |
+
|
| 43 |
+
# Create a non-root user 'user' (UID 1000) for security and Hugging Face compatibility
|
| 44 |
+
# Grant sudo privileges without password for easy administration
|
| 45 |
+
RUN useradd -m -u 1000 user && \
|
| 46 |
+
echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
|
| 47 |
+
|
| 48 |
+
# Set working directory to user's home
|
| 49 |
+
WORKDIR $HOME
|
| 50 |
+
|
| 51 |
+
# Copy configuration files
|
| 52 |
+
COPY --chown=user:user nginx.conf /etc/nginx/nginx.conf
|
| 53 |
+
COPY --chown=user:user oauth2-proxy-github.cfg $HOME/oauth2-proxy-github.cfg
|
| 54 |
+
COPY --chown=user:user sign_in.html /var/www/html/theme/sign_in.html
|
| 55 |
+
COPY --chown=user:user start.sh $HOME/start.sh
|
| 56 |
+
RUN chmod +x $HOME/start.sh
|
| 57 |
+
|
| 58 |
+
# Switch to the non-root user
|
| 59 |
+
USER user
|
| 60 |
+
|
| 61 |
+
# Expose port 7860 (Standard for Hugging Face Spaces)
|
| 62 |
+
EXPOSE 7860
|
| 63 |
+
|
| 64 |
+
# Start via entrypoint script
|
| 65 |
+
CMD ["./start.sh"]
|
README.md
CHANGED
|
@@ -1,11 +1,118 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: VPS Linux
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo: green
|
| 6 |
-
sdk: docker
|
| 7 |
-
pinned: false
|
| 8 |
-
license: mit
|
| 9 |
-
---
|
| 10 |
-
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: VPS Linux
|
| 3 |
+
emoji: 🐨
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: green
|
| 6 |
+
sdk: docker
|
| 7 |
+
pinned: false
|
| 8 |
+
license: mit
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Simplified Linux VPS on Hugging Face Spaces
|
| 12 |
+
|
| 13 |
+
This project provides a simplified Linux VPS on Hugging Face Spaces with:
|
| 14 |
+
|
| 15 |
+
- Debian Bookworm Slim base
|
| 16 |
+
- Browser terminal powered by `ttyd`
|
| 17 |
+
- GitHub OAuth authentication via `nginx + oauth2-proxy`
|
| 18 |
+
- Simple allowlist control
|
| 19 |
+
|
| 20 |
+
Users can access the Linux terminal only after successful GitHub login.
|
| 21 |
+
|
| 22 |
+
## 🚀 Quick Start
|
| 23 |
+
|
| 24 |
+
### 1) Create a Hugging Face Space
|
| 25 |
+
|
| 26 |
+
1. Log in to Hugging Face.
|
| 27 |
+
2. Click your avatar in the top right corner and choose **New Space**.
|
| 28 |
+
3. Enter a Space name (for example: `my-linux-vps`).
|
| 29 |
+
4. Select **SDK: Docker**.
|
| 30 |
+
5. Select **Docker Template: Blank**.
|
| 31 |
+
6. Click **Create Space**.
|
| 32 |
+
|
| 33 |
+
### 2) Upload project files
|
| 34 |
+
|
| 35 |
+
Upload all files from this folder to your Space repository.
|
| 36 |
+
|
| 37 |
+
### 3) Configure Variables and Secrets
|
| 38 |
+
|
| 39 |
+
In **Space Settings -> Variables and Secrets**, add:
|
| 40 |
+
|
| 41 |
+
**Variables**
|
| 42 |
+
|
| 43 |
+
- `SPACE_PUBLIC_URL=https://<your-space-name>.hf.space`
|
| 44 |
+
- `ALLOWED_USERS=user1@gmail.com,github_username_1` (Supports GitHub email addresses or usernames)
|
| 45 |
+
|
| 46 |
+
**Secrets**
|
| 47 |
+
|
| 48 |
+
- `GITHUB_CLIENT_ID=<github oauth app client id>`
|
| 49 |
+
- `GITHUB_CLIENT_SECRET=<github oauth app client secret>`
|
| 50 |
+
- `OAUTH2_PROXY_COOKIE_SECRET=<32-byte-base64-secret>`
|
| 51 |
+
|
| 52 |
+
Requirements:
|
| 53 |
+
|
| 54 |
+
- Secret values must be plain text (no quotes, no leading/trailing spaces).
|
| 55 |
+
- `SPACE_PUBLIC_URL` must not include a trailing slash.
|
| 56 |
+
|
| 57 |
+
### 4) Configure GitHub OAuth callback
|
| 58 |
+
|
| 59 |
+
In your GitHub OAuth App, set callback URL to:
|
| 60 |
+
|
| 61 |
+
`https://<your-space-name>.hf.space/oauth2/callback`
|
| 62 |
+
|
| 63 |
+
`SPACE_PUBLIC_URL` and callback domain must match exactly.
|
| 64 |
+
During login consent, the app requests `user:email` scope only.
|
| 65 |
+
|
| 66 |
+
### 5) Access the VPS
|
| 67 |
+
|
| 68 |
+
1. Wait until the Space status is **Running**.
|
| 69 |
+
2. Open the **App** tab.
|
| 70 |
+
3. Sign in with GitHub.
|
| 71 |
+
4. After successful authentication, the web terminal will be available.
|
| 72 |
+
|
| 73 |
+
## 🛠️ Features
|
| 74 |
+
|
| 75 |
+
- **Base system**: Debian Bookworm Slim
|
| 76 |
+
- **Privileges**: default `user` has passwordless sudo
|
| 77 |
+
- **Toolchain**: `git`, `curl`, `wget`, `vim`, `nano`, `build-essential`, `cmake`
|
| 78 |
+
- **Web terminal**: `ttyd`
|
| 79 |
+
- **Authentication**: `nginx + oauth2-proxy` (GitHub only)
|
| 80 |
+
- **Allowlist**: supports GitHub email addresses and GitHub usernames in `ALLOWED_USERS`
|
| 81 |
+
|
| 82 |
+
## 🎮 How to Build OpenClaw
|
| 83 |
+
|
| 84 |
+
OpenClaw needs extra dependencies. Hugging Face Spaces has no native display, so GUI execution usually fails unless you set up VNC/X11 manually.
|
| 85 |
+
|
| 86 |
+
### Install dependencies
|
| 87 |
+
|
| 88 |
+
```bash
|
| 89 |
+
sudo apt-get update
|
| 90 |
+
sudo apt-get install -y \
|
| 91 |
+
libsdl2-dev \
|
| 92 |
+
libsdl2-image-dev \
|
| 93 |
+
libsdl2-mixer-dev \
|
| 94 |
+
libsdl2-ttf-dev \
|
| 95 |
+
libxml2-dev \
|
| 96 |
+
zlib1g-dev
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
### Clone and compile
|
| 100 |
+
|
| 101 |
+
```bash
|
| 102 |
+
git clone https://github.com/pjasicek/OpenClaw.git
|
| 103 |
+
cd OpenClaw
|
| 104 |
+
mkdir build && cd build
|
| 105 |
+
cmake ..
|
| 106 |
+
make -j$(nproc)
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
## Notes
|
| 110 |
+
|
| 111 |
+
- Running `./OpenClaw` may fail with `Could not initialize SDL: No available video device`.
|
| 112 |
+
- After Space restart, files outside `/data` may be lost. Save important data in `/data` (if persistent storage is enabled) or sync with Git.
|
| 113 |
+
- **Troubleshooting 500 Errors**: If you encounter a 500 error during login, ensure you have removed any legacy `OAUTH2_PROXY_GITHUB_ORG` variables from Space Settings, revoke the GitHub App authorization, and clear your browser cookies.
|
| 114 |
+
|
| 115 |
+
## ⚠️ Security Warning
|
| 116 |
+
|
| 117 |
+
- This VPS has elevated privileges. Do not store sensitive keys inside it.
|
| 118 |
+
- Public Spaces are accessible unless protected. This project protects terminal access with GitHub OAuth and allowlist rules.
|
nginx.conf
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
worker_processes auto;
|
| 2 |
+
pid /tmp/nginx.pid;
|
| 3 |
+
|
| 4 |
+
events {
|
| 5 |
+
worker_connections 768;
|
| 6 |
+
}
|
| 7 |
+
|
| 8 |
+
http {
|
| 9 |
+
sendfile on;
|
| 10 |
+
tcp_nopush on;
|
| 11 |
+
types_hash_max_size 2048;
|
| 12 |
+
include /etc/nginx/mime.types;
|
| 13 |
+
default_type application/octet-stream;
|
| 14 |
+
|
| 15 |
+
access_log /dev/stdout;
|
| 16 |
+
error_log /dev/stderr;
|
| 17 |
+
|
| 18 |
+
client_body_temp_path /tmp/client_body;
|
| 19 |
+
proxy_temp_path /tmp/proxy;
|
| 20 |
+
fastcgi_temp_path /tmp/fastcgi;
|
| 21 |
+
uwsgi_temp_path /tmp/uwsgi;
|
| 22 |
+
scgi_temp_path /tmp/scgi;
|
| 23 |
+
|
| 24 |
+
server {
|
| 25 |
+
listen 7860;
|
| 26 |
+
server_name localhost;
|
| 27 |
+
|
| 28 |
+
# Custom sign-in page
|
| 29 |
+
location = /signin {
|
| 30 |
+
root /var/www/html/theme;
|
| 31 |
+
try_files /sign_in.html =404;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# OAuth2 Proxy endpoints
|
| 35 |
+
location /oauth2/ {
|
| 36 |
+
proxy_pass http://127.0.0.1:4180;
|
| 37 |
+
proxy_set_header Host $host;
|
| 38 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 39 |
+
proxy_set_header X-Scheme $scheme;
|
| 40 |
+
proxy_set_header X-Auth-Request-Redirect $request_uri;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
location = /oauth2/auth {
|
| 44 |
+
internal;
|
| 45 |
+
proxy_pass http://127.0.0.1:4180;
|
| 46 |
+
proxy_set_header Host $host;
|
| 47 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 48 |
+
proxy_set_header X-Scheme $scheme;
|
| 49 |
+
proxy_set_header Content-Length "";
|
| 50 |
+
proxy_pass_request_body off;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
# Main application (ttyd) protected by auth_request
|
| 54 |
+
location / {
|
| 55 |
+
auth_request /oauth2/auth;
|
| 56 |
+
error_page 401 = /signin;
|
| 57 |
+
|
| 58 |
+
proxy_pass http://127.0.0.1:7681;
|
| 59 |
+
proxy_http_version 1.1;
|
| 60 |
+
proxy_set_header Upgrade $http_upgrade;
|
| 61 |
+
proxy_set_header Connection "upgrade";
|
| 62 |
+
proxy_set_header Host $host;
|
| 63 |
+
proxy_set_header X-Real-IP $remote_addr;
|
| 64 |
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
| 65 |
+
proxy_set_header X-Forwarded-Proto $scheme;
|
| 66 |
+
}
|
| 67 |
+
}
|
| 68 |
+
}
|
oauth2-proxy-github.cfg
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
http_address = "127.0.0.1:4180"
|
| 2 |
+
provider = "github"
|
| 3 |
+
email_domains = ["*"]
|
| 4 |
+
cookie_secure = true
|
| 5 |
+
cookie_httponly = true
|
| 6 |
+
cookie_refresh = "1h"
|
| 7 |
+
cookie_expire = "168h"
|
| 8 |
+
reverse_proxy = true
|
| 9 |
+
set_xauthrequest = true
|
| 10 |
+
skip_provider_button = true
|
| 11 |
+
upstreams = ["http://127.0.0.1:7681"]
|
| 12 |
+
request_logging = true
|
sign_in.html
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
+
<title>Sign In - VPS Linux</title>
|
| 7 |
+
<style>
|
| 8 |
+
:root {
|
| 9 |
+
/* 页面背景色 - 极深黑 */
|
| 10 |
+
--bg-color: #050505;
|
| 11 |
+
/* 卡片背景色 - 稍浅的黑 */
|
| 12 |
+
--card-bg: #0f0f0f;
|
| 13 |
+
/* 标题颜色 - 纯白 */
|
| 14 |
+
--title-color: #ffffff;
|
| 15 |
+
/* 副标题颜色 - 灰色 */
|
| 16 |
+
--subtitle-color: #888888;
|
| 17 |
+
/* 边框颜色 - 极淡灰 */
|
| 18 |
+
--border-color: #222222;
|
| 19 |
+
/* 按钮背景 - 深灰 */
|
| 20 |
+
--button-bg: #1c1c1c;
|
| 21 |
+
/* 按钮文字 - 浅灰 */
|
| 22 |
+
--button-text: #e1e1e1;
|
| 23 |
+
/* 按钮悬停 - 稍亮灰 */
|
| 24 |
+
--button-hover: #2a2a2a;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
body {
|
| 28 |
+
background-color: var(--bg-color);
|
| 29 |
+
color: var(--title-color);
|
| 30 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
| 31 |
+
display: flex;
|
| 32 |
+
align-items: center;
|
| 33 |
+
justify-content: center;
|
| 34 |
+
height: 100vh;
|
| 35 |
+
margin: 0;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
.login-container {
|
| 39 |
+
background-color: var(--card-bg);
|
| 40 |
+
border: 1px solid var(--border-color);
|
| 41 |
+
border-radius: 12px;
|
| 42 |
+
padding: 48px 40px;
|
| 43 |
+
width: 100%;
|
| 44 |
+
max-width: 360px;
|
| 45 |
+
text-align: center;
|
| 46 |
+
/* 柔和阴影 */
|
| 47 |
+
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4);
|
| 48 |
+
}
|
| 49 |
+
|
| 50 |
+
.logo {
|
| 51 |
+
width: 64px;
|
| 52 |
+
height: 64px;
|
| 53 |
+
margin: 0 auto 24px;
|
| 54 |
+
/* 红色实心机器人 SVG */
|
| 55 |
+
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path fill="%23ff595e" d="M32 6C18.745 6 8 16.745 8 30c0 8.837 4.785 16.685 12.049 21.146-.688 2.375-2.049 4.354-2.049 4.354s4.5.5 8.5-2.5c1.616.323 3.298.5 5 .5 13.255 0 24-10.745 24-24S45.255 6 32 6zm-8 22c-2.209 0-4-1.791-4-4s1.791-4 4-4 4 1.791 4 4-1.791 4-4 4zm16 0c-2.209 0-4-1.791-4-4s1.791-4 4-4 4 1.791 4 4-1.791 4-4 4z"/><circle cx="24" cy="28" r="2" fill="%23333"/><circle cx="40" cy="28" r="2" fill="%23333"/></svg>');
|
| 56 |
+
background-repeat: no-repeat;
|
| 57 |
+
background-position: center;
|
| 58 |
+
background-size: contain;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
h1 {
|
| 62 |
+
font-size: 24px;
|
| 63 |
+
font-weight: 600;
|
| 64 |
+
margin: 0 0 12px;
|
| 65 |
+
color: var(--title-color);
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
p {
|
| 69 |
+
color: var(--subtitle-color);
|
| 70 |
+
margin: 0 0 32px;
|
| 71 |
+
font-size: 14px;
|
| 72 |
+
line-height: 1.5;
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
.btn {
|
| 76 |
+
display: block;
|
| 77 |
+
width: 100%;
|
| 78 |
+
padding: 14px;
|
| 79 |
+
border-radius: 8px;
|
| 80 |
+
border: none;
|
| 81 |
+
background-color: var(--button-bg);
|
| 82 |
+
color: var(--button-text);
|
| 83 |
+
font-size: 14px;
|
| 84 |
+
font-weight: 600;
|
| 85 |
+
text-decoration: none;
|
| 86 |
+
box-sizing: border-box;
|
| 87 |
+
cursor: pointer;
|
| 88 |
+
transition: background-color 0.2s ease;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.btn:hover {
|
| 92 |
+
background-color: var(--button-hover);
|
| 93 |
+
}
|
| 94 |
+
</style>
|
| 95 |
+
</head>
|
| 96 |
+
<body>
|
| 97 |
+
<div class="login-container">
|
| 98 |
+
<div class="logo"></div>
|
| 99 |
+
<h1>Welcome Back</h1>
|
| 100 |
+
<p>Sign in to access your VPS Linux environment</p>
|
| 101 |
+
<a class="btn" href="/oauth2/start?rd=/">Sign in with GitHub</a>
|
| 102 |
+
</div>
|
| 103 |
+
</body>
|
| 104 |
+
</html>
|
start.sh
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
set -e
|
| 3 |
+
set -x
|
| 4 |
+
|
| 5 |
+
# 1. 强制清理遗留的组织校验变量(避免500错误)
|
| 6 |
+
unset OAUTH2_PROXY_GITHUB_ORG OAUTH2_PROXY_GITHUB_ORGS
|
| 7 |
+
unset OAUTH2_PROXY_GITHUB_TEAM OAUTH2_PROXY_GITHUB_TEAMS
|
| 8 |
+
unset OAUTH2_PROXY_GITHUB_REPO OAUTH2_PROXY_GITHUB_REPOS
|
| 9 |
+
unset OAUTH2_PROXY_ALLOWED_GROUPS
|
| 10 |
+
|
| 11 |
+
# 2. 检查必要变量
|
| 12 |
+
if [ -z "$ALLOWED_USERS" ]; then
|
| 13 |
+
echo "Error: ALLOWED_USERS is required."
|
| 14 |
+
exit 1
|
| 15 |
+
fi
|
| 16 |
+
|
| 17 |
+
if [ -z "$GITHUB_CLIENT_ID" ] || [ -z "$GITHUB_CLIENT_SECRET" ] || [ -z "$OAUTH2_PROXY_COOKIE_SECRET" ]; then
|
| 18 |
+
echo "Error: GitHub Secrets (CLIENT_ID, CLIENT_SECRET, COOKIE_SECRET) are required."
|
| 19 |
+
exit 1
|
| 20 |
+
fi
|
| 21 |
+
|
| 22 |
+
if [ -z "$SPACE_PUBLIC_URL" ]; then
|
| 23 |
+
echo "Error: SPACE_PUBLIC_URL is required."
|
| 24 |
+
exit 1
|
| 25 |
+
fi
|
| 26 |
+
|
| 27 |
+
# 3. 变量清洗
|
| 28 |
+
trim_secret() {
|
| 29 |
+
printf "%s" "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | tr -d '\r' | sed 's/^"//;s/"$//'
|
| 30 |
+
}
|
| 31 |
+
GITHUB_CLIENT_ID=$(trim_secret "$GITHUB_CLIENT_ID")
|
| 32 |
+
GITHUB_CLIENT_SECRET=$(trim_secret "$GITHUB_CLIENT_SECRET")
|
| 33 |
+
OAUTH2_PROXY_COOKIE_SECRET=$(trim_secret "$OAUTH2_PROXY_COOKIE_SECRET")
|
| 34 |
+
SPACE_PUBLIC_URL=$(echo "$SPACE_PUBLIC_URL" | sed "s/[[:space:]]//g" | sed "s/\`//g")
|
| 35 |
+
SPACE_PUBLIC_URL="${SPACE_PUBLIC_URL%/}"
|
| 36 |
+
|
| 37 |
+
# 4. 生成白名单文件
|
| 38 |
+
AUTH_FILE="/tmp/authenticated_emails.txt"
|
| 39 |
+
> "$AUTH_FILE"
|
| 40 |
+
declare -a GITHUB_USERS
|
| 41 |
+
IFS=',' read -ra USERS <<< "$ALLOWED_USERS"
|
| 42 |
+
for USER_ITEM in "${USERS[@]}"; do
|
| 43 |
+
USER_ITEM=$(echo "$USER_ITEM" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
| 44 |
+
[ -z "$USER_ITEM" ] && continue
|
| 45 |
+
|
| 46 |
+
# 区分邮箱与用户名
|
| 47 |
+
if [[ "$USER_ITEM" == *"@"* ]]; then
|
| 48 |
+
echo "$USER_ITEM" | tr '[:upper:]' '[:lower:]' >> "$AUTH_FILE"
|
| 49 |
+
else
|
| 50 |
+
GITHUB_USERS+=("$(echo "$USER_ITEM" | tr '[:upper:]' '[:lower:]')")
|
| 51 |
+
fi
|
| 52 |
+
done
|
| 53 |
+
|
| 54 |
+
# 5. 启动 ttyd
|
| 55 |
+
echo "Starting ttyd..."
|
| 56 |
+
ttyd -p 7681 -i 127.0.0.1 -W bash &
|
| 57 |
+
|
| 58 |
+
# 6. 启动 oauth2-proxy (GitHub)
|
| 59 |
+
echo "Starting oauth2-proxy..."
|
| 60 |
+
GITHUB_CMD=(oauth2-proxy \
|
| 61 |
+
--config=$HOME/oauth2-proxy-github.cfg \
|
| 62 |
+
--client-id="$GITHUB_CLIENT_ID" \
|
| 63 |
+
--client-secret="$GITHUB_CLIENT_SECRET" \
|
| 64 |
+
--cookie-secret="$OAUTH2_PROXY_COOKIE_SECRET" \
|
| 65 |
+
--cookie-name="_oauth2_proxy_github" \
|
| 66 |
+
--scope="user:email" \
|
| 67 |
+
--show-debug-on-error=true \
|
| 68 |
+
--redirect-url="$SPACE_PUBLIC_URL/oauth2/callback")
|
| 69 |
+
|
| 70 |
+
# 按需挂载白名单
|
| 71 |
+
if [ -s "$AUTH_FILE" ]; then
|
| 72 |
+
GITHUB_CMD+=("--authenticated-emails-file=$AUTH_FILE")
|
| 73 |
+
fi
|
| 74 |
+
for GH_USER in "${GITHUB_USERS[@]}"; do
|
| 75 |
+
GITHUB_CMD+=("--github-user=$GH_USER")
|
| 76 |
+
done
|
| 77 |
+
|
| 78 |
+
"${GITHUB_CMD[@]}" 2>&1 &
|
| 79 |
+
|
| 80 |
+
# 7. 等待服务就绪
|
| 81 |
+
for i in {1..30}; do
|
| 82 |
+
if nc -z 127.0.0.1 4180 && nc -z 127.0.0.1 7681; then
|
| 83 |
+
echo "Services ready."
|
| 84 |
+
break
|
| 85 |
+
fi
|
| 86 |
+
sleep 1
|
| 87 |
+
done
|
| 88 |
+
|
| 89 |
+
# 8. 启动 Nginx
|
| 90 |
+
echo "Starting Nginx..."
|
| 91 |
+
nginx -g "daemon off;"
|