mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2025-12-08 04:26:44 +03:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aaf8dc6fe4 | ||
|
|
cda78bc0f5 | ||
|
|
9ccd656734 | ||
|
|
8b5c5d8ed2 | ||
|
|
1ab642c9e7 | ||
|
|
1eae725535 | ||
|
|
5bf52c806f | ||
|
|
a15178d2cd | ||
|
|
32ef9124a7 | ||
|
|
161685b966 | ||
|
|
0cf95b2a0e | ||
|
|
c896194aeb |
@@ -49,6 +49,6 @@ VOLUME /app/data
|
||||
EXPOSE 4321
|
||||
|
||||
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"]
|
||||
|
||||
46
README.md
46
README.md
@@ -19,8 +19,12 @@ docker compose --profile production up -d
|
||||
# Using Bun
|
||||
bun run setup && bun run dev
|
||||
|
||||
# Using LXC on Proxmox
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
||||
# Using LXC Containers
|
||||
# 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).
|
||||
@@ -163,21 +167,37 @@ docker compose --profile production up -d
|
||||
|
||||
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
|
||||
# One-command installation on an Ubuntu 22.04 LXC container
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
||||
# One-command installation on Proxmox VE
|
||||
# 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:
|
||||
- Downloads the Gitea Mirror repository
|
||||
- Installs all dependencies including Bun
|
||||
- Builds the application
|
||||
- Sets up a systemd service
|
||||
- Starts the application
|
||||
**2. Local testing (offline-friendly, works on developer laptops)**
|
||||
|
||||
```bash
|
||||
# Download the script
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-local.sh -o gitea-mirror-lxc-local.sh
|
||||
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.
|
||||
|
||||
@@ -379,7 +399,7 @@ docker compose -f docker-compose.dev.yml up -d
|
||||
- **Backend**: Bun
|
||||
- **Database**: SQLite (handles both data storage and event notifications)
|
||||
- **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
|
||||
|
||||
|
||||
97
bun.lock
97
bun.lock
@@ -40,7 +40,6 @@
|
||||
"react-dom": "^19.1.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"sonner": "^2.0.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
"superagent": "^10.2.1",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
"tailwindcss": "^4.1.7",
|
||||
@@ -637,7 +636,7 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1187,7 +1186,7 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1199,9 +1198,9 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1491,7 +1490,7 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1643,7 +1642,7 @@
|
||||
|
||||
"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=="],
|
||||
|
||||
@@ -1667,7 +1666,7 @@
|
||||
|
||||
"@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=="],
|
||||
|
||||
@@ -1675,8 +1674,6 @@
|
||||
|
||||
"@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/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=="],
|
||||
|
||||
"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/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=="],
|
||||
|
||||
"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/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-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=="],
|
||||
|
||||
"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-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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"@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/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=="],
|
||||
|
||||
"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/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/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=="],
|
||||
|
||||
"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/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
|
||||
- DELAY=${DELAY:-3600}
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4321/health"]
|
||||
test: ["CMD", "curl", "-f", "http://localhost:4321/api/health"]
|
||||
interval: 1m
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "gitea-mirror",
|
||||
"type": "module",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.0",
|
||||
"engines": {
|
||||
"bun": ">=1.2.9"
|
||||
},
|
||||
@@ -61,7 +61,6 @@
|
||||
"react-dom": "^19.1.0",
|
||||
"react-icons": "^5.5.0",
|
||||
"sonner": "^2.0.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
"superagent": "^10.2.1",
|
||||
"tailwind-merge": "^3.3.0",
|
||||
"tailwindcss": "^4.1.7",
|
||||
|
||||
@@ -1,109 +1,117 @@
|
||||
# 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:
|
||||
- Choose Ubuntu 22.04 as the template
|
||||
- Allocate appropriate resources (2GB RAM, 2 CPU cores recommended)
|
||||
- At least 10GB of disk space
|
||||
- Configure networking as needed
|
||||
### Prerequisites
|
||||
* Proxmox VE node with the default `vmbr0` bridge
|
||||
* Root shell on the node
|
||||
* Ubuntu 22.04 LXC template present (`pveam update && pveam download ...`)
|
||||
|
||||
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:
|
||||
```bash
|
||||
ssh root@lxc-container-ip
|
||||
```
|
||||
Browse to:
|
||||
|
||||
2. Run the installer script directly:
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-installer.sh | bash
|
||||
```
|
||||
```
|
||||
http://<container-ip>:4321
|
||||
```
|
||||
|
||||
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:
|
||||
```bash
|
||||
apt update
|
||||
apt install -y curl git sqlite3 build-essential
|
||||
```
|
||||
* `lxd` installed (`sudo apt install lxd`; `lxd init --auto`)
|
||||
* Your repo cloned locally – e.g. `~/Development/gitea-mirror`
|
||||
* Bun ZIP downloaded once:
|
||||
`https://github.com/oven-sh/bun/releases/latest/download/bun-linux-x64.zip`
|
||||
|
||||
2. Install Bun:
|
||||
```bash
|
||||
curl -fsSL https://bun.sh/install | bash
|
||||
export BUN_INSTALL="/root/.bun"
|
||||
export PATH="$BUN_INSTALL/bin:$PATH"
|
||||
```
|
||||
### Offline installer script
|
||||
|
||||
3. Clone or copy your project:
|
||||
```bash
|
||||
git clone https://github.com/yourusername/gitea-mirror.git /opt/gitea-mirror
|
||||
cd /opt/gitea-mirror
|
||||
```
|
||||
```bash
|
||||
git clone https://github.com/arunavo4/gitea-mirror.git # if not already
|
||||
curl -fsSL https://raw.githubusercontent.com/arunavo4/gitea-mirror/main/scripts/gitea-mirror-lxc-local.sh -o gitea-mirror-lxc-local.sh
|
||||
chmod +x gitea-mirror-lxc-local.sh
|
||||
|
||||
4. Build and initialize:
|
||||
```bash
|
||||
bun install
|
||||
bun run build
|
||||
bun run manage-db init
|
||||
```
|
||||
sudo LOCAL_REPO_DIR=~/Development/gitea-mirror \
|
||||
./gitea-mirror-lxc-local.sh
|
||||
```
|
||||
|
||||
5. Create a systemd service manually:
|
||||
```bash
|
||||
nano /etc/systemd/system/gitea-mirror.service
|
||||
# Add the service configuration as shown below:
|
||||
What it does:
|
||||
|
||||
[Unit]
|
||||
Description=Gitea Mirror
|
||||
After=network.target
|
||||
* Launches privileged LXC `gitea-test` (`lxc launch ubuntu:22.04 ...`)
|
||||
* Pushes **Bun ZIP** + tarred **local repo** into `/opt`
|
||||
* Unpacks, builds, initializes DB
|
||||
* Symlinks both `bun` and `bunx` → `/usr/local/bin`
|
||||
* Creates a root systemd unit and starts it
|
||||
|
||||
[Service]
|
||||
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
|
||||
Access from host:
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
```
|
||||
http://$(lxc exec gitea-test -- hostname -I | awk '{print $1}'):4321
|
||||
```
|
||||
|
||||
6. Enable and start the service:
|
||||
```bash
|
||||
systemctl enable gitea-mirror.service
|
||||
systemctl start gitea-mirror.service
|
||||
```
|
||||
(Optional) forward to host localhost:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
@@ -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.
|
||||
|
||||
## 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
|
||||
|
||||
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.
|
||||
|
||||
### Features
|
||||
#### Features
|
||||
|
||||
- **Check Mode**: Validates the existence and integrity of the database
|
||||
- **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
|
||||
- **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:
|
||||
|
||||
```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
|
||||
|
||||
# Check database status
|
||||
@@ -37,9 +39,6 @@ bun run db-auto
|
||||
# Reset all users (for testing signup flow)
|
||||
bun run reset-users
|
||||
|
||||
# Update the database schema to the latest version
|
||||
bun run update-schema
|
||||
|
||||
# Remove database files completely
|
||||
bun run cleanup-db
|
||||
|
||||
@@ -53,6 +52,70 @@ bun run dev:clean
|
||||
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.
|
||||
|
||||
## 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"
|
||||
description: "Comprehensive overview of the Gitea Mirror application architecture."
|
||||
order: 1
|
||||
updatedDate: 2023-10-15
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<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">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">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">Drizzle ORM</span>: Type-safe ORM for database interactions
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph "Gitea Mirror"
|
||||
Frontend["Frontend<br/>(Astro)"]
|
||||
Frontend["Frontend<br/>(Astro + React)"]
|
||||
Backend["Backend<br/>(Bun)"]
|
||||
Database["Database<br/>(SQLite)"]
|
||||
Database["Database<br/>(SQLite + Drizzle)"]
|
||||
|
||||
Frontend <--> Backend
|
||||
Backend <--> Database
|
||||
@@ -70,14 +71,15 @@ The backend is built with Bun and provides API endpoints for the frontend to int
|
||||
- Mirroring operations
|
||||
- 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
|
||||
- GitHub and Gitea configuration
|
||||
- Repository and organization information
|
||||
- Mirroring job history and status
|
||||
- Event notifications and their read status
|
||||
|
||||
## Data Flow
|
||||
|
||||
@@ -93,11 +95,30 @@ SQLite is used for data persistence, storing:
|
||||
gitea-mirror/
|
||||
├── src/ # Source code
|
||||
│ ├── components/ # React components
|
||||
│ ├── content/ # Documentation and content
|
||||
│ ├── layouts/ # Astro layout components
|
||||
│ ├── lib/ # Utility functions and database
|
||||
│ ├── pages/ # Astro pages and API routes
|
||||
│ └── styles/ # CSS and Tailwind styles
|
||||
├── public/ # Static assets
|
||||
├── 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"
|
||||
description: "Guide to configuring Gitea Mirror for your environment."
|
||||
order: 2
|
||||
updatedDate: 2023-10-15
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<div class="mb-6">
|
||||
@@ -24,10 +24,10 @@ The following environment variables can be used to configure Gitea Mirror:
|
||||
| Variable | Description | Default Value | Example |
|
||||
|----------|-------------|---------------|---------|
|
||||
| `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` |
|
||||
| `HOST` | Server host | `localhost` | `0.0.0.0` |
|
||||
| `PORT` | Server port | `3000` | `8080` |
|
||||
| `PORT` | Server port | `4321` | `8080` |
|
||||
|
||||
### Important Security Note
|
||||
|
||||
@@ -118,3 +118,58 @@ Example patterns:
|
||||
- `*` - All repositories
|
||||
- `org-name/*` - All repositories in a specific organization
|
||||
- `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"
|
||||
description: "Get started with Gitea Mirror quickly."
|
||||
order: 3
|
||||
updatedDate: 2023-10-15
|
||||
updatedDate: 2025-05-22
|
||||
---
|
||||
|
||||
<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>
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
### Manual Installation
|
||||
### Using Bun (Native Installation)
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
Note: For Bun-specific features, use:
|
||||
```bash
|
||||
bunx --bun astro dev
|
||||
```
|
||||
|
||||
**Production Mode:**
|
||||
```bash
|
||||
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)
|
||||
|
||||
### 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
|
||||
|
||||
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
|
||||
- Verify your GitHub and Gitea tokens have the correct permissions
|
||||
- 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
|
||||
|
||||
@@ -125,3 +176,7 @@ After your initial setup:
|
||||
- Explore the dashboard for an overview of your mirroring status
|
||||
- Set up automatic mirroring schedules for hands-off operation
|
||||
- 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 }),
|
||||
}),
|
||||
};
|
||||
|
||||
// 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