mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-10 13:36:45 +03:00
Merge pull request #13 from arunavo4/fix-bun-permissions-in-lxc
Fix Bun permissions issue in LXC container installer
This commit is contained in:
@@ -49,6 +49,6 @@ VOLUME /app/data
|
|||||||
EXPOSE 4321
|
EXPOSE 4321
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
||||||
CMD wget --no-verbose --tries=1 --spider http://localhost:4321/ || exit 1
|
CMD wget --no-verbose --tries=1 --spider http://localhost:4321/api/health || exit 1
|
||||||
|
|
||||||
ENTRYPOINT ["./docker-entrypoint.sh"]
|
ENTRYPOINT ["./docker-entrypoint.sh"]
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -19,8 +19,12 @@ docker compose --profile production up -d
|
|||||||
# Using Bun
|
# Using Bun
|
||||||
bun run setup && bun run dev
|
bun run setup && bun run dev
|
||||||
|
|
||||||
# Using LXC on Proxmox
|
# Using LXC Containers
|
||||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
# For Proxmox VE (online)
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-proxmox.sh | bash
|
||||||
|
|
||||||
|
# For local testing (offline-friendly)
|
||||||
|
sudo LOCAL_REPO_DIR=~/Development/gitea-mirror ./scripts/gitea-mirror-lxc-local.sh
|
||||||
````
|
````
|
||||||
|
|
||||||
See the [LXC Container Deployment Guide](scripts/README-lxc.md).
|
See the [LXC Container Deployment Guide](scripts/README-lxc.md).
|
||||||
@@ -163,21 +167,37 @@ docker compose --profile production up -d
|
|||||||
|
|
||||||
See [Docker build documentation](./scripts/README-docker.md) for more details.
|
See [Docker build documentation](./scripts/README-docker.md) for more details.
|
||||||
|
|
||||||
##### Using LXC Containers (for Proxmox Homelab Setups)
|
##### Using LXC Containers
|
||||||
|
|
||||||
Gitea Mirror can be deployed on Proxmox LXC containers, which is ideal for homelab setups:
|
Gitea Mirror offers two deployment options for LXC containers:
|
||||||
|
|
||||||
|
**1. Proxmox VE (online, recommended for production)**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# One-command installation on an Ubuntu 22.04 LXC container
|
# One-command installation on Proxmox VE
|
||||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
# Optional env overrides: CTID HOSTNAME STORAGE DISK_SIZE CORES MEMORY BRIDGE IP_CONF
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-proxmox.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
The installer script:
|
**2. Local testing (offline-friendly, works on developer laptops)**
|
||||||
- Downloads the Gitea Mirror repository
|
|
||||||
- Installs all dependencies including Bun
|
```bash
|
||||||
- Builds the application
|
# Download the script
|
||||||
- Sets up a systemd service
|
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-local.sh -o gitea-mirror-lxc-local.sh
|
||||||
- Starts the application
|
chmod +x gitea-mirror-lxc-local.sh
|
||||||
|
|
||||||
|
# Run with your local repo directory
|
||||||
|
sudo LOCAL_REPO_DIR=~/Development/gitea-mirror ./gitea-mirror-lxc-local.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Both scripts:
|
||||||
|
- Set up a privileged Ubuntu 22.04 LXC container
|
||||||
|
- Install Bun runtime environment
|
||||||
|
- Build the application
|
||||||
|
- Configure a systemd service
|
||||||
|
- Start the service automatically
|
||||||
|
|
||||||
|
The application includes a health check endpoint at `/api/health` for monitoring.
|
||||||
|
|
||||||
See the [LXC Container Deployment Guide](scripts/README-lxc.md) for detailed instructions.
|
See the [LXC Container Deployment Guide](scripts/README-lxc.md) for detailed instructions.
|
||||||
|
|
||||||
@@ -379,7 +399,7 @@ docker compose -f docker-compose.dev.yml up -d
|
|||||||
- **Backend**: Bun
|
- **Backend**: Bun
|
||||||
- **Database**: SQLite (handles both data storage and event notifications)
|
- **Database**: SQLite (handles both data storage and event notifications)
|
||||||
- **API Integration**: GitHub API (Octokit), Gitea API
|
- **API Integration**: GitHub API (Octokit), Gitea API
|
||||||
- **Deployment Options**: Docker containers, Proxmox LXC containers
|
- **Deployment Options**: Docker containers, LXC containers (Proxmox VE and local testing)
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
97
bun.lock
97
bun.lock
@@ -40,7 +40,6 @@
|
|||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"sqlite3": "^5.1.7",
|
|
||||||
"superagent": "^10.2.1",
|
"superagent": "^10.2.1",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
@@ -637,7 +636,7 @@
|
|||||||
|
|
||||||
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
"chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
|
||||||
|
|
||||||
"chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
"chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
||||||
|
|
||||||
"ci-info": ["ci-info@4.2.0", "", {}, "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg=="],
|
"ci-info": ["ci-info@4.2.0", "", {}, "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg=="],
|
||||||
|
|
||||||
@@ -1187,7 +1186,7 @@
|
|||||||
|
|
||||||
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
||||||
|
|
||||||
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
"minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
||||||
|
|
||||||
"minipass-collect": ["minipass-collect@1.0.2", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA=="],
|
"minipass-collect": ["minipass-collect@1.0.2", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA=="],
|
||||||
|
|
||||||
@@ -1199,9 +1198,9 @@
|
|||||||
|
|
||||||
"minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="],
|
"minipass-sized": ["minipass-sized@1.0.3", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g=="],
|
||||||
|
|
||||||
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
"minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
||||||
|
|
||||||
"mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
"mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
||||||
|
|
||||||
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
|
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
|
||||||
|
|
||||||
@@ -1491,7 +1490,7 @@
|
|||||||
|
|
||||||
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
"tapable": ["tapable@2.2.2", "", {}, "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg=="],
|
||||||
|
|
||||||
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
"tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
||||||
|
|
||||||
"tar-fs": ["tar-fs@2.1.2", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA=="],
|
"tar-fs": ["tar-fs@2.1.2", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA=="],
|
||||||
|
|
||||||
@@ -1643,7 +1642,7 @@
|
|||||||
|
|
||||||
"xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
|
"xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="],
|
||||||
|
|
||||||
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
"yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
||||||
|
|
||||||
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
|
||||||
|
|
||||||
@@ -1667,7 +1666,7 @@
|
|||||||
|
|
||||||
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
"@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
|
||||||
|
|
||||||
"@isaacs/fs-minipass/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
"@npmcli/move-file/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||||
|
|
||||||
"@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
|
"@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="],
|
||||||
|
|
||||||
@@ -1675,8 +1674,6 @@
|
|||||||
|
|
||||||
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
"@rollup/pluginutils/estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar": ["tar@7.4.3", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.0.1", "mkdirp": "^3.0.1", "yallist": "^5.0.0" } }, "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.4.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||||
@@ -1701,10 +1698,16 @@
|
|||||||
|
|
||||||
"boxen/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
"boxen/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
|
||||||
|
|
||||||
|
"cacache/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
||||||
|
|
||||||
"cacache/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
|
"cacache/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
|
||||||
|
|
||||||
"cacache/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"cacache/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
|
"cacache/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||||
|
|
||||||
|
"cacache/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
||||||
|
|
||||||
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"gauge/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
"gauge/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
||||||
@@ -1725,16 +1728,18 @@
|
|||||||
|
|
||||||
"minipass-fetch/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-fetch/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
|
"minipass-fetch/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||||
|
|
||||||
"minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"minipass-sized/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
|
||||||
|
|
||||||
"node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
"node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="],
|
||||||
|
|
||||||
|
"node-gyp/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
||||||
|
|
||||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||||
|
|
||||||
"pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
"pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
||||||
@@ -1745,6 +1750,8 @@
|
|||||||
|
|
||||||
"socks-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
"socks-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||||
|
|
||||||
|
"sqlite3/tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
||||||
|
|
||||||
"ssri/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
"ssri/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
"strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
"strip-ansi/ansi-regex": ["ansi-regex@6.1.0", "", {}, "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA=="],
|
||||||
@@ -1761,34 +1768,80 @@
|
|||||||
|
|
||||||
"@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
"@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar/chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar/minipass": ["minipass@7.1.2", "", {}, "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar/minizlib": ["minizlib@3.0.2", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar/mkdirp": ["mkdirp@3.0.1", "", { "bin": { "mkdirp": "dist/cjs/src/bin.js" } }, "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg=="],
|
|
||||||
|
|
||||||
"@tailwindcss/oxide/tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="],
|
|
||||||
|
|
||||||
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"cacache/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"cacache/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"cacache/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
||||||
|
|
||||||
|
"cacache/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||||
|
|
||||||
|
"cacache/tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"fs-minipass/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
"gauge/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"gauge/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
"make-fetch-happen/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
"make-fetch-happen/http-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||||
|
|
||||||
"make-fetch-happen/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
"make-fetch-happen/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
|
||||||
|
|
||||||
|
"make-fetch-happen/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"make-fetch-happen/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-collect/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-fetch/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-fetch/minizlib/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"minipass-sized/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
"node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
"node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
|
||||||
|
|
||||||
"node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
"node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
"send/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
|
"ssri/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
||||||
|
|
||||||
"wide-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
"wide-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
|
||||||
|
|
||||||
"wide-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
"wide-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
||||||
|
|
||||||
|
"cacache/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
|
"node-gyp/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
|
|
||||||
|
"sqlite3/tar/minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
- DATABASE_URL=sqlite://data/gitea-mirror.db
|
- DATABASE_URL=sqlite://data/gitea-mirror.db
|
||||||
- DELAY=${DELAY:-3600}
|
- DELAY=${DELAY:-3600}
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:4321/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:4321/api/health"]
|
||||||
interval: 1m
|
interval: 1m
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|||||||
@@ -61,7 +61,6 @@
|
|||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"sonner": "^2.0.3",
|
"sonner": "^2.0.3",
|
||||||
"sqlite3": "^5.1.7",
|
|
||||||
"superagent": "^10.2.1",
|
"superagent": "^10.2.1",
|
||||||
"tailwind-merge": "^3.3.0",
|
"tailwind-merge": "^3.3.0",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
|
|||||||
@@ -1,109 +1,117 @@
|
|||||||
# LXC Container Deployment Guide
|
# LXC Container Deployment Guide
|
||||||
|
|
||||||
This guide explains how to deploy the Gitea Mirror application on Proxmox LXC containers while keeping your existing Docker containers.
|
## Overview
|
||||||
|
Run **Gitea Mirror** in an isolated LXC container, either:
|
||||||
|
|
||||||
## Prerequisites
|
1. **Online, on a Proxmox VE host** – script pulls everything from GitHub
|
||||||
|
2. **Offline / LAN-only, on a developer laptop** – script pushes your local checkout + Bun ZIP
|
||||||
|
|
||||||
- Proxmox VE installed and configured
|
---
|
||||||
- Basic knowledge of LXC containers and Proxmox
|
|
||||||
- Access to Proxmox web interface or CLI
|
|
||||||
|
|
||||||
## Creating an LXC Container
|
## 1. Proxmox VE (online, recommended for prod)
|
||||||
|
|
||||||
1. In Proxmox web interface, create a new LXC container:
|
### Prerequisites
|
||||||
- Choose Ubuntu 22.04 as the template
|
* Proxmox VE node with the default `vmbr0` bridge
|
||||||
- Allocate appropriate resources (2GB RAM, 2 CPU cores recommended)
|
* Root shell on the node
|
||||||
- At least 10GB of disk space
|
* Ubuntu 22.04 LXC template present (`pveam update && pveam download ...`)
|
||||||
- Configure networking as needed
|
|
||||||
|
|
||||||
2. Start the container and get a shell (either via Proxmox web console or SSH)
|
### One-command install
|
||||||
|
|
||||||
## Deploying Gitea Mirror
|
```bash
|
||||||
|
# optional env overrides: CTID HOSTNAME STORAGE DISK_SIZE CORES MEMORY BRIDGE IP_CONF
|
||||||
|
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-proxmox.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
### Option 1: One-Command Installation (Recommended)
|
What it does:
|
||||||
|
|
||||||
This method allows you to install Gitea Mirror with a single command, without having to copy files manually:
|
* Creates **privileged** CT `$CTID` with nesting enabled
|
||||||
|
* Installs curl / git / Bun (official installer)
|
||||||
|
* Clones & builds `arunavo4/gitea-mirror`
|
||||||
|
* Writes a root-run systemd service and starts it
|
||||||
|
* Prints the container IP + random `JWT_SECRET`
|
||||||
|
|
||||||
1. SSH into your LXC container:
|
Browse to:
|
||||||
```bash
|
|
||||||
ssh root@lxc-container-ip
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Run the installer script directly:
|
```
|
||||||
```bash
|
http://<container-ip>:4321
|
||||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
```
|
||||||
```
|
|
||||||
|
|
||||||
3. The installer will:
|
---
|
||||||
- Download the Gitea Mirror repository
|
|
||||||
- Install all dependencies including Bun
|
|
||||||
- Build the application
|
|
||||||
- Set up a systemd service
|
|
||||||
- Start the application
|
|
||||||
- Display access information
|
|
||||||
|
|
||||||
### Option 2: Manual Setup
|
## 2. Local testing (LXD on a workstation, works offline)
|
||||||
|
|
||||||
If you prefer to set up manually or the automatic script doesn't work for your environment:
|
### Prerequisites
|
||||||
|
|
||||||
1. Install dependencies:
|
* `lxd` installed (`sudo apt install lxd`; `lxd init --auto`)
|
||||||
```bash
|
* Your repo cloned locally – e.g. `~/Development/gitea-mirror`
|
||||||
apt update
|
* Bun ZIP downloaded once:
|
||||||
apt install -y curl git sqlite3 build-essential
|
`https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip`
|
||||||
```
|
|
||||||
|
|
||||||
2. Install Bun:
|
### Offline installer script
|
||||||
```bash
|
|
||||||
curl -fsSL https://bun.sh/install | bash
|
|
||||||
export BUN_INSTALL="/root/.bun"
|
|
||||||
export PATH="$BUN_INSTALL/bin:$PATH"
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Clone or copy your project:
|
```bash
|
||||||
```bash
|
git clone https://github.com/arunavo4/gitea-mirror.git # if not already
|
||||||
git clone https://github.com/yourusername/gitea-mirror.git /opt/gitea-mirror
|
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-local.sh -o gitea-mirror-lxc-local.sh
|
||||||
cd /opt/gitea-mirror
|
chmod +x gitea-mirror-lxc-local.sh
|
||||||
```
|
|
||||||
|
|
||||||
4. Build and initialize:
|
sudo LOCAL_REPO_DIR=~/Development/gitea-mirror \
|
||||||
```bash
|
./gitea-mirror-lxc-local.sh
|
||||||
bun install
|
```
|
||||||
bun run build
|
|
||||||
bun run manage-db init
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Create a systemd service manually:
|
What it does:
|
||||||
```bash
|
|
||||||
nano /etc/systemd/system/gitea-mirror.service
|
|
||||||
# Add the service configuration as shown below:
|
|
||||||
|
|
||||||
[Unit]
|
* Launches privileged LXC `gitea-test` (`lxc launch ubuntu:22.04 ...`)
|
||||||
Description=Gitea Mirror
|
* Pushes **Bun ZIP** + tarred **local repo** into `/opt`
|
||||||
After=network.target
|
* Unpacks, builds, initializes DB
|
||||||
|
* Symlinks both `bun` and `bunx` → `/usr/local/bin`
|
||||||
|
* Creates a root systemd unit and starts it
|
||||||
|
|
||||||
[Service]
|
Access from host:
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=/opt/gitea-mirror
|
|
||||||
ExecStart=/root/.bun/bin/bun dist/server/entry.mjs
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=gitea-mirror
|
|
||||||
Group=gitea-mirror
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=HOST=0.0.0.0
|
|
||||||
Environment=PORT=4321
|
|
||||||
Environment=DATABASE_URL=file:data/gitea-mirror.db
|
|
||||||
Environment=JWT_SECRET=your-secure-secret-key
|
|
||||||
|
|
||||||
[Install]
|
```
|
||||||
WantedBy=multi-user.target
|
http://$(lxc exec gitea-test -- hostname -I | awk '{print $1}'):4321
|
||||||
```
|
```
|
||||||
|
|
||||||
6. Enable and start the service:
|
(Optional) forward to host localhost:
|
||||||
```bash
|
|
||||||
systemctl enable gitea-mirror.service
|
```bash
|
||||||
systemctl start gitea-mirror.service
|
sudo lxc config device add gitea-test mirror proxy \
|
||||||
```
|
listen=tcp:0.0.0.0:4321 connect=tcp:127.0.0.1:4321
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Health-check endpoint
|
||||||
|
|
||||||
|
Gitea Mirror includes a built-in health check endpoint at `/api/health` that provides:
|
||||||
|
|
||||||
|
- System status and uptime
|
||||||
|
- Database connectivity check
|
||||||
|
- Memory usage statistics
|
||||||
|
- Environment information
|
||||||
|
|
||||||
|
You can use this endpoint for monitoring your deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic check (returns 200 OK if healthy)
|
||||||
|
curl -I http://<container-ip>:4321/api/health
|
||||||
|
|
||||||
|
# Detailed health information (JSON)
|
||||||
|
curl http://<container-ip>:4321/api/health
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
| Check | Command |
|
||||||
|
| -------------- | ----------------------------------------------------- |
|
||||||
|
| Service status | `systemctl status gitea-mirror` |
|
||||||
|
| Live logs | `journalctl -u gitea-mirror -f` |
|
||||||
|
| Verify Bun | `bun --version && bunx --version` |
|
||||||
|
| DB perms | `chown -R root:root /opt/gitea-mirror/data` (Proxmox) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Connecting LXC and Docker Containers
|
## Connecting LXC and Docker Containers
|
||||||
|
|
||||||
@@ -121,32 +129,3 @@ If you need your LXC container to communicate with Docker containers:
|
|||||||
```
|
```
|
||||||
|
|
||||||
3. In Proxmox, edit the LXC container's network configuration to use this bridge.
|
3. In Proxmox, edit the LXC container's network configuration to use this bridge.
|
||||||
|
|
||||||
## Accessing the Application
|
|
||||||
|
|
||||||
Once deployed, you can access the Gitea Mirror application at:
|
|
||||||
```
|
|
||||||
http://lxc-container-ip:4321
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
- Check service status:
|
|
||||||
```bash
|
|
||||||
systemctl status gitea-mirror
|
|
||||||
```
|
|
||||||
|
|
||||||
- View logs:
|
|
||||||
```bash
|
|
||||||
journalctl -u gitea-mirror -f
|
|
||||||
```
|
|
||||||
|
|
||||||
- If the service fails to start, check permissions on the data directory:
|
|
||||||
```bash
|
|
||||||
chown -R gitea-mirror:gitea-mirror /opt/gitea-mirror/data
|
|
||||||
```
|
|
||||||
|
|
||||||
- Verify Bun is installed correctly:
|
|
||||||
```bash
|
|
||||||
bun --version
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
# Scripts Directory
|
# Scripts Directory
|
||||||
|
|
||||||
This folder contains utility scripts for database management.
|
This folder contains utility scripts for database management, event management, Docker builds, and LXC container deployment.
|
||||||
|
|
||||||
## Database Management Tool (manage-db.ts)
|
## Database Management
|
||||||
|
|
||||||
|
### Database Management Tool (manage-db.ts)
|
||||||
|
|
||||||
This is a consolidated database management tool that handles all database-related operations. It combines the functionality of the previous separate scripts into a single, more intelligent script that can check, fix, and initialize the database as needed.
|
This is a consolidated database management tool that handles all database-related operations. It combines the functionality of the previous separate scripts into a single, more intelligent script that can check, fix, and initialize the database as needed.
|
||||||
|
|
||||||
### Features
|
#### Features
|
||||||
|
|
||||||
- **Check Mode**: Validates the existence and integrity of the database
|
- **Check Mode**: Validates the existence and integrity of the database
|
||||||
- **Init Mode**: Creates the database only if it doesn't already exist
|
- **Init Mode**: Creates the database only if it doesn't already exist
|
||||||
@@ -14,12 +16,12 @@ This is a consolidated database management tool that handles all database-relate
|
|||||||
- **Reset Users Mode**: Removes all users and their data
|
- **Reset Users Mode**: Removes all users and their data
|
||||||
- **Auto Mode**: Automatically checks, fixes, and initializes the database if needed
|
- **Auto Mode**: Automatically checks, fixes, and initializes the database if needed
|
||||||
|
|
||||||
## Running the Database Management Tool
|
#### Running the Database Management Tool
|
||||||
|
|
||||||
You can execute the database management tool using your package manager with various commands:
|
You can execute the database management tool using your package manager with various commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Checks database status (default action if no command is specified, equivalent to 'bun run check-db')
|
# Checks database status (default action if no command is specified)
|
||||||
bun run manage-db
|
bun run manage-db
|
||||||
|
|
||||||
# Check database status
|
# Check database status
|
||||||
@@ -37,9 +39,6 @@ bun run db-auto
|
|||||||
# Reset all users (for testing signup flow)
|
# Reset all users (for testing signup flow)
|
||||||
bun run reset-users
|
bun run reset-users
|
||||||
|
|
||||||
# Update the database schema to the latest version
|
|
||||||
bun run update-schema
|
|
||||||
|
|
||||||
# Remove database files completely
|
# Remove database files completely
|
||||||
bun run cleanup-db
|
bun run cleanup-db
|
||||||
|
|
||||||
@@ -53,6 +52,70 @@ bun run dev:clean
|
|||||||
bun run start:fresh
|
bun run start:fresh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database File Location
|
#### Database File Location
|
||||||
|
|
||||||
The database file should be located in the `./data/gitea-mirror.db` directory. If the file is found in the root directory, the fix mode will move it to the correct location.
|
The database file should be located in the `./data/gitea-mirror.db` directory. If the file is found in the root directory, the fix mode will move it to the correct location.
|
||||||
|
|
||||||
|
## Event Management
|
||||||
|
|
||||||
|
The following scripts help manage events in the SQLite database:
|
||||||
|
|
||||||
|
### Event Inspection (check-events.ts)
|
||||||
|
|
||||||
|
Displays all events currently stored in the database.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun scripts/check-events.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Cleanup (cleanup-events.ts)
|
||||||
|
|
||||||
|
Removes old events from the database to prevent it from growing too large.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove events older than 7 days (default)
|
||||||
|
bun scripts/cleanup-events.ts
|
||||||
|
|
||||||
|
# Remove events older than X days
|
||||||
|
bun scripts/cleanup-events.ts 14
|
||||||
|
```
|
||||||
|
|
||||||
|
This script can be scheduled to run periodically (e.g., daily) using cron or another scheduler.
|
||||||
|
|
||||||
|
### Mark Events as Read (mark-events-read.ts)
|
||||||
|
|
||||||
|
Marks all unread events as read.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun scripts/mark-events-read.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Make Events Appear Older (make-events-old.ts)
|
||||||
|
|
||||||
|
For testing purposes, this script modifies event timestamps to make them appear older.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun scripts/make-events-old.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deployment Scripts
|
||||||
|
|
||||||
|
### Docker Deployment
|
||||||
|
|
||||||
|
- **build-docker.sh**: Builds the Docker image for the application
|
||||||
|
- **docker-diagnostics.sh**: Provides diagnostic information for Docker deployments
|
||||||
|
|
||||||
|
### LXC Container Deployment
|
||||||
|
|
||||||
|
Two scripts are provided for deploying Gitea Mirror in LXC containers:
|
||||||
|
|
||||||
|
1. **gitea-mirror-lxc-proxmox.sh**: For online deployment on a Proxmox VE host
|
||||||
|
- Pulls everything from GitHub
|
||||||
|
- Creates a privileged container with the application
|
||||||
|
- Sets up systemd service
|
||||||
|
|
||||||
|
2. **gitea-mirror-lxc-local.sh**: For offline/LAN-only deployment on a developer laptop
|
||||||
|
- Pushes your local checkout + Bun ZIP to the container
|
||||||
|
- Useful for testing without internet access
|
||||||
|
|
||||||
|
For detailed instructions on LXC deployment, see [README-lxc.md](./README-lxc.md).
|
||||||
|
|||||||
@@ -1,188 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Gitea Mirror LXC Container Installer
|
|
||||||
# This is a self-contained script to install Gitea Mirror in an LXC container
|
|
||||||
# Usage: curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Configuration variables - change these as needed
|
|
||||||
INSTALL_DIR="/opt/gitea-mirror"
|
|
||||||
REPO_URL="https://github.com/arunavo4/gitea-mirror.git"
|
|
||||||
SERVICE_USER="gitea-mirror"
|
|
||||||
PORT=4321
|
|
||||||
|
|
||||||
# Color codes for better readability
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
# Print banner
|
|
||||||
echo -e "${BLUE}"
|
|
||||||
echo "╔════════════════════════════════════════════════════════════╗"
|
|
||||||
echo "║ ║"
|
|
||||||
echo "║ Gitea Mirror LXC Container Installer ║"
|
|
||||||
echo "║ ║"
|
|
||||||
echo "╚════════════════════════════════════════════════════════════╝"
|
|
||||||
echo -e "${NC}"
|
|
||||||
|
|
||||||
# Ensure script is run as root
|
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
|
||||||
echo -e "${RED}This script must be run as root${NC}" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}Starting Gitea Mirror installation...${NC}"
|
|
||||||
|
|
||||||
# Check if we're in an LXC container
|
|
||||||
if [ -d /proc/vz ] && [ ! -d /proc/bc ]; then
|
|
||||||
echo -e "${YELLOW}Running in an OpenVZ container. Some features may not work.${NC}"
|
|
||||||
elif [ -f /proc/1/environ ] && grep -q container=lxc /proc/1/environ; then
|
|
||||||
echo -e "${GREEN}Running in an LXC container. Good!${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Not running in a container. This script is designed for LXC containers.${NC}"
|
|
||||||
read -p "Continue anyway? (y/n) " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
echo -e "${RED}Installation aborted.${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
echo -e "${BLUE}Step 1/7: Installing dependencies...${NC}"
|
|
||||||
apt update
|
|
||||||
apt install -y curl git sqlite3 build-essential openssl
|
|
||||||
|
|
||||||
# Create service user
|
|
||||||
echo -e "${BLUE}Step 2/7: Creating service user...${NC}"
|
|
||||||
if id "$SERVICE_USER" &>/dev/null; then
|
|
||||||
echo -e "${YELLOW}User $SERVICE_USER already exists${NC}"
|
|
||||||
else
|
|
||||||
useradd -m -s /bin/bash "$SERVICE_USER"
|
|
||||||
echo -e "${GREEN}Created user $SERVICE_USER${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install Bun
|
|
||||||
echo -e "${BLUE}Step 3/7: Installing Bun runtime...${NC}"
|
|
||||||
if command -v bun >/dev/null 2>&1; then
|
|
||||||
echo -e "${YELLOW}Bun is already installed${NC}"
|
|
||||||
bun --version
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}Installing Bun...${NC}"
|
|
||||||
curl -fsSL https://bun.sh/install | bash
|
|
||||||
export BUN_INSTALL=${BUN_INSTALL:-"/root/.bun"}
|
|
||||||
export PATH="$BUN_INSTALL/bin:$PATH"
|
|
||||||
echo -e "${GREEN}Bun installed successfully${NC}"
|
|
||||||
bun --version
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Clone repository
|
|
||||||
echo -e "${BLUE}Step 4/7: Downloading Gitea Mirror...${NC}"
|
|
||||||
if [ -d "$INSTALL_DIR" ]; then
|
|
||||||
echo -e "${YELLOW}Directory $INSTALL_DIR already exists${NC}"
|
|
||||||
read -p "Update existing installation? (y/n) " -n 1 -r
|
|
||||||
echo
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
||||||
cd "$INSTALL_DIR"
|
|
||||||
git pull
|
|
||||||
echo -e "${GREEN}Repository updated${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${YELLOW}Using existing installation${NC}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}Cloning repository...${NC}"
|
|
||||||
git clone "$REPO_URL" "$INSTALL_DIR"
|
|
||||||
echo -e "${GREEN}Repository cloned to $INSTALL_DIR${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set up application
|
|
||||||
echo -e "${BLUE}Step 5/7: Setting up application...${NC}"
|
|
||||||
cd "$INSTALL_DIR"
|
|
||||||
|
|
||||||
# Create data directory with proper permissions
|
|
||||||
mkdir -p data
|
|
||||||
chown -R "$SERVICE_USER:$SERVICE_USER" data
|
|
||||||
|
|
||||||
# Install dependencies and build
|
|
||||||
echo -e "${GREEN}Installing dependencies and building application...${NC}"
|
|
||||||
bun install
|
|
||||||
bun run build
|
|
||||||
|
|
||||||
# Initialize database if it doesn't exist
|
|
||||||
echo -e "${GREEN}Initializing database...${NC}"
|
|
||||||
if [ ! -f "data/gitea-mirror.db" ]; then
|
|
||||||
bun run manage-db init
|
|
||||||
chown "$SERVICE_USER:$SERVICE_USER" data/gitea-mirror.db
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Generate a random JWT secret if not provided
|
|
||||||
JWT_SECRET=${JWT_SECRET:-$(openssl rand -hex 32)}
|
|
||||||
|
|
||||||
# Create systemd service
|
|
||||||
echo -e "${BLUE}Step 6/7: Creating systemd service...${NC}"
|
|
||||||
|
|
||||||
# Store Bun path in a variable for better maintainability
|
|
||||||
BUN_PATH=$(command -v bun)
|
|
||||||
echo -e "${GREEN}Using Bun from: $BUN_PATH${NC}"
|
|
||||||
|
|
||||||
cat >/etc/systemd/system/gitea-mirror.service <<SERVICE
|
|
||||||
[Unit]
|
|
||||||
Description=Gitea Mirror
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
WorkingDirectory=$INSTALL_DIR
|
|
||||||
ExecStart=$BUN_PATH dist/server/entry.mjs
|
|
||||||
Restart=on-failure
|
|
||||||
RestartSec=10
|
|
||||||
User=$SERVICE_USER
|
|
||||||
Group=$SERVICE_USER
|
|
||||||
Environment=NODE_ENV=production
|
|
||||||
Environment=HOST=0.0.0.0
|
|
||||||
Environment=PORT=$PORT
|
|
||||||
Environment=DATABASE_URL=file:data/gitea-mirror.db
|
|
||||||
Environment=JWT_SECRET=${JWT_SECRET}
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
SERVICE
|
|
||||||
|
|
||||||
# Start service
|
|
||||||
echo -e "${BLUE}Step 7/7: Starting service...${NC}"
|
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable gitea-mirror.service
|
|
||||||
systemctl start gitea-mirror.service
|
|
||||||
|
|
||||||
# Check if service started successfully
|
|
||||||
if systemctl is-active --quiet gitea-mirror.service; then
|
|
||||||
echo -e "${GREEN}Gitea Mirror service started successfully!${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}Failed to start Gitea Mirror service. Check logs with: journalctl -u gitea-mirror${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get IP address
|
|
||||||
IP_ADDRESS=$(hostname -I | awk '{print $1}')
|
|
||||||
|
|
||||||
# Print success message
|
|
||||||
echo -e "${GREEN}"
|
|
||||||
echo "╔════════════════════════════════════════════════════════════╗"
|
|
||||||
echo "║ ║"
|
|
||||||
echo "║ Gitea Mirror Installation Complete ║"
|
|
||||||
echo "║ ║"
|
|
||||||
echo "╚════════════════════════════════════════════════════════════╝"
|
|
||||||
echo -e "${NC}"
|
|
||||||
echo -e "${GREEN}Gitea Mirror is now running at: http://$IP_ADDRESS:$PORT${NC}"
|
|
||||||
echo
|
|
||||||
echo -e "${YELLOW}Important security information:${NC}"
|
|
||||||
echo -e "JWT_SECRET: ${JWT_SECRET}"
|
|
||||||
echo -e "${YELLOW}Please save this JWT_SECRET in a secure location.${NC}"
|
|
||||||
echo
|
|
||||||
echo -e "${BLUE}To check service status:${NC} systemctl status gitea-mirror"
|
|
||||||
echo -e "${BLUE}To view logs:${NC} journalctl -u gitea-mirror -f"
|
|
||||||
echo -e "${BLUE}Data directory:${NC} $INSTALL_DIR/data"
|
|
||||||
echo
|
|
||||||
echo -e "${GREEN}Thank you for installing Gitea Mirror!${NC}"
|
|
||||||
86
scripts/gitea-mirror-lxc-local.sh
Executable file
86
scripts/gitea-mirror-lxc-local.sh
Executable file
@@ -0,0 +1,86 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# gitea-mirror-lxc-local.sh (offline, local repo, verbose)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CONTAINER="gitea-test"
|
||||||
|
IMAGE="ubuntu:22.04"
|
||||||
|
INSTALL_DIR="/opt/gitea-mirror"
|
||||||
|
PORT=4321
|
||||||
|
JWT_SECRET="$(openssl rand -hex 32)"
|
||||||
|
|
||||||
|
BUN_ZIP="/tmp/bun-linux-x64.zip"
|
||||||
|
BUN_URL="https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip"
|
||||||
|
|
||||||
|
LOCAL_REPO_DIR="${LOCAL_REPO_DIR:-./gitea-mirror}"
|
||||||
|
REPO_TAR="/tmp/gitea-mirror-local.tar.gz"
|
||||||
|
|
||||||
|
need() { command -v "$1" >/dev/null || { echo "Missing $1"; exit 1; }; }
|
||||||
|
need curl; need lxc; need tar; need unzip
|
||||||
|
|
||||||
|
# ── build host artefacts ────────────────────────────────────────────────
|
||||||
|
[[ -d $LOCAL_REPO_DIR ]] || { echo "❌ LOCAL_REPO_DIR not found"; exit 1; }
|
||||||
|
[[ -f $LOCAL_REPO_DIR/package.json ]] || { echo "❌ package.json missing"; exit 1; }
|
||||||
|
[[ -f $BUN_ZIP ]] || curl -L --retry 5 --retry-delay 5 -o "$BUN_ZIP" "$BUN_URL"
|
||||||
|
tar -czf "$REPO_TAR" -C "$(dirname "$LOCAL_REPO_DIR")" "$(basename "$LOCAL_REPO_DIR")"
|
||||||
|
|
||||||
|
# ── ensure container exists ─────────────────────────────────────────────
|
||||||
|
lxd init --auto >/dev/null 2>&1 || true
|
||||||
|
lxc info "$CONTAINER" >/dev/null 2>&1 || lxc launch "$IMAGE" "$CONTAINER"
|
||||||
|
|
||||||
|
echo "🔧 installing base packages…"
|
||||||
|
sudo lxc exec "$CONTAINER" -- bash -c 'set -ex; apt update; apt install -y unzip tar openssl sqlite3'
|
||||||
|
|
||||||
|
echo "⬆️ pushing artefacts…"
|
||||||
|
sudo lxc file push "$BUN_ZIP" "$CONTAINER/opt/"
|
||||||
|
sudo lxc file push "$REPO_TAR" "$CONTAINER/opt/"
|
||||||
|
|
||||||
|
echo "📦 unpacking Bun + repo…"
|
||||||
|
sudo lxc exec "$CONTAINER" -- bash -ex <<'IN'
|
||||||
|
cd /opt
|
||||||
|
# Bun
|
||||||
|
unzip -oq bun-linux-x64.zip -d bun
|
||||||
|
BIN=$(find /opt/bun -type f -name bun -perm -111 | head -n1)
|
||||||
|
ln -sf "$BIN" /usr/local/bin/bun # bun
|
||||||
|
ln -sf "$BIN" /usr/local/bin/bunx # bunx shim
|
||||||
|
# Repo
|
||||||
|
rm -rf /opt/gitea-mirror
|
||||||
|
mkdir -p /opt/gitea-mirror
|
||||||
|
tar -xzf gitea-mirror-local.tar.gz --strip-components=1 -C /opt/gitea-mirror
|
||||||
|
IN
|
||||||
|
|
||||||
|
echo "🏗️ bun install / build…"
|
||||||
|
sudo lxc exec "$CONTAINER" -- bash -ex <<'IN'
|
||||||
|
cd /opt/gitea-mirror
|
||||||
|
bun install
|
||||||
|
bun run build
|
||||||
|
bun run manage-db init
|
||||||
|
IN
|
||||||
|
|
||||||
|
echo "📝 systemd unit…"
|
||||||
|
sudo lxc exec "$CONTAINER" -- bash -ex <<IN
|
||||||
|
cat >/etc/systemd/system/gitea-mirror.service <<SERVICE
|
||||||
|
[Unit]
|
||||||
|
Description=Gitea Mirror
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=$INSTALL_DIR
|
||||||
|
ExecStart=/usr/local/bin/bun dist/server/entry.mjs
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Environment=HOST=0.0.0.0
|
||||||
|
Environment=PORT=$PORT
|
||||||
|
Environment=DATABASE_URL=file:data/gitea-mirror.db
|
||||||
|
Environment=JWT_SECRET=$JWT_SECRET
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable gitea-mirror
|
||||||
|
systemctl restart gitea-mirror
|
||||||
|
IN
|
||||||
|
|
||||||
|
echo -e "\n✅ finished; service status:"
|
||||||
|
sudo lxc exec "$CONTAINER" -- systemctl status gitea-mirror --no-pager
|
||||||
97
scripts/gitea-mirror-lxc-proxmox.sh
Executable file
97
scripts/gitea-mirror-lxc-proxmox.sh
Executable file
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# gitea-mirror-lxc-proxmox.sh
|
||||||
|
# Fully online installer for a Proxmox LXC guest running Gitea Mirror + Bun.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ────── adjustable defaults ──────────────────────────────────────────────
|
||||||
|
CTID=${CTID:-106} # container ID
|
||||||
|
HOSTNAME=${HOSTNAME:-gitea-mirror}
|
||||||
|
STORAGE=${STORAGE:-local-lvm} # where rootfs lives
|
||||||
|
DISK_SIZE=${DISK_SIZE:-8G}
|
||||||
|
CORES=${CORES:-2}
|
||||||
|
MEMORY=${MEMORY:-2048} # MiB
|
||||||
|
BRIDGE=${BRIDGE:-vmbr0}
|
||||||
|
IP_CONF=${IP_CONF:-dhcp} # or "192.168.1.240/24,gw=192.168.1.1"
|
||||||
|
|
||||||
|
PORT=4321
|
||||||
|
JWT_SECRET=$(openssl rand -hex 32)
|
||||||
|
|
||||||
|
REPO="https://github.com/arunavo4/gitea-mirror.git"
|
||||||
|
# ─────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEMPLATE='ubuntu-22.04-standard_22.04-1_amd64.tar.zst'
|
||||||
|
TEMPLATE_PATH="/var/lib/vz/template/cache/${TEMPLATE}"
|
||||||
|
|
||||||
|
echo "▶️ Ensuring template exists…"
|
||||||
|
if [[ ! -f $TEMPLATE_PATH ]]; then
|
||||||
|
pveam update >/dev/null
|
||||||
|
pveam download "$STORAGE" "$TEMPLATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "▶️ Creating container $CTID (if missing)…"
|
||||||
|
if ! pct status "$CTID" &>/dev/null; then
|
||||||
|
pct create "$CTID" "$TEMPLATE_PATH" \
|
||||||
|
--rootfs "$STORAGE:$DISK_SIZE" \
|
||||||
|
--hostname "$HOSTNAME" \
|
||||||
|
--cores "$CORES" --memory "$MEMORY" \
|
||||||
|
--net0 "name=eth0,bridge=$BRIDGE,ip=$IP_CONF" \
|
||||||
|
--features nesting=1 \
|
||||||
|
--unprivileged 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
pct start "$CTID"
|
||||||
|
|
||||||
|
echo "▶️ Installing base packages inside CT $CTID…"
|
||||||
|
pct exec "$CTID" -- bash -c 'apt update && apt install -y curl git build-essential openssl sqlite3 unzip'
|
||||||
|
|
||||||
|
echo "▶️ Installing Bun runtime…"
|
||||||
|
pct exec "$CTID" -- bash -c '
|
||||||
|
export BUN_INSTALL=/opt/bun
|
||||||
|
curl -fsSL https://bun.sh/install | bash -s -- --yes
|
||||||
|
ln -sf /opt/bun/bin/bun /usr/local/bin/bun
|
||||||
|
ln -sf /opt/bun/bin/bun /usr/local/bin/bunx
|
||||||
|
bun --version
|
||||||
|
'
|
||||||
|
|
||||||
|
echo "▶️ Cloning & building Gitea Mirror…"
|
||||||
|
pct exec "$CTID" -- bash -c "
|
||||||
|
git clone --depth=1 '$REPO' /opt/gitea-mirror || (cd /opt/gitea-mirror && git pull)
|
||||||
|
cd /opt/gitea-mirror
|
||||||
|
bun install
|
||||||
|
bun run build
|
||||||
|
bun run manage-db init
|
||||||
|
"
|
||||||
|
|
||||||
|
echo "▶️ Creating systemd service…"
|
||||||
|
pct exec "$CTID" -- bash -c "
|
||||||
|
cat >/etc/systemd/system/gitea-mirror.service <<SERVICE
|
||||||
|
[Unit]
|
||||||
|
Description=Gitea Mirror
|
||||||
|
After=network.target
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/opt/gitea-mirror
|
||||||
|
ExecStart=/usr/local/bin/bun dist/server/entry.mjs
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
Environment=NODE_ENV=production
|
||||||
|
Environment=HOST=0.0.0.0
|
||||||
|
Environment=PORT=$PORT
|
||||||
|
Environment=DATABASE_URL=file:data/gitea-mirror.db
|
||||||
|
Environment=JWT_SECRET=$JWT_SECRET
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable gitea-mirror
|
||||||
|
systemctl restart gitea-mirror
|
||||||
|
"
|
||||||
|
|
||||||
|
echo -e "\n🔍 Service status:"
|
||||||
|
pct exec "$CTID" -- systemctl status gitea-mirror --no-pager | head -n15
|
||||||
|
|
||||||
|
GUEST_IP=$(pct exec "$CTID" -- hostname -I | awk '{print $1}')
|
||||||
|
echo -e "\n🌐 Browse to: http://$GUEST_IP:$PORT\n"
|
||||||
|
echo "🗝️ JWT_SECRET = $JWT_SECRET"
|
||||||
|
echo -e "\n✅ Done – Gitea Mirror is running in CT $CTID."
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
title: "Architecture"
|
title: "Architecture"
|
||||||
description: "Comprehensive overview of the Gitea Mirror application architecture."
|
description: "Comprehensive overview of the Gitea Mirror application architecture."
|
||||||
order: 1
|
order: 1
|
||||||
updatedDate: 2023-10-15
|
updatedDate: 2025-05-22
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@@ -21,17 +21,18 @@ The application is built using:
|
|||||||
- <span class="font-semibold text-foreground">Astro</span>: Web framework for the frontend
|
- <span class="font-semibold text-foreground">Astro</span>: Web framework for the frontend
|
||||||
- <span class="font-semibold text-foreground">React</span>: Component library for interactive UI elements
|
- <span class="font-semibold text-foreground">React</span>: Component library for interactive UI elements
|
||||||
- <span class="font-semibold text-foreground">Shadcn UI</span>: UI component library built on Tailwind CSS
|
- <span class="font-semibold text-foreground">Shadcn UI</span>: UI component library built on Tailwind CSS
|
||||||
- <span class="font-semibold text-foreground">SQLite</span>: Database for storing configuration and state
|
- <span class="font-semibold text-foreground">SQLite</span>: Database for storing configuration, state, and events
|
||||||
- <span class="font-semibold text-foreground">Bun</span>: Runtime environment for the backend
|
- <span class="font-semibold text-foreground">Bun</span>: Runtime environment for the backend
|
||||||
|
- <span class="font-semibold text-foreground">Drizzle ORM</span>: Type-safe ORM for database interactions
|
||||||
|
|
||||||
## Architecture Diagram
|
## Architecture Diagram
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TD
|
graph TD
|
||||||
subgraph "Gitea Mirror"
|
subgraph "Gitea Mirror"
|
||||||
Frontend["Frontend<br/>(Astro)"]
|
Frontend["Frontend<br/>(Astro + React)"]
|
||||||
Backend["Backend<br/>(Bun)"]
|
Backend["Backend<br/>(Bun)"]
|
||||||
Database["Database<br/>(SQLite)"]
|
Database["Database<br/>(SQLite + Drizzle)"]
|
||||||
|
|
||||||
Frontend <--> Backend
|
Frontend <--> Backend
|
||||||
Backend <--> Database
|
Backend <--> Database
|
||||||
@@ -70,14 +71,15 @@ The backend is built with Bun and provides API endpoints for the frontend to int
|
|||||||
- Mirroring operations
|
- Mirroring operations
|
||||||
- Database interactions
|
- Database interactions
|
||||||
|
|
||||||
### Database (SQLite)
|
### Database (SQLite + Drizzle ORM)
|
||||||
|
|
||||||
SQLite is used for data persistence, storing:
|
SQLite with Bun's native SQLite driver is used for data persistence, with Drizzle ORM providing type-safe database interactions. The database stores:
|
||||||
|
|
||||||
- User accounts and authentication data
|
- User accounts and authentication data
|
||||||
- GitHub and Gitea configuration
|
- GitHub and Gitea configuration
|
||||||
- Repository and organization information
|
- Repository and organization information
|
||||||
- Mirroring job history and status
|
- Mirroring job history and status
|
||||||
|
- Event notifications and their read status
|
||||||
|
|
||||||
## Data Flow
|
## Data Flow
|
||||||
|
|
||||||
@@ -93,11 +95,30 @@ SQLite is used for data persistence, storing:
|
|||||||
gitea-mirror/
|
gitea-mirror/
|
||||||
├── src/ # Source code
|
├── src/ # Source code
|
||||||
│ ├── components/ # React components
|
│ ├── components/ # React components
|
||||||
|
│ ├── content/ # Documentation and content
|
||||||
│ ├── layouts/ # Astro layout components
|
│ ├── layouts/ # Astro layout components
|
||||||
│ ├── lib/ # Utility functions and database
|
│ ├── lib/ # Utility functions and database
|
||||||
│ ├── pages/ # Astro pages and API routes
|
│ ├── pages/ # Astro pages and API routes
|
||||||
│ └── styles/ # CSS and Tailwind styles
|
│ └── styles/ # CSS and Tailwind styles
|
||||||
├── public/ # Static assets
|
├── public/ # Static assets
|
||||||
├── data/ # Database and persistent data
|
├── data/ # Database and persistent data
|
||||||
└── docker/ # Docker configuration
|
├── docker/ # Docker configuration
|
||||||
|
└── scripts/ # Utility scripts for deployment and maintenance
|
||||||
|
├── gitea-mirror-lxc-proxmox.sh # Proxmox LXC deployment script
|
||||||
|
├── gitea-mirror-lxc-local.sh # Local LXC deployment script
|
||||||
|
└── manage-db.ts # Database management tool
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Deployment Options
|
||||||
|
|
||||||
|
Gitea Mirror supports multiple deployment options:
|
||||||
|
|
||||||
|
1. **Docker**: Run as a containerized application using Docker and docker-compose
|
||||||
|
2. **LXC Containers**: Deploy in Linux Containers (LXC) on Proxmox VE or local workstations
|
||||||
|
3. **Native**: Run directly on the host system using Bun runtime
|
||||||
|
|
||||||
|
Each deployment method has its own advantages:
|
||||||
|
|
||||||
|
- **Docker**: Isolation, easy updates, consistent environment
|
||||||
|
- **LXC**: Lightweight virtualization, better performance than Docker, system-level isolation
|
||||||
|
- **Native**: Best performance, direct access to system resources
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: "Configuration"
|
title: "Configuration"
|
||||||
description: "Guide to configuring Gitea Mirror for your environment."
|
description: "Guide to configuring Gitea Mirror for your environment."
|
||||||
order: 2
|
order: 2
|
||||||
updatedDate: 2023-10-15
|
updatedDate: 2025-05-22
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@@ -24,10 +24,10 @@ The following environment variables can be used to configure Gitea Mirror:
|
|||||||
| Variable | Description | Default Value | Example |
|
| Variable | Description | Default Value | Example |
|
||||||
|----------|-------------|---------------|---------|
|
|----------|-------------|---------------|---------|
|
||||||
| `NODE_ENV` | Runtime environment (development, production, test) | `development` | `production` |
|
| `NODE_ENV` | Runtime environment (development, production, test) | `development` | `production` |
|
||||||
| `DATABASE_URL` | SQLite database URL | `sqlite://data/gitea-mirror.db` | `sqlite://path/to/your/database.db` |
|
| `DATABASE_URL` | SQLite database URL | `file:data/gitea-mirror.db` | `file:path/to/your/database.db` |
|
||||||
| `JWT_SECRET` | Secret key for JWT authentication | `your-secret-key-change-this-in-production` | `your-secure-random-string` |
|
| `JWT_SECRET` | Secret key for JWT authentication | `your-secret-key-change-this-in-production` | `your-secure-random-string` |
|
||||||
| `HOST` | Server host | `localhost` | `0.0.0.0` |
|
| `HOST` | Server host | `localhost` | `0.0.0.0` |
|
||||||
| `PORT` | Server port | `3000` | `8080` |
|
| `PORT` | Server port | `4321` | `8080` |
|
||||||
|
|
||||||
### Important Security Note
|
### Important Security Note
|
||||||
|
|
||||||
@@ -118,3 +118,58 @@ Example patterns:
|
|||||||
- `*` - All repositories
|
- `*` - All repositories
|
||||||
- `org-name/*` - All repositories in a specific organization
|
- `org-name/*` - All repositories in a specific organization
|
||||||
- `username/repo-name` - A specific repository
|
- `username/repo-name` - A specific repository
|
||||||
|
|
||||||
|
### Database Management
|
||||||
|
|
||||||
|
Gitea Mirror includes several database management tools that can be run from the command line:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Initialize the database (only if it doesn't exist)
|
||||||
|
bun run init-db
|
||||||
|
|
||||||
|
# Check database status
|
||||||
|
bun run check-db
|
||||||
|
|
||||||
|
# Fix database location issues
|
||||||
|
bun run fix-db
|
||||||
|
|
||||||
|
# Reset all users (for testing signup flow)
|
||||||
|
bun run reset-users
|
||||||
|
|
||||||
|
# Remove database files completely
|
||||||
|
bun run cleanup-db
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event Management
|
||||||
|
|
||||||
|
Events in Gitea Mirror (such as repository mirroring operations) are stored in the SQLite database. You can manage these events using the following scripts:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View all events in the database
|
||||||
|
bun scripts/check-events.ts
|
||||||
|
|
||||||
|
# Clean up old events (default: older than 7 days)
|
||||||
|
bun scripts/cleanup-events.ts
|
||||||
|
|
||||||
|
# Mark all events as read
|
||||||
|
bun scripts/mark-events-read.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### Health Check Endpoint
|
||||||
|
|
||||||
|
Gitea Mirror includes a built-in health check endpoint at `/api/health` that provides:
|
||||||
|
|
||||||
|
- System status and uptime
|
||||||
|
- Database connectivity check
|
||||||
|
- Memory usage statistics
|
||||||
|
- Environment information
|
||||||
|
|
||||||
|
You can use this endpoint for monitoring your deployment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Basic check (returns 200 OK if healthy)
|
||||||
|
curl -I http://your-server:port/api/health
|
||||||
|
|
||||||
|
# Detailed health information (JSON)
|
||||||
|
curl http://your-server:port/api/health
|
||||||
|
```
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
title: "Quick Start Guide"
|
title: "Quick Start Guide"
|
||||||
description: "Get started with Gitea Mirror quickly."
|
description: "Get started with Gitea Mirror quickly."
|
||||||
order: 3
|
order: 3
|
||||||
updatedDate: 2023-10-15
|
updatedDate: 2025-05-22
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@@ -16,13 +16,16 @@ Before you begin, make sure you have:
|
|||||||
|
|
||||||
1. <span class="font-semibold text-foreground">A GitHub account with a personal access token</span>
|
1. <span class="font-semibold text-foreground">A GitHub account with a personal access token</span>
|
||||||
2. <span class="font-semibold text-foreground">A Gitea instance with an access token</span>
|
2. <span class="font-semibold text-foreground">A Gitea instance with an access token</span>
|
||||||
3. <span class="font-semibold text-foreground">Docker and docker-compose (recommended) or Bun 1.2.9+ installed</span>
|
3. <span class="font-semibold text-foreground">One of the following:</span>
|
||||||
|
- Docker and docker-compose (for Docker deployment)
|
||||||
|
- Bun 1.2.9+ (for native deployment)
|
||||||
|
- Proxmox VE or LXD (for LXC container deployment)
|
||||||
|
|
||||||
## Installation Options
|
## Installation Options
|
||||||
|
|
||||||
Choose the installation method that works best for your environment.
|
Choose the installation method that works best for your environment.
|
||||||
|
|
||||||
### Using Docker (Recommended)
|
### Using Docker (Recommended for most users)
|
||||||
|
|
||||||
Docker provides the easiest way to get started with minimal configuration.
|
Docker provides the easiest way to get started with minimal configuration.
|
||||||
|
|
||||||
@@ -39,7 +42,7 @@ Docker provides the easiest way to get started with minimal configuration.
|
|||||||
|
|
||||||
3. Access the application at [http://localhost:4321](http://localhost:4321)
|
3. Access the application at [http://localhost:4321](http://localhost:4321)
|
||||||
|
|
||||||
### Manual Installation
|
### Using Bun (Native Installation)
|
||||||
|
|
||||||
If you prefer to run the application directly on your system:
|
If you prefer to run the application directly on your system:
|
||||||
|
|
||||||
@@ -62,6 +65,11 @@ If you prefer to run the application directly on your system:
|
|||||||
bun run dev
|
bun run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note: For Bun-specific features, use:
|
||||||
|
```bash
|
||||||
|
bunx --bun astro dev
|
||||||
|
```
|
||||||
|
|
||||||
**Production Mode:**
|
**Production Mode:**
|
||||||
```bash
|
```bash
|
||||||
bun run build
|
bun run build
|
||||||
@@ -70,6 +78,44 @@ If you prefer to run the application directly on your system:
|
|||||||
|
|
||||||
4. Access the application at [http://localhost:4321](http://localhost:4321)
|
4. Access the application at [http://localhost:4321](http://localhost:4321)
|
||||||
|
|
||||||
|
### Using LXC Containers (Recommended for server deployments)
|
||||||
|
|
||||||
|
#### Proxmox VE (Online Installation)
|
||||||
|
|
||||||
|
For deploying on a Proxmox VE host with internet access:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Optional env overrides: CTID HOSTNAME STORAGE DISK_SIZE CORES MEMORY BRIDGE IP_CONF
|
||||||
|
sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-proxmox.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
This script:
|
||||||
|
- Creates a privileged LXC container
|
||||||
|
- Installs Bun and dependencies
|
||||||
|
- Clones and builds the application
|
||||||
|
- Sets up a systemd service
|
||||||
|
|
||||||
|
#### Local LXD (Offline-friendly Installation)
|
||||||
|
|
||||||
|
For testing on a local workstation or in environments without internet access:
|
||||||
|
|
||||||
|
1. Clone the repository locally:
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/arunavo4/gitea-mirror.git
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Download the Bun installer once:
|
||||||
|
```bash
|
||||||
|
curl -L -o /tmp/bun-linux-x64.zip https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the local LXC installer:
|
||||||
|
```bash
|
||||||
|
sudo LOCAL_REPO_DIR=~/path/to/gitea-mirror ./gitea-mirror/scripts/gitea-mirror-lxc-local.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
For more details on LXC deployment, see the [LXC Container Deployment Guide](https://github.com/arunavo4/gitea-mirror/blob/main/scripts/README-lxc.md).
|
||||||
|
|
||||||
## Initial Configuration
|
## Initial Configuration
|
||||||
|
|
||||||
Follow these steps to configure Gitea Mirror for first use:
|
Follow these steps to configure Gitea Mirror for first use:
|
||||||
@@ -116,7 +162,12 @@ If you encounter any issues:
|
|||||||
- Check the Activity Log for detailed error messages
|
- Check the Activity Log for detailed error messages
|
||||||
- Verify your GitHub and Gitea tokens have the correct permissions
|
- Verify your GitHub and Gitea tokens have the correct permissions
|
||||||
- Ensure your Gitea instance is accessible from the machine running Gitea Mirror
|
- Ensure your Gitea instance is accessible from the machine running Gitea Mirror
|
||||||
- For Docker installations, check container logs with `docker logs gitea-mirror`
|
- Check logs based on your deployment method:
|
||||||
|
- Docker: `docker logs gitea-mirror`
|
||||||
|
- Native: Check the terminal output or system logs
|
||||||
|
- LXC: `systemctl status gitea-mirror` or `journalctl -u gitea-mirror -f`
|
||||||
|
- Use the health check endpoint to verify system status: `curl http://your-server:4321/api/health`
|
||||||
|
- For database issues, try the database management tools: `bun run check-db` or `bun run fix-db`
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
@@ -125,3 +176,7 @@ After your initial setup:
|
|||||||
- Explore the dashboard for an overview of your mirroring status
|
- Explore the dashboard for an overview of your mirroring status
|
||||||
- Set up automatic mirroring schedules for hands-off operation
|
- Set up automatic mirroring schedules for hands-off operation
|
||||||
- Configure organization mirroring for team repositories
|
- Configure organization mirroring for team repositories
|
||||||
|
- Check out the [Configuration Guide](/configuration) for advanced settings
|
||||||
|
- Review the [Architecture Documentation](/architecture) to understand the system
|
||||||
|
- For server deployments, set up monitoring using the health check endpoint
|
||||||
|
- Consider setting up a cron job to clean up old events: `bun scripts/cleanup-events.ts`
|
||||||
|
|||||||
@@ -88,3 +88,80 @@ export const giteaApi = {
|
|||||||
body: JSON.stringify({ url, token }),
|
body: JSON.stringify({ url, token }),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Health API
|
||||||
|
export interface HealthResponse {
|
||||||
|
status: "ok" | "error";
|
||||||
|
timestamp: string;
|
||||||
|
version: string;
|
||||||
|
database: {
|
||||||
|
connected: boolean;
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
system: {
|
||||||
|
uptime: {
|
||||||
|
startTime: string;
|
||||||
|
uptimeMs: number;
|
||||||
|
formatted: string;
|
||||||
|
};
|
||||||
|
memory: {
|
||||||
|
rss: string;
|
||||||
|
heapTotal: string;
|
||||||
|
heapUsed: string;
|
||||||
|
external: string;
|
||||||
|
systemTotal: string;
|
||||||
|
systemFree: string;
|
||||||
|
};
|
||||||
|
os: {
|
||||||
|
platform: string;
|
||||||
|
version: string;
|
||||||
|
arch: string;
|
||||||
|
};
|
||||||
|
env: string;
|
||||||
|
};
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const healthApi = {
|
||||||
|
check: async (): Promise<HealthResponse> => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${API_BASE}/health`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
const errorData = await response.json().catch(() => ({
|
||||||
|
status: "error",
|
||||||
|
error: "Failed to parse error response",
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
...errorData,
|
||||||
|
status: "error",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
} as HealthResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
status: "error",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
error: error instanceof Error ? error.message : "Unknown error checking health",
|
||||||
|
version: "unknown",
|
||||||
|
database: { connected: false, message: "Failed to connect to API" },
|
||||||
|
system: {
|
||||||
|
uptime: { startTime: "", uptimeMs: 0, formatted: "N/A" },
|
||||||
|
memory: {
|
||||||
|
rss: "N/A",
|
||||||
|
heapTotal: "N/A",
|
||||||
|
heapUsed: "N/A",
|
||||||
|
external: "N/A",
|
||||||
|
systemTotal: "N/A",
|
||||||
|
systemFree: "N/A",
|
||||||
|
},
|
||||||
|
os: { platform: "", version: "", arch: "" },
|
||||||
|
env: "",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
126
src/pages/api/health.ts
Normal file
126
src/pages/api/health.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
import type { APIRoute } from "astro";
|
||||||
|
import { jsonResponse } from "@/lib/utils";
|
||||||
|
import { db } from "@/lib/db";
|
||||||
|
import { ENV } from "@/lib/config";
|
||||||
|
import os from "os";
|
||||||
|
|
||||||
|
// Track when the server started
|
||||||
|
const serverStartTime = new Date();
|
||||||
|
|
||||||
|
export const GET: APIRoute = async () => {
|
||||||
|
try {
|
||||||
|
// Check database connection by running a simple query
|
||||||
|
const dbStatus = await checkDatabaseConnection();
|
||||||
|
|
||||||
|
// Get system information
|
||||||
|
const systemInfo = {
|
||||||
|
uptime: getUptime(),
|
||||||
|
memory: getMemoryUsage(),
|
||||||
|
os: {
|
||||||
|
platform: os.platform(),
|
||||||
|
version: os.version(),
|
||||||
|
arch: os.arch(),
|
||||||
|
},
|
||||||
|
env: ENV.NODE_ENV,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build response
|
||||||
|
const healthData = {
|
||||||
|
status: "ok",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
version: process.env.npm_package_version || "unknown",
|
||||||
|
database: dbStatus,
|
||||||
|
system: systemInfo,
|
||||||
|
};
|
||||||
|
|
||||||
|
return jsonResponse({
|
||||||
|
data: healthData,
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Health check failed:", error);
|
||||||
|
|
||||||
|
return jsonResponse({
|
||||||
|
data: {
|
||||||
|
status: "error",
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
error: error instanceof Error ? error.message : "Unknown error",
|
||||||
|
},
|
||||||
|
status: 503, // Service Unavailable
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check database connection by running a simple query
|
||||||
|
*/
|
||||||
|
async function checkDatabaseConnection() {
|
||||||
|
try {
|
||||||
|
// Run a simple query to check if the database is accessible
|
||||||
|
const result = await db.select({ test: sql`1` }).from(sql`sqlite_master`).limit(1);
|
||||||
|
|
||||||
|
return {
|
||||||
|
connected: true,
|
||||||
|
message: "Database connection successful",
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Database connection check failed:", error);
|
||||||
|
|
||||||
|
return {
|
||||||
|
connected: false,
|
||||||
|
message: error instanceof Error ? error.message : "Database connection failed",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get server uptime information
|
||||||
|
*/
|
||||||
|
function getUptime() {
|
||||||
|
const now = new Date();
|
||||||
|
const uptimeMs = now.getTime() - serverStartTime.getTime();
|
||||||
|
|
||||||
|
// Convert to human-readable format
|
||||||
|
const seconds = Math.floor(uptimeMs / 1000);
|
||||||
|
const minutes = Math.floor(seconds / 60);
|
||||||
|
const hours = Math.floor(minutes / 60);
|
||||||
|
const days = Math.floor(hours / 24);
|
||||||
|
|
||||||
|
return {
|
||||||
|
startTime: serverStartTime.toISOString(),
|
||||||
|
uptimeMs,
|
||||||
|
formatted: `${days}d ${hours % 24}h ${minutes % 60}m ${seconds % 60}s`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get memory usage information
|
||||||
|
*/
|
||||||
|
function getMemoryUsage() {
|
||||||
|
const memoryUsage = process.memoryUsage();
|
||||||
|
|
||||||
|
return {
|
||||||
|
rss: formatBytes(memoryUsage.rss),
|
||||||
|
heapTotal: formatBytes(memoryUsage.heapTotal),
|
||||||
|
heapUsed: formatBytes(memoryUsage.heapUsed),
|
||||||
|
external: formatBytes(memoryUsage.external),
|
||||||
|
systemTotal: formatBytes(os.totalmem()),
|
||||||
|
systemFree: formatBytes(os.freemem()),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format bytes to human-readable format
|
||||||
|
*/
|
||||||
|
function formatBytes(bytes: number): string {
|
||||||
|
if (bytes === 0) return '0 Bytes';
|
||||||
|
|
||||||
|
const k = 1024;
|
||||||
|
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import sql tag for raw SQL queries
|
||||||
|
import { sql } from "drizzle-orm";
|
||||||
Reference in New Issue
Block a user