浏览代码

feat: use devconatiner

Jacky 2 月之前
父节点
当前提交
00f4855dce

+ 57 - 0
.devcontainer/Dockerfile

@@ -0,0 +1,57 @@
+FROM mcr.microsoft.com/devcontainers/base:jammy
+
+# Combine installation steps for Nginx and Go to avoid repetitive update/cleanup commands
+RUN apt-get update && \
+    apt-get install -y --no-install-recommends curl gnupg2 ca-certificates lsb-release ubuntu-keyring jq && \
+    \
+    # Configure the Nginx repository
+    curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor > /usr/share/keyrings/nginx-archive-keyring.gpg && \
+    echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/mainline/ubuntu $(lsb_release -cs) nginx" \
+        > /etc/apt/sources.list.d/nginx.list && \
+    printf "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
+        > /etc/apt/preferences.d/99nginx && \
+    \
+    # Update package information and install Nginx
+    apt-get update && \
+    apt-get install -y --no-install-recommends nginx && \
+    \
+    # Install the latest Node.js via NodeSource setup script
+    curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \
+    apt-get update && \
+    apt-get install -y nodejs && \
+    \
+    # Install pnpm globally using npm
+    npm install -g pnpm && \
+    \
+    # Automatically retrieve the latest stable Go version and install it,
+    # download the appropriate binary based on system architecture (amd64 or arm64)
+    GO_VERSION=$(curl -sSL "https://golang.org/dl/?mode=json" | \
+        jq -r 'map(select(.stable)) | .[0].version' | sed 's/^go//') && \
+    ARCH=$(dpkg --print-architecture) && \
+    if [ "$ARCH" = "arm64" ]; then \
+      GO_ARCH=linux-arm64; \
+    else \
+      GO_ARCH=linux-amd64; \
+    fi && \
+    echo "Installing Go version: ${GO_VERSION} for architecture: ${GO_ARCH}" && \
+    curl -sSL "https://golang.org/dl/go${GO_VERSION}.${GO_ARCH}.tar.gz" -o go.tar.gz && \
+    rm -rf /usr/local/go && \
+    tar -C /usr/local -xzf go.tar.gz && \
+    rm go.tar.gz && \
+    \
+    # Remove jq and clean up to reduce image size
+    apt-get remove -y jq && \
+    apt-get autoremove -y && \
+    apt-get clean && \
+    rm -rf /var/lib/apt/lists/*
+
+RUN cp -rp /etc/nginx /etc/nginx.orig
+
+# Set PATH to include Go installation and default go install binary location
+ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}"
+
+# Install air with go install (requires Go 1.23 or higher)
+RUN go install github.com/air-verse/air@latest
+
+# set zsh as default shell
+RUN chsh -s $(which zsh)

+ 42 - 0
.devcontainer/devcontainer.json

@@ -0,0 +1,42 @@
+// For format details, see https://aka.ms/devcontainer.json. For config options, see the
+// README at: https://github.com/devcontainers/templates/tree/main/src/ubuntu
+{
+  "name": "Ubuntu",
+  "dockerComposeFile": "docker-compose.yml",
+  "service": "nginx-ui",
+  "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
+  "shutdownAction": "stopCompose",
+  // Features to add to the dev container. More info: https://containers.dev/features.
+  "features": {
+    "ghcr.io/devcontainers/features/common-utils:2": {
+      "installOhMyZsh": true
+    }
+  },
+
+  // Use 'forwardPorts' to make a list of ports inside the container available locally.
+  // "forwardPorts": [],
+
+  // Use 'postCreateCommand' to run commands after the container is created.
+  // "postCreateCommand": "",
+
+  // Configure tool-specific properties.
+  "customizations": {
+    "vscode": {
+      "extensions": [
+        "antfu.iconify",
+        "antfu.unocss",
+        "github.copilot",
+        "golang.go",
+        "vue.volar"
+      ]
+    }
+  },
+
+  // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
+  "remoteUser": "root",
+  "overrideCommand": false,
+  "postStartCommand": "./.devcontainer/start.sh",
+  "mounts": [
+    "source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind,consistency=cached"
+  ]
+}

+ 41 - 0
.devcontainer/docker-compose.yml

@@ -0,0 +1,41 @@
+services:
+  nginx-ui:
+    build: .
+    volumes:
+      - ../..:/workspaces:cached
+      - ./go-path:/root/go
+      - ./nginx:/etc/nginx
+    command: sleep infinity
+    environment:
+      - NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
+    networks:
+      nginxui:
+  pebble:
+    image: ghcr.io/letsencrypt/pebble:latest
+    volumes:
+      - ./pebble-test:/test
+    command: -config /test/config/pebble-config.json -strict -dnsserver challtestsrv:8053
+    ports:
+        - 14000:14000 # HTTPS ACME API
+        - 15000:15000 # HTTPS Management API
+    environment:
+      - PEBBLE_VA_NOSLEEP=1
+      - PEBBLE_VA_ALWAYS_VALID=1
+    networks:
+      nginxui:
+  challtestsrv:
+    image: ghcr.io/letsencrypt/pebble-challtestsrv:latest
+    command: -defaultIPv6 "" -defaultIPv4 challtestsrv
+    ports:
+      - 8055:8055 # HTTP Management API
+    networks:
+      nginxui:
+  casdoor:
+    image: casbin/casdoor-all-in-one
+    ports:
+      - 8001:8000
+    networks:
+      - nginxui
+
+networks:
+  nginxui:

+ 25 - 0
.devcontainer/pebble-test/certs/README.md

@@ -0,0 +1,25 @@
+# certs/
+
+This directory contains a CA certificate (`pebble.minica.pem`) and a private key
+(`pebble.minica.key.pem`) that are used to issue a end-entity certificate (See
+`certs/localhost`)  for the Pebble HTTPS server.
+
+To get your **testing code** to use Pebble without HTTPS errors you should
+configure your ACME client to trust the `pebble.minica.pem` CA certificate. Your
+ACME client should offer a runtime option to specify a list of root CAs that you
+can configure to include the `pebble.minica.pem` file.
+
+**Do not** add this CA certificate to the system trust store or in production
+code!!! The CA's private key is **public** and anyone can use it to issue
+certificates that will be trusted by a system with the Pebble CA in the trust
+store.
+
+To re-create all of the Pebble certificates run:
+
+    minica -ca-cert pebble.minica.pem \
+           -ca-key pebble.minica.key.pem \
+           -domains localhost,pebble \
+           -ip-addresses 127.0.0.1
+
+From the `test/certs/` directory after [installing
+MiniCA](https://github.com/jsha/minica#installation)

+ 5 - 0
.devcontainer/pebble-test/certs/localhost/README.md

@@ -0,0 +1,5 @@
+# certs/localhost
+
+This directory contains an end-entity (leaf) certificate (`cert.pem`) and
+a private key (`key.pem`) for the Pebble HTTPS server. It includes `127.0.0.1`
+as an IP address SAN, and `[localhost, pebble]` as DNS SANs.

+ 19 - 0
.devcontainer/pebble-test/certs/localhost/cert.pem

@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDGzCCAgOgAwIBAgIIbEfayDFsBtwwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
+AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMDcx
+MjA2MTk0MjEwWjAUMRIwEAYDVQQDEwlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCbFMW3DXXdErvQf2lCZ0qz0DGEWadDoF0O2neM5mVa
+VQ7QGW0xc5Qwvn3Tl62C0JtwLpF0pG2BICIN+DHdVaIUwkf77iBS2doH1I3waE1I
+8GkV9JrYmFY+j0dA1SwBmqUZNXhLNwZGq1a91nFSI59DZNy/JciqxoPX2K++ojU2
+FPpuXe2t51NmXMsszpa+TDqF/IeskA9A/ws6UIh4Mzhghx7oay2/qqj2IIPjAmJj
+i73kdUvtEry3wmlkBvtVH50+FscS9WmPC5h3lDTk5nbzSAXKuFusotuqy3XTgY5B
+PiRAwkZbEY43JNfqenQPHo7mNTt29i+NVVrBsnAa5ovrAgMBAAGjYzBhMA4GA1Ud
+DwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0T
+AQH/BAIwADAiBgNVHREEGzAZgglsb2NhbGhvc3SCBnBlYmJsZYcEfwAAATANBgkq
+hkiG9w0BAQsFAAOCAQEAYIkXff8H28KS0KyLHtbbSOGU4sujHHVwiVXSATACsNAE
+D0Qa8hdtTQ6AUqA6/n8/u1tk0O4rPE/cTpsM3IJFX9S3rZMRsguBP7BSr1Lq/XAB
+7JP/CNHt+Z9aKCKcg11wIX9/B9F7pyKM3TdKgOpqXGV6TMuLjg5PlYWI/07lVGFW
+/mSJDRs8bSCFmbRtEqc4lpwlrpz+kTTnX6G7JDLfLWYw/xXVqwFfdengcDTHCc8K
+wtgGq/Gu6vcoBxIO3jaca+OIkMfxxXmGrcNdseuUCa3RMZ8Qy03DqGu6Y6XQyK4B
+W8zIG6H9SVKkAznM2yfYhW8v2ktcaZ95/OBHY97ZIw==
+-----END CERTIFICATE-----

+ 27 - 0
.devcontainer/pebble-test/certs/localhost/key.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEAmxTFtw113RK70H9pQmdKs9AxhFmnQ6BdDtp3jOZlWlUO0Blt
+MXOUML5905etgtCbcC6RdKRtgSAiDfgx3VWiFMJH++4gUtnaB9SN8GhNSPBpFfSa
+2JhWPo9HQNUsAZqlGTV4SzcGRqtWvdZxUiOfQ2TcvyXIqsaD19ivvqI1NhT6bl3t
+redTZlzLLM6Wvkw6hfyHrJAPQP8LOlCIeDM4YIce6Gstv6qo9iCD4wJiY4u95HVL
+7RK8t8JpZAb7VR+dPhbHEvVpjwuYd5Q05OZ280gFyrhbrKLbqst104GOQT4kQMJG
+WxGONyTX6np0Dx6O5jU7dvYvjVVawbJwGuaL6wIDAQABAoIBAGW9W/S6lO+DIcoo
+PHL+9sg+tq2gb5ZzN3nOI45BfI6lrMEjXTqLG9ZasovFP2TJ3J/dPTnrwZdr8Et/
+357YViwORVFnKLeSCnMGpFPq6YEHj7mCrq+YSURjlRhYgbVPsi52oMOfhrOIJrEG
+ZXPAwPRi0Ftqu1omQEqz8qA7JHOkjB2p0i2Xc/uOSJccCmUDMlksRYz8zFe8wHuD
+XvUL2k23n2pBZ6wiez6Xjr0wUQ4ESI02x7PmYgA3aqF2Q6ECDwHhjVeQmAuypMF6
+IaTjIJkWdZCW96pPaK1t+5nTNZ+Mg7tpJ/PRE4BkJvqcfHEOOl6wAE8gSk5uVApY
+ZRKGmGkCgYEAzF9iRXYo7A/UphL11bR0gqxB6qnQl54iLhqS/E6CVNcmwJ2d9pF8
+5HTfSo1/lOXT3hGV8gizN2S5RmWBrc9HBZ+dNrVo7FYeeBiHu+opbX1X/C1HC0m1
+wJNsyoXeqD1OFc1WbDpHz5iv4IOXzYdOdKiYEcTv5JkqE7jomqBLQk8CgYEAwkG/
+rnwr4ThUo/DG5oH+l0LVnHkrJY+BUSI33g3eQ3eM0MSbfJXGT7snh5puJW0oXP7Z
+Gw88nK3Vnz2nTPesiwtO2OkUVgrIgWryIvKHaqrYnapZHuM+io30jbZOVaVTMR9c
+X/7/d5/evwXuP7p2DIdZKQKKFgROm1XnhNqVgaUCgYBD/ogHbCR5RVsOVciMbRlG
+UGEt3YmUp/vfMuAsKUKbT2mJM+dWHVlb+LZBa4pC06QFgfxNJi/aAhzSGvtmBEww
+xsXbaceauZwxgJfIIUPfNZCMSdQVIVTi2Smcx6UofBz6i/Jw14MEwlvhamaa7qVf
+kqflYYwelga1wRNCPopLaQKBgQCWsZqZKQqBNMm0Q9yIhN+TR+2d7QFjqeePoRPl
+1qxNejhq25ojE607vNv1ff9kWUGuoqSZMUC76r6FQba/JoNbefI4otd7x/GzM9uS
+8MHMJazU4okwROkHYwgLxxkNp6rZuJJYheB4VDTfyyH/ng5lubmY7rdgTQcNyZ5I
+majRYQKBgAMKJ3RlII0qvAfNFZr4Y2bNIq+60Z+Qu2W5xokIHCFNly3W1XDDKGFe
+CCPHSvQljinke3P9gPt2HVdXxcnku9VkTti+JygxuLkVg7E0/SWwrWfGsaMJs+84
+fK+mTZay2d3v24r9WKEKwLykngYPyZw5+BdWU0E+xx5lGUd3U4gG
+-----END RSA PRIVATE KEY-----

+ 27 - 0
.devcontainer/pebble-test/certs/pebble.minica.key.pem

@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAuVoGTaFSWp3Y+N5JC8lOdL8wmWpaM73UaNzhYiqA7ZqijzVk
+TTtoQvQFDcUwyXKOdWHONrv1ld3z224Us504jjlbZwI5uoquCOZ2WJbRhmXrRgzk
+Fq+/MtoFmPkhtO/DLjjtocgyIirVXN8Yl2APvB5brvRfCm6kktYeecsWfW/O3ikf
+gdM7tmocwQiBypiloHOjdd5e2g8cWNw+rqvILSUVNLaLpsi23cxnLqVb424wz9dZ
+5dO0REg1gSxtf4N5LSb6iGuAVoFNhzIeKzQ+svDg9x8tx/DGOghJS/jDgmxSY1qo
+bTsXhcmWVfat5GJ5PQgLkCSjBBrjeBlOrc4VtQIDAQABAoIBAQCAoRoou6C0ZEDU
+DScyN8TrvlcS0LzClaWYFFmRT5/jxOG1cr8l3elwNXpgYQ2Hb6mvim2ajHxVQg/e
+oxlYwO4jvWhSJzg63c0DPjS5LAlCNO6+0Wlk2RheSPGDhLlAoPeZ10YKdS1dis5B
+Qk4Fl1O0IHlOBCcEzV4GzPOfYDI+X6/f4xY7qz1s+CgoIxjIeiG+1/WpZQpYhobY
+7CfSDdYDKtksXi7iQkc5earUAHBqZ1gQTq6e5LVm9AjRzENhMctFgcPs5zOjp2ak
+PluixrA8LTAfu9wQzvxDkPl0UarZVxCerw6nlAziILpQ+U6PtoPZj49VpntTc+cq
+1qjzkbhBAoGBANElJmFWY2X6LgBpszeqt0ZOSbkFg2bC0wHCJrMlRzUMEn83w9e8
+Z2Fqml9eCC5qxJcyxWDVQeoAX6090m0qgP8xNmGdafcVic2cUlrqtkqhhst2OHCO
+MCQEB7cdsjiidNNrOgLbQ3i1bYID8BVLf/TDhEbRgvTewDaz6XPdoSIRAoGBAOLg
+RuOec5gn50SrVycx8BLFO8AXjXojpZb1Xg26V5miz1IavSfDcgae/699ppSz+UWi
+jGMFr/PokY2JxDVs3PyQLu7ahMzyFHr16Agvp5g5kq056XV+uI/HhqLHOWSQ09DS
+1Vrj7FOYpKRzge3/AC7ty9Vr35uMiebpm4/CLFVlAoGALnsIJZfSbWaFdLgJCXUa
+WDir77/G7T6dMIXanfPJ+IMfVUCqeLa5bxAHEOzP+qjl2giBjzy18nB00warTnGk
+y5I/WMBoPW5++sAkGWqSatGtKGi0sGcZUdfHcy3ZXvbT6eyprtrWCuyfUsbXQ5RM
+8rPFIQwNA6jBpSak2ohF+FECgYEAn+6IKncNd6pRfnfmdSvf1+uPxkcUJZCxb2xC
+xByjGhvKWE+fHkPJwt8c0SIbZuJEC5Gds0RUF/XPfV4roZm/Yo9ldl02lp7kTxXA
+XtzxIP8c5d5YM8qD4l8+Csu0Kq9pkeC+JFddxkRpc8A1TIehInPhZ+6mb6mvoMb3
+MW0pAX0CgYATT74RYuIYWZvx0TK4ZXIKTw2i6HObLF63Y6UwyPXXdEVie/ToYRNH
+JIxE1weVpHvnHZvVD6D3yGk39ZsCIt31VvKpatWXlWBm875MbBc6kuIGsYT+mSSj
+y9TXaE89E5zfL27nZe15QLJ+Xw8Io6PMLZ/jtC5TYoEixSZ9J8v6HA==
+-----END RSA PRIVATE KEY-----

+ 19 - 0
.devcontainer/pebble-test/certs/pebble.minica.pem

@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDCTCCAfGgAwIBAgIIJOLbes8sTr4wDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE
+AxMVbWluaWNhIHJvb3QgY2EgMjRlMmRiMCAXDTE3MTIwNjE5NDIxMFoYDzIxMTcx
+MjA2MTk0MjEwWjAgMR4wHAYDVQQDExVtaW5pY2Egcm9vdCBjYSAyNGUyZGIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC5WgZNoVJandj43kkLyU50vzCZ
+alozvdRo3OFiKoDtmqKPNWRNO2hC9AUNxTDJco51Yc42u/WV3fPbbhSznTiOOVtn
+Ajm6iq4I5nZYltGGZetGDOQWr78y2gWY+SG078MuOO2hyDIiKtVc3xiXYA+8Hluu
+9F8KbqSS1h55yxZ9b87eKR+B0zu2ahzBCIHKmKWgc6N13l7aDxxY3D6uq8gtJRU0
+toumyLbdzGcupVvjbjDP11nl07RESDWBLG1/g3ktJvqIa4BWgU2HMh4rND6y8OD3
+Hy3H8MY6CElL+MOCbFJjWqhtOxeFyZZV9q3kYnk9CAuQJKMEGuN4GU6tzhW1AgMB
+AAGjRTBDMA4GA1UdDwEB/wQEAwIChDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB
+BQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQsFAAOCAQEAF85v
+d40HK1ouDAtWeO1PbnWfGEmC5Xa478s9ddOd9Clvp2McYzNlAFfM7kdcj6xeiNhF
+WPIfaGAi/QdURSL/6C1KsVDqlFBlTs9zYfh2g0UXGvJtj1maeih7zxFLvet+fqll
+xseM4P9EVJaQxwuK/F78YBt0tCNfivC6JNZMgxKF59h0FBpH70ytUSHXdz7FKwix
+Mfn3qEb9BXSk0Q3prNV5sOV3vgjEtB4THfDxSz9z3+DepVnW3vbbqwEbkXdk3j82
+2muVldgOUgTwK8eT+XdofVdntzU/kzygSAtAQwLJfn51fS1GvEcYGBc1bDryIqmF
+p9BI7gVKtWSZYegicA==
+-----END CERTIFICATE-----

+ 26 - 0
.devcontainer/pebble-test/config/load-generator-config.json

@@ -0,0 +1,26 @@
+{
+    "plan": {
+        "actions": [
+            "newAccount",
+            "newOrder",
+            "fulfillOrder",
+            "finalizeOrder"
+        ],
+        "rate": 10,
+        "runtime": "10s",
+        "rateDelta": "1/10s"
+    },
+    "directoryURL": "https://localhost:14000/dir",
+    "domainBase": "com",
+    "challengeStrategy": "random",
+    "httpOneAddrs": [":5002"],
+    "tlsAlpnOneAddrs": [":5001"],
+    "dnsAddrs": [":8053"],
+    "fakeDNS": "127.0.0.1",
+    "regKeySize": 2048,
+    "certKeySize": 2048,
+    "regEmail": "loadtesting@letsencrypt.org",
+    "maxRegs": 20,
+    "maxNamesPerCert": 20,
+    "dontSaveState": true
+}

+ 22 - 0
.devcontainer/pebble-test/config/pebble-config-external-account-bindings.json

@@ -0,0 +1,22 @@
+{
+  "pebble": {
+    "listenAddress": "0.0.0.0:14000",
+    "managementListenAddress": "0.0.0.0:15000",
+    "certificate": "/test/certs/localhost/cert.pem",
+    "privateKey": "/test/certs/localhost/key.pem",
+    "httpPort": 5002,
+    "tlsPort": 5001,
+    "ocspResponderURL": "",
+    "retryAfter": {
+        "authz": 3,
+        "order": 5
+    },
+    "externalAccountBindingRequired": true,
+    "externalAccountMACKeys": {
+      "kid-1": "zWNDZM6eQGHWpSRTPal5eIUYFTu7EajVIoguysqZ9wG44nMEtx3MUAsUDkMTQ12W",
+      "kid-2": "b10lLJs8l1GPIzsLP0s6pMt8O0XVGnfTaCeROxQM0BIt2XrJMDHJZBM5NuQmQJQH",
+      "kid-3": "HjudV5qnbreN-n9WyFSH-t4HXuEx_XFen45zuxY-G1h6fr74V3cUM_dVlwQZBWmc"
+    },
+    "certificateValidityPeriod": 157766400
+  }
+}

+ 27 - 0
.devcontainer/pebble-test/config/pebble-config.json

@@ -0,0 +1,27 @@
+{
+  "pebble": {
+    "listenAddress": "0.0.0.0:14000",
+    "managementListenAddress": "0.0.0.0:15000",
+    "certificate": "/test/certs/localhost/cert.pem",
+    "privateKey": "/test/certs/localhost/key.pem",
+    "httpPort": 5002,
+    "tlsPort": 5001,
+    "ocspResponderURL": "",
+    "externalAccountBindingRequired": false,
+    "domainBlocklist": ["blocked-domain.example"],
+    "retryAfter": {
+        "authz": 3,
+        "order": 5
+    },
+    "profiles": {
+      "default": {
+        "description": "The profile you know and love",
+        "validityPeriod": 7776000
+      },
+      "shortlived": {
+        "description": "A short-lived cert profile, without actual enforcement",
+        "validityPeriod": 518400
+      }
+    }
+  }
+}

+ 28 - 0
.devcontainer/start.sh

@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# install zsh-autosuggestions
+git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
+
+if ! grep -q "zsh-autosuggestions" ~/.zshrc; then
+    # add zsh-autosuggestions to plugins list
+    sed -i "/^plugins=(/s/)/ zsh-autosuggestions)/" ~/.zshrc
+fi
+
+# init nginx config dir
+if [ "$(ls -A /etc/nginx)" = "" ]; then
+    echo "Initialing Nginx config dir"
+    cp -rp /etc/nginx.orig/* /etc/nginx/
+    echo "Initialed Nginx config dir"
+fi
+
+# install app dependencies
+echo "Installing app dependencies"
+cd app && pnpm install -f
+# Build app
+pnpm build
+cd ..
+
+# install docs dependencies
+echo "Installing docs dependencies"
+cd docs && pnpm install -f
+cd ..

+ 3 - 0
.dockerignore

@@ -2,3 +2,6 @@
 app/node_modules
 .idea
 tmp
+
+.devcontainer
+.vscode

+ 3 - 1
.gitignore

@@ -12,6 +12,8 @@ nginx-ui
 resources/development/nginx
 app/.env
 app/.status_hash
-casdoor.pub
 .idea/deployment.xml
 .idea/webServers.xml
+.devcontainer/go-path
+.devcontainer/nginx
+.devcontainer/casdoor.pem

+ 48 - 0
.vscode/tasks.json

@@ -0,0 +1,48 @@
+{
+  "version": "2.0.0",
+  "tasks": [
+    {
+      "label": "Start Backend",
+      "type": "shell",
+      "command": "air",
+      "isBackground": true,
+      "presentation": {
+        "panel": "new"
+      },
+      "problemMatcher": []
+    },
+    {
+      "label": "Start Frontend",
+      "type": "shell",
+      "command": "cd app && pnpm dev",
+      "isBackground": true,
+      "presentation": {
+        "panel": "new"
+      }
+    },
+    {
+      "label": "Start Documentation",
+      "type": "shell",
+      "command": "cd docs && pnpm docs:dev",
+      "isBackground": true,
+      "presentation": {
+        "panel": "new"
+      },
+      "problemMatcher": []
+    },
+    {
+      "label": "Start All Services",
+      "dependsOrder": "parallel",
+      "dependsOn": [
+        "Start Backend",
+        "Start Frontend",
+        "Start Documentation"
+      ],
+      "group": {
+        "kind": "build",
+        "isDefault": true
+      },
+      "problemMatcher": []
+    }
+  ]
+}

+ 1 - 1
app/.env

@@ -1 +1 @@
-VITE_PROXY_TARGET=http://127.0.0.1:9001
+VITE_PROXY_TARGET=http://127.0.0.1:9000

+ 0 - 1
app/src/App.vue

@@ -4,7 +4,6 @@ import gettext from '@/gettext'
 import { useSettingsStore } from '@/pinia'
 import { theme } from 'ant-design-vue'
 import en_US from 'ant-design-vue/es/locale/en_US'
-
 import zh_CN from 'ant-design-vue/es/locale/zh_CN'
 import zh_TW from 'ant-design-vue/es/locale/zh_TW'
 // This starter template is using Vue 3 <script setup> SFCs

+ 30 - 30
docs/.vitepress/config/en.ts

@@ -1,12 +1,12 @@
-import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
-import {demoUrl} from './common'
+import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
+import { demoUrl } from './common'
 
 export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     nav: [
-      {text: 'Home', link: '/'},
-      {text: 'Guide', link: '/guide/about'},
-      {text: 'Demo', link: demoUrl}
+      { text: 'Home', link: '/' },
+      { text: 'Guide', link: '/guide/about' },
+      { text: 'Demo', link: demoUrl }
     ],
 
     sidebar: {
@@ -15,55 +15,55 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           text: 'Introduction',
           collapsed: false,
           items: [
-            {text: 'What is Nginx UI?', link: '/guide/about'},
-            {text: 'Getting Started', link: '/guide/getting-started'},
-            {text: 'Install Script', link: '/guide/install-script-linux'}
+            { text: 'What is Nginx UI?', link: '/guide/about' },
+            { text: 'Getting Started', link: '/guide/getting-started' },
+            { text: 'Install Script', link: '/guide/install-script-linux' }
           ]
         },
         {
           text: 'Development',
           collapsed: false,
           items: [
-            {text: 'Build', link: '/guide/build'},
-            {text: 'Project Structure', link: '/guide/project-structure'},
-            {text: 'Config Template', link: '/guide/nginx-ui-template'},
-            {text: 'Contributing', link: '/guide/contributing'}
+            { text: 'Build', link: '/guide/build' },
+            { text: 'Project Structure', link: '/guide/project-structure' },
+            { text: 'Config Template', link: '/guide/nginx-ui-template' },
+            { text: 'Contributing', link: '/guide/contributing' }
           ]
         },
         {
           text: 'Configuration',
           collapsed: false,
           items: [
-            {text: 'App', link: '/guide/config-app'},
-            {text: 'Server', link: '/guide/config-server'},
-            {text: 'Database', link: '/guide/config-database'},
-            {text: 'Auth', link: '/guide/config-auth'},
-            {text: 'Casdoor', link: '/guide/config-casdoor'},
-            {text: 'Cert', link: '/guide/config-cert'},
-            {text: 'Cluster', link: '/guide/config-cluster'},
-            {text: 'Crypto', link: '/guide/config-crypto'},
-            {text: 'Http', link: '/guide/config-http'},
-            {text: 'Logrotate', link: '/guide/config-logrotate'},
-            {text: 'Nginx', link: '/guide/config-nginx'},
-            {text: 'Node', link: '/guide/config-node'},
-            {text: 'Open AI', link: '/guide/config-openai'},
-            {text: 'Terminal', link: '/guide/config-terminal'},
-            {text: 'Webauthn', link: '/guide/config-webauthn'}
+            { text: 'App', link: '/guide/config-app' },
+            { text: 'Server', link: '/guide/config-server' },
+            { text: 'Database', link: '/guide/config-database' },
+            { text: 'Auth', link: '/guide/config-auth' },
+            { text: 'Casdoor', link: '/guide/config-casdoor' },
+            { text: 'Cert', link: '/guide/config-cert' },
+            { text: 'Cluster', link: '/guide/config-cluster' },
+            { text: 'Crypto', link: '/guide/config-crypto' },
+            { text: 'Http', link: '/guide/config-http' },
+            { text: 'Logrotate', link: '/guide/config-logrotate' },
+            { text: 'Nginx', link: '/guide/config-nginx' },
+            { text: 'Node', link: '/guide/config-node' },
+            { text: 'Open AI', link: '/guide/config-openai' },
+            { text: 'Terminal', link: '/guide/config-terminal' },
+            { text: 'Webauthn', link: '/guide/config-webauthn' }
           ]
         },
         {
           text: 'Environment Variables',
           collapsed: false,
           items: [
-            {text: 'Reference', link: '/guide/env'},
+            { text: 'Reference', link: '/guide/env' },
           ]
         },
         {
           text: 'Appendix',
           collapsed: false,
           items: [
-            {text: 'Nginx Proxy Example', link: '/guide/nginx-proxy-example'},
-            {text: 'License', link: '/guide/license'}
+            { text: 'Nginx Proxy Example', link: '/guide/nginx-proxy-example' },
+            { text: 'License', link: '/guide/license' }
           ]
         }
       ]

+ 9 - 3
docs/.vitepress/config/shared.ts

@@ -1,8 +1,8 @@
 import { defineConfig } from 'vitepress'
-import {projectUrl, editLinkPattern} from './common'
+import { projectUrl, editLinkPattern } from './common'
 
 export const commitRef = process.env.COMMIT_REF ?
-    `<a href="${projectUrl}/commit/${process.env.COMMIT_REF}">` + process.env.COMMIT_REF.slice(0, 8) + '</a>':
+    `<a href="${projectUrl}/commit/${process.env.COMMIT_REF}">` + process.env.COMMIT_REF.slice(0, 8) + '</a>' :
     'dev'
 
 function thisYear() {
@@ -37,7 +37,13 @@ export const sharedConfig = defineConfig({
         },
 
         socialLinks: [
-            {icon: 'github', link: projectUrl}
+            { icon: 'github', link: projectUrl }
         ]
+    },
+
+    vite: {
+        server: {
+            port: Number.parseInt(process.env.VITE_PORT ?? '3003')
+        }
     }
 })

+ 30 - 30
docs/.vitepress/config/zh_CN.ts

@@ -1,12 +1,12 @@
-import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
-import {demoUrl, editLinkPattern} from './common'
+import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
+import { demoUrl, editLinkPattern } from './common'
 
 export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     nav: [
-      {text: '首页', link: '/zh_CN/'},
-      {text: '手册', link: '/zh_CN/guide/about'},
-      {text: '演示', link: demoUrl}
+      { text: '首页', link: '/zh_CN/' },
+      { text: '手册', link: '/zh_CN/guide/about' },
+      { text: '演示', link: demoUrl }
     ],
 
     editLink: {
@@ -20,55 +20,55 @@ export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           text: '介绍',
           collapsed: false,
           items: [
-            {text: '何为 Nginx UI?', link: '/zh_CN/guide/about'},
-            {text: '即刻开始', link: '/zh_CN/guide/getting-started'},
-            {text: '安装脚本', link: '/zh_CN/guide/install-script-linux'}
+            { text: '何为 Nginx UI?', link: '/zh_CN/guide/about' },
+            { text: '即刻开始', link: '/zh_CN/guide/getting-started' },
+            { text: '安装脚本', link: '/zh_CN/guide/install-script-linux' }
           ]
         },
         {
           text: '开发',
           collapsed: false,
           items: [
-            {text: '构建', link: '/zh_CN/guide/build'},
-            {text: '项目结构', link: '/zh_CN/guide/project-structure'},
-            {text: '配置模板', link: '/zh_CN/guide/nginx-ui-template'},
-            {text: '贡献代码', link: '/zh_CN/guide/contributing'}
+            { text: '构建', link: '/zh_CN/guide/build' },
+            { text: '项目结构', link: '/zh_CN/guide/project-structure' },
+            { text: '配置模板', link: '/zh_CN/guide/nginx-ui-template' },
+            { text: '贡献代码', link: '/zh_CN/guide/contributing' }
           ]
         },
         {
           text: '配置',
           collapsed: false,
           items: [
-            {text: 'App', link: '/zh_CN/guide/config-app'},
-            {text: 'Server', link: '/zh_CN/guide/config-server'},
-            {text: 'Database', link: '/zh_CN/guide/config-database'},
-            {text: 'Auth', link: '/zh_CN/guide/config-auth'},
-            {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
-            {text: 'Cert', link: '/zh_CN/guide/config-cert'},
-            {text: 'Cluster', link: '/zh_CN/guide/config-cluster'},
-            {text: 'Crypto', link: '/zh_CN/guide/config-crypto'},
-            {text: 'Http', link: '/zh_CN/guide/config-http'},
-            {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'},
-            {text: 'Nginx', link: '/zh_CN/guide/config-nginx'},
-            {text: 'Node', link: '/zh_CN/guide/config-node'},
-            {text: 'Open AI', link: '/zh_CN/guide/config-openai'},
-            {text: 'Terminal', link: '/zh_CN/guide/config-terminal'},
-            {text: 'Webauthn', link: '/zh_CN/guide/config-webauthn'}
+            { text: 'App', link: '/zh_CN/guide/config-app' },
+            { text: 'Server', link: '/zh_CN/guide/config-server' },
+            { text: 'Database', link: '/zh_CN/guide/config-database' },
+            { text: 'Auth', link: '/zh_CN/guide/config-auth' },
+            { text: 'Casdoor', link: '/zh_CN/guide/config-casdoor' },
+            { text: 'Cert', link: '/zh_CN/guide/config-cert' },
+            { text: 'Cluster', link: '/zh_CN/guide/config-cluster' },
+            { text: 'Crypto', link: '/zh_CN/guide/config-crypto' },
+            { text: 'Http', link: '/zh_CN/guide/config-http' },
+            { text: 'Logrotate', link: '/zh_CN/guide/config-logrotate' },
+            { text: 'Nginx', link: '/zh_CN/guide/config-nginx' },
+            { text: 'Node', link: '/zh_CN/guide/config-node' },
+            { text: 'Open AI', link: '/zh_CN/guide/config-openai' },
+            { text: 'Terminal', link: '/zh_CN/guide/config-terminal' },
+            { text: 'Webauthn', link: '/zh_CN/guide/config-webauthn' }
           ]
         },
         {
           text: '环境变量',
           collapsed: false,
           items: [
-            {text: '参考手册', link: '/zh_CN/guide/env'},
+            { text: '参考手册', link: '/zh_CN/guide/env' },
           ]
         },
         {
           text: '附录',
           collapsed: false,
           items: [
-            {text: 'Nginx 代理示例', link: '/zh_CN/guide/nginx-proxy-example'},
-            {text: '开源协议', link: '/zh_CN/guide/license'}
+            { text: 'Nginx 代理示例', link: '/zh_CN/guide/nginx-proxy-example' },
+            { text: '开源协议', link: '/zh_CN/guide/license' }
           ]
         }
       ]

+ 30 - 30
docs/.vitepress/config/zh_TW.ts

@@ -1,12 +1,12 @@
-import {LocaleSpecificConfig, DefaultTheme} from 'vitepress'
-import {demoUrl, editLinkPattern} from './common'
+import { LocaleSpecificConfig, DefaultTheme } from 'vitepress'
+import { demoUrl, editLinkPattern } from './common'
 
 export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
   themeConfig: {
     nav: [
-      {text: '首頁', link: '/zh_TW/'},
-      {text: '手冊', link: '/zh_TW/guide/about'},
-      {text: '演示', link: demoUrl}
+      { text: '首頁', link: '/zh_TW/' },
+      { text: '手冊', link: '/zh_TW/guide/about' },
+      { text: '演示', link: demoUrl }
     ],
 
     editLink: {
@@ -20,55 +20,55 @@ export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
           text: '介紹',
           collapsed: false,
           items: [
-            {text: '何為 Nginx UI?', link: '/zh_TW/guide/about'},
-            {text: '即刻開始', link: '/zh_TW/guide/getting-started'},
-            {text: '安裝指令碼', link: '/zh_TW/guide/install-script-linux'}
+            { text: '何為 Nginx UI?', link: '/zh_TW/guide/about' },
+            { text: '即刻開始', link: '/zh_TW/guide/getting-started' },
+            { text: '安裝指令碼', link: '/zh_TW/guide/install-script-linux' }
           ]
         },
         {
           text: '開發',
           collapsed: false,
           items: [
-            {text: '構建', link: '/zh_TW/guide/build'},
-            {text: '專案結構', link: '/zh_TW/guide/project-structure'},
-            {text: '配置模板', link: '/zh_TW/guide/nginx-ui-template'},
-            {text: '貢獻程式碼', link: '/zh_TW/guide/contributing'}
+            { text: '構建', link: '/zh_TW/guide/build' },
+            { text: '專案結構', link: '/zh_TW/guide/project-structure' },
+            { text: '配置模板', link: '/zh_TW/guide/nginx-ui-template' },
+            { text: '貢獻程式碼', link: '/zh_TW/guide/contributing' }
           ]
         },
         {
           text: '配置',
           collapsed: false,
           items: [
-            {text: 'App', link: '/zh_TW/guide/config-app'},
-            {text: 'Server', link: '/zh_TW/guide/config-server'},
-            {text: 'Database', link: '/zh_TW/guide/config-database'},
-            {text: 'Auth', link: '/zh_TW/guide/config-auth'},
-            {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
-            {text: 'Cert', link: '/zh_TW/guide/config-cert'},
-            {text: 'Cluster', link: '/zh_TW/guide/config-cluster'},
-            {text: 'Crypto', link: '/zh_TW/guide/config-crypto'},
-            {text: 'Http', link: '/zh_TW/guide/config-http'},
-            {text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'},
-            {text: 'Nginx', link: '/zh_TW/guide/config-nginx'},
-            {text: 'Node', link: '/zh_TW/guide/config-node'},
-            {text: 'Open AI', link: '/zh_TW/guide/config-openai'},
-            {text: 'Terminal', link: '/zh_TW/guide/config-terminal'},
-            {text: 'Webauthn', link: '/zh_TW/guide/config-webauthn'}
+            { text: 'App', link: '/zh_TW/guide/config-app' },
+            { text: 'Server', link: '/zh_TW/guide/config-server' },
+            { text: 'Database', link: '/zh_TW/guide/config-database' },
+            { text: 'Auth', link: '/zh_TW/guide/config-auth' },
+            { text: 'Casdoor', link: '/zh_TW/guide/config-casdoor' },
+            { text: 'Cert', link: '/zh_TW/guide/config-cert' },
+            { text: 'Cluster', link: '/zh_TW/guide/config-cluster' },
+            { text: 'Crypto', link: '/zh_TW/guide/config-crypto' },
+            { text: 'Http', link: '/zh_TW/guide/config-http' },
+            { text: 'Logrotate', link: '/zh_TW/guide/config-logrotate' },
+            { text: 'Nginx', link: '/zh_TW/guide/config-nginx' },
+            { text: 'Node', link: '/zh_TW/guide/config-node' },
+            { text: 'Open AI', link: '/zh_TW/guide/config-openai' },
+            { text: 'Terminal', link: '/zh_TW/guide/config-terminal' },
+            { text: 'Webauthn', link: '/zh_TW/guide/config-webauthn' }
           ]
         },
         {
           text: '環境變量',
           collapsed: false,
           items: [
-            {text: '參考手冊', link: '/zh_TW/guide/env'},
+            { text: '參考手冊', link: '/zh_TW/guide/env' },
           ]
         },
         {
           text: '附錄',
           collapsed: false,
           items: [
-            {text: 'Nginx 代理示例', link: '/zh_TW/guide/nginx-proxy-example'},
-            {text: '開源協議', link: '/zh_TW/guide/license'}
+            { text: 'Nginx 代理示例', link: '/zh_TW/guide/nginx-proxy-example' },
+            { text: '開源協議', link: '/zh_TW/guide/license' }
           ]
         }
       ]

+ 1 - 1
docs/package.json

@@ -2,7 +2,7 @@
   "name": "nginx-ui-docs",
   "type": "module",
   "scripts": {
-    "docs:dev": "vitepress dev",
+    "docs:dev": "vitepress dev --host",
     "docs:build": "vitepress build",
     "docs:preview": "vitepress preview"
   },

+ 0 - 13
resources/development/entrypoint.sh

@@ -1,13 +0,0 @@
-#!/bin/bash
-
-if [ "$(ls -A /etc/nginx)" = "" ]; then
-    echo "Initialing Nginx config dir"
-    cp -rp /usr/etc/nginx/* /etc/nginx/
-    echo "Initialed Nginx config dir"
-fi
-
-echo "export PATH=$PATH:/usr/local/go/bin:$(go env GOPATH)/bin" >> ~/.profile
-source ~/.profile
-
-nginx
-cd /app && air

+ 0 - 9
resources/development/sources.list

@@ -1,9 +0,0 @@
-# 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
-deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
-# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse
-deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
-# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse
-deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
-# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse
-deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
-# deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse