feat: add admin API routes for tags, timeline events, uploads, and uses management
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
Some checks failed
Deploy to VPS / deploy (push) Has been cancelled
- Implemented GET and POST endpoints for managing tags in `src/app/api/admin/tags/route.ts`. - Created PUT and DELETE endpoints for timeline events in `src/app/api/admin/timeline/[id]/route.ts`. - Added GET and POST endpoints for timeline management in `src/app/api/admin/timeline/route.ts`. - Developed file upload functionality with validation in `src/app/api/admin/upload/route.ts`. - Introduced PUT and DELETE endpoints for managing uses items in `src/app/api/admin/uses/[id]/route.ts`. - Added GET and POST endpoints for uses management in `src/app/api/admin/uses/route.ts`. feat: enhance admin UI components for better user experience - Created `AdminSidebar` component for navigation in `src/components/admin/AdminSidebar.tsx`. - Developed `ImageUpload` component for handling image uploads in `src/components/admin/ImageUpload.tsx`. - Implemented `RichTextEditor` component for rich text editing in `src/components/admin/RichTextEditor.tsx`. - Added `TagsInput` component for managing tags in `src/components/admin/TagsInput.tsx`. - Created `TiptapRenderer` component for rendering HTML content in `src/components/writing/TiptapRenderer.tsx`. feat: establish database interaction layer with Prisma - Added database connection and session management in `src/lib/db.ts` and `src/lib/auth.ts`. - Implemented CRUD operations for posts, products, projects, settings, timeline events, and uses items in respective files under `src/lib/db/`. - Introduced utility functions for formatting dates and slug generation in `src/lib/types.ts`.
This commit is contained in:
433
nodecloud-server-context.md
Normal file
433
nodecloud-server-context.md
Normal file
@@ -0,0 +1,433 @@
|
||||
# NODE-Cloud Server — Master Context for AI Assistants
|
||||
|
||||
> Last updated: 2026-04-27
|
||||
> Owner: Ali Taghavi (@biztaghavi), CEO of NODE-Group (Novin Ofogh Dadeh Etemad)
|
||||
> Purpose: Paste this into any new Claude/AI chat when working on this server or deploying new apps.
|
||||
|
||||
---
|
||||
|
||||
## 1. Server Overview
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Hostname | `srv9588446167` |
|
||||
| IP | `193.105.234.35` |
|
||||
| OS | Ubuntu 24.04.4 LTS |
|
||||
| Kernel | 6.8.0-107-generic |
|
||||
| CPU | 4 cores (KVM/QEMU) |
|
||||
| RAM | 3.8 GB |
|
||||
| Disk | 145 GB (29 GB used, 116 GB free) |
|
||||
| Swap | None |
|
||||
| Virtualization | KVM |
|
||||
| SSH | Port 22, root access |
|
||||
| Docker | 28.2.2 with Compose 2.37.1 |
|
||||
| Nginx | 1.24.0 |
|
||||
| Certbot | 2.9.0 with auto-renewal timer active |
|
||||
|
||||
---
|
||||
|
||||
## 2. Iran-Specific Constraints (CRITICAL — Read Before Any Deployment)
|
||||
|
||||
This server is hosted in Iran. Several international services are blocked or unreliable:
|
||||
|
||||
### 2.1 Docker Images
|
||||
- **Docker Hub is blocked.** All images must use the ArvanCloud mirror: `docker.arvancloud.ir/library/`
|
||||
- Examples: `docker.arvancloud.ir/library/node:20-alpine`, `docker.arvancloud.ir/library/mariadb:11`, `docker.arvancloud.ir/library/redis:7-alpine`
|
||||
- Docker is configured with mirror: `https://docker-mirror.liara.ir/`
|
||||
|
||||
### 2.2 npm/Node.js Packages
|
||||
- **npmjs.org is intermittently blocked.** Use Liara's npm mirror: `https://package-mirror.liara.ir/repository/npm/`
|
||||
- **npm v10 has a known bug** ("Exit handler never called") — it silently fails and doesn't install packages. Use **pnpm** instead.
|
||||
- **pnpm installation:** Use `corepack enable && corepack prepare pnpm@9 --activate` with `ENV COREPACK_NPM_REGISTRY=https://package-mirror.liara.ir/repository/npm/`
|
||||
- **Liara mirror rate-limits aggressively** — use `--network-concurrency 1` to avoid 429 errors. If rate-limited, wait 10-30 minutes and retry.
|
||||
- **Fallback strategy for large projects:** Install `node_modules` on a Mac/dev machine with unrestricted internet, then `scp` the tarball to the server. When doing this:
|
||||
- Install with `npm install --platform=linux --arch=x64 --libc=musl` to get Linux Alpine binaries
|
||||
- Also manually install native musl binaries: `@next/swc-linux-x64-musl`, `lightningcss-linux-x64-musl`, `@tailwindcss/oxide-linux-x64-musl`
|
||||
- Match SWC version to the exact Next.js version (check `package.json`)
|
||||
- Set `ENV NEXT_SWC_DOWNLOAD_DISABLED=1` in Dockerfile to prevent Next.js from trying to download SWC
|
||||
|
||||
### 2.3 Alpine Linux Packages
|
||||
- **`apk add` is blocked** — `dl-cdn.alpinelinux.org` is unreachable. Never use `apk add` in Dockerfiles. The base `node:20-alpine` image already has what's needed.
|
||||
|
||||
### 2.4 Google Services
|
||||
- **Google Fonts are blocked at build time.** If a project uses `next/font/google`, it must be replaced with `next/font/local` or `@fontsource/*` local packages.
|
||||
- `fonts.googleapis.com` is unreachable during Docker builds.
|
||||
|
||||
### 2.5 Prisma ORM
|
||||
- **`binaries.prisma.sh` is blocked.** Prisma cannot download its engine binaries during build.
|
||||
- **Solution:** Pre-download Prisma engine binaries on a machine with internet access, commit them to the repo in `prisma-binaries/`, and set these env vars in the Dockerfile:
|
||||
```dockerfile
|
||||
ENV PRISMA_QUERY_ENGINE_LIBRARY=/app/prisma-binaries/libquery_engine-linux-musl-openssl-3.0.x.so.node
|
||||
ENV PRISMA_SCHEMA_ENGINE_BINARY=/app/prisma-binaries/schema-engine-linux-musl-openssl-3.0.x
|
||||
ENV PRISMA_ENGINES_CHECKSUM_IGNORE_MISSING=1
|
||||
ENV PRISMA_SKIP_POSTINSTALL_GENERATE=1
|
||||
```
|
||||
- Both `libquery_engine` and `schema-engine` binaries are needed for `linux-musl-openssl-3.0.x` (Alpine).
|
||||
- Run `prisma generate` in the Dockerfile after copying binaries — it uses local files, no network needed.
|
||||
- For migrations, apply SQL files directly: `docker exec -i <mysql_container> mariadb -u user -ppassword dbname < migration.sql`
|
||||
|
||||
### 2.6 MySQL
|
||||
- **MySQL 8.0+ Docker images crash** on this server's CPU (no x86-64-v2 support). Use **MariaDB 11** instead — fully MySQL-compatible.
|
||||
- MariaDB healthcheck: `["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]`
|
||||
|
||||
### 2.7 SSL / Let's Encrypt
|
||||
- **Let's Encrypt cannot reach this server directly** for domains behind ArvanCloud CDN. Certbot fails with timeouts.
|
||||
- **For domains behind ArvanCloud CDN:** Use ArvanCloud's built-in SSL (set mode to "Full" or "Flexible"). No certbot needed.
|
||||
- **For domains pointing directly to the server IP:** Certbot works fine (e.g., pouyatebparto.ir, nodegroup.ir, hooranhr.ir).
|
||||
- A **self-signed certificate** exists at `/etc/ssl/certs/nodecloud-selfsigned.crt` and `/etc/ssl/private/nodecloud-selfsigned.key` — used for domains behind ArvanCloud where ArvanCloud handles public SSL.
|
||||
- **IMPORTANT:** Any new site behind ArvanCloud CDN MUST listen on port 443 with the self-signed cert in Nginx. Otherwise Nginx falls back to the first server block that has SSL (which is git.nodecloud.ir/Gitea) and serves wrong content.
|
||||
|
||||
---
|
||||
|
||||
## 3. Hosted Applications
|
||||
|
||||
### 3.1 Gitea (Self-hosted Git)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `git.nodecloud.ir` |
|
||||
| Container | `gitea` + `gitea-db` |
|
||||
| Port | `127.0.0.1:3000` |
|
||||
| Stack | Gitea 1.25.5 + PostgreSQL 14 |
|
||||
| Compose | `/srv/nodecloud/gitea/docker-compose.yml` |
|
||||
| SSL | Self-signed cert (ArvanCloud CDN handles public SSL) |
|
||||
|
||||
### 3.2 Pouya Teb Parto (Medical Services)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `pouyatebparto.ir` |
|
||||
| Container | `pouya_teb_app` + `pouya_teb_mysql` + `pouya_teb_phpmyadmin` |
|
||||
| Port | `127.0.0.1:3001` |
|
||||
| Stack | Next.js 16 + MariaDB 11 + phpMyAdmin |
|
||||
| Compose | `/srv/nodecloud/apps/pouya-teb-parto/docker-compose.prod.yml` |
|
||||
| Git | `http://git.nodecloud.ir/pouyadolat/Pouya-teb-parto.git` |
|
||||
| SSL | Let's Encrypt (certbot) |
|
||||
| phpMyAdmin | `127.0.0.1:8080` (SSH tunnel only) |
|
||||
|
||||
### 3.3 NODE-Group Website
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `nodegroup.ir` |
|
||||
| Container | `nodegroup_web` |
|
||||
| Port | `127.0.0.1:3002` |
|
||||
| Stack | Static Next.js (exported to HTML, served by Nginx in container) |
|
||||
| Compose | `/srv/nodecloud/apps/nodegroup/docker-compose.prod.yml` |
|
||||
| Git | `http://git.nodecloud.ir/nodegroup/nodegroupirwebsite.git` |
|
||||
| SSL | Let's Encrypt (certbot) |
|
||||
|
||||
### 3.4 Hooran HR (HR Gamification Platform)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `hooranhr.ir`, `www.hooranhr.ir`, `hooranhr.com`, `www.hooranhr.com` |
|
||||
| Container | `hooranhr_app` + `hooranhr_mysql` |
|
||||
| Port | `127.0.0.1:3003` |
|
||||
| Stack | Next.js 16 + MariaDB 11 + DISC assessment |
|
||||
| Compose | `/srv/nodecloud/apps/hooranhr/docker-compose.prod.yml` |
|
||||
| Git | `http://git.nodecloud.ir/nodegroup/hooranhrir.git` |
|
||||
| SSL | Let's Encrypt (certbot, covers all 4 domains) |
|
||||
|
||||
### 3.5 Khanehban (Building Management SaaS)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `khanehbaan.ir` |
|
||||
| Container | `khanehbaan-app-1` + `khanehbaan-mysql-1` + `khanehbaan-redis-1` |
|
||||
| Port | `127.0.0.1:3008` |
|
||||
| Stack | Next.js 16 + MariaDB 11 + Redis 7 + Prisma ORM |
|
||||
| Compose | `/srv/nodecloud/apps/khanehbaan/docker-compose.prod.yml` |
|
||||
| Git | `http://git.nodecloud.ir/nodegroup/khanehbaan-ir.git` |
|
||||
| SSL | ArvanCloud CDN (self-signed cert on server, ArvanCloud "Full" mode) |
|
||||
| S3 Storage | Liara S3 (`storage.c2.liara.space`, bucket: `buildingmanagement`) — remains on Liara |
|
||||
| Special | Prisma with pre-downloaded binaries, node_modules transferred from Mac |
|
||||
|
||||
### 3.6 Portainer (Docker Management UI)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `manage.nodecloud.ir` |
|
||||
| Container | `portainer` |
|
||||
| Port | `127.0.0.1:9000` |
|
||||
| Stack | Portainer CE LTS |
|
||||
| Compose | `/srv/nodecloud/apps/portainer/docker-compose.yml` |
|
||||
| SSL | Self-signed cert (ArvanCloud CDN handles public SSL) |
|
||||
|
||||
### 3.7 Nodecloud.ir (Gateway/Placeholder)
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Domain | `nodecloud.ir`, `www.nodecloud.ir` |
|
||||
| Type | Static text response ("nodecloud main gateway is up") |
|
||||
| Port | 80 only (no SSL, no proxy) |
|
||||
|
||||
---
|
||||
|
||||
## 4. Port Allocation Map
|
||||
|
||||
| Port | Service | Notes |
|
||||
|---|---|---|
|
||||
| 3000 | Gitea | Reserved |
|
||||
| 3001 | Pouya Teb Parto | Next.js app |
|
||||
| 3002 | NODE-Group website | Static Nginx |
|
||||
| 3003 | Hooran HR | Next.js app |
|
||||
| 3004-3007 | Available | — |
|
||||
| 3008 | Khanehban | Next.js + Prisma |
|
||||
| 3009+ | Available | — |
|
||||
| 8080 | phpMyAdmin (Pouya Teb) | SSH tunnel only |
|
||||
| 9000 | Portainer | Docker management UI |
|
||||
|
||||
**Next available port: 3004**
|
||||
|
||||
---
|
||||
|
||||
## 5. Architecture Pattern for New Deployments
|
||||
|
||||
Every app follows this pattern:
|
||||
|
||||
```
|
||||
Internet → ArvanCloud CDN (SSL) → Server:80/443 → Nginx → 127.0.0.1:PORT → Docker Container
|
||||
```
|
||||
|
||||
### 5.1 Directory Structure
|
||||
```
|
||||
/srv/nodecloud/
|
||||
├── gitea/ # Gitea (separate, not under apps/)
|
||||
│ └── docker-compose.yml
|
||||
└── apps/
|
||||
├── pouya-teb-parto/ # Each app gets its own directory
|
||||
│ ├── docker-compose.prod.yml
|
||||
│ ├── Dockerfile
|
||||
│ ├── .env
|
||||
│ └── ... (source code)
|
||||
├── nodegroup/
|
||||
├── hooranhr/
|
||||
├── khanehbaan/
|
||||
└── portainer/
|
||||
```
|
||||
|
||||
### 5.2 Standard Dockerfile Template (Next.js + pnpm)
|
||||
```dockerfile
|
||||
FROM docker.arvancloud.ir/library/node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV PATH="/app/node_modules/.bin:$PATH"
|
||||
ENV COREPACK_NPM_REGISTRY=https://package-mirror.liara.ir/repository/npm/
|
||||
|
||||
RUN corepack enable && corepack prepare pnpm@9 --activate
|
||||
|
||||
COPY package.json ./
|
||||
RUN pnpm config set registry https://package-mirror.liara.ir/repository/npm/ && \
|
||||
pnpm install --no-frozen-lockfile --network-concurrency 1
|
||||
|
||||
COPY . .
|
||||
RUN next build
|
||||
|
||||
FROM docker.arvancloud.ir/library/node:20-alpine AS runner
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
|
||||
RUN addgroup --system --gid 1001 nodejs && \
|
||||
adduser --system --uid 1001 nextjs
|
||||
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||
|
||||
USER nextjs
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server.js"]
|
||||
```
|
||||
|
||||
> **Note:** `next.config` must have `output: "standalone"` for this to work.
|
||||
|
||||
### 5.3 Standard docker-compose.prod.yml Template
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
container_name: APPNAME_app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:PORT:3000"
|
||||
env_file: .env
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
|
||||
# Only if app needs a database:
|
||||
mysql:
|
||||
image: docker.arvancloud.ir/library/mariadb:11
|
||||
container_name: APPNAME_mysql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
|
||||
MYSQL_DATABASE: ${MYSQL_DATABASE}
|
||||
MYSQL_USER: ${MYSQL_USER}
|
||||
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
# Only if app needs Redis:
|
||||
redis:
|
||||
image: docker.arvancloud.ir/library/redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
redis_data:
|
||||
```
|
||||
|
||||
### 5.4 Nginx Config Template
|
||||
|
||||
**For domains with direct DNS (certbot possible):**
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name DOMAIN.ir www.DOMAIN.ir;
|
||||
|
||||
client_max_body_size 20M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:PORT;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 60;
|
||||
proxy_send_timeout 60;
|
||||
}
|
||||
}
|
||||
```
|
||||
Then: `certbot --nginx -d DOMAIN.ir -d www.DOMAIN.ir`
|
||||
|
||||
**For domains behind ArvanCloud CDN (MUST include SSL block):**
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
server_name DOMAIN.ir www.DOMAIN.ir;
|
||||
|
||||
ssl_certificate /etc/ssl/certs/nodecloud-selfsigned.crt;
|
||||
ssl_certificate_key /etc/ssl/private/nodecloud-selfsigned.key;
|
||||
|
||||
client_max_body_size 20M;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:PORT;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_read_timeout 60;
|
||||
proxy_send_timeout 60;
|
||||
}
|
||||
}
|
||||
```
|
||||
In ArvanCloud: SSL mode = "Full", origin = `193.105.234.35`, purge cache after setup.
|
||||
|
||||
---
|
||||
|
||||
## 6. Deployment Checklist for New Sites
|
||||
|
||||
1. **Clone repo** to `/srv/nodecloud/apps/APPNAME/`
|
||||
2. **Fix Dockerfile** for Iran: replace `node:20-alpine` with `docker.arvancloud.ir/library/node:20-alpine`, remove any `apk add`, use pnpm with Liara mirror
|
||||
3. **Fix Google Fonts** if present: grep for `next/font/google` and replace
|
||||
4. **Create `.env`** from `.env.example` with real credentials
|
||||
5. **Use MariaDB 11** instead of MySQL 8.x
|
||||
6. **Set port** in `docker-compose.prod.yml` to next available (currently 3004+)
|
||||
7. **Build:** `docker compose -f docker-compose.prod.yml build --no-cache`
|
||||
8. **Launch:** `docker compose -f docker-compose.prod.yml up -d`
|
||||
9. **Verify:** `curl -s http://127.0.0.1:PORT | head -5`
|
||||
10. **Run migrations** if needed (apply SQL directly to MariaDB container)
|
||||
11. **Create Nginx config** in `/etc/nginx/sites-available/`, symlink to `sites-enabled/`
|
||||
12. **SSL:** Either certbot (direct DNS) or self-signed + ArvanCloud CDN
|
||||
13. **Test:** `curl -I https://DOMAIN`
|
||||
|
||||
---
|
||||
|
||||
## 7. Common Operations
|
||||
|
||||
### Redeploy an app after code changes
|
||||
```bash
|
||||
cd /srv/nodecloud/apps/APPNAME
|
||||
git pull
|
||||
# Re-fix Dockerfile if git pull overwrote it
|
||||
docker compose -f docker-compose.prod.yml build --no-cache
|
||||
docker compose -f docker-compose.prod.yml up -d
|
||||
```
|
||||
|
||||
### View all container status
|
||||
```bash
|
||||
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||||
```
|
||||
|
||||
### View resource usage
|
||||
```bash
|
||||
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
|
||||
```
|
||||
|
||||
### View logs for an app
|
||||
```bash
|
||||
cd /srv/nodecloud/apps/APPNAME
|
||||
docker compose -f docker-compose.prod.yml logs -f app
|
||||
```
|
||||
|
||||
### Restart an app
|
||||
```bash
|
||||
cd /srv/nodecloud/apps/APPNAME
|
||||
docker compose -f docker-compose.prod.yml restart
|
||||
```
|
||||
|
||||
### Access phpMyAdmin (Pouya Teb) via SSH tunnel
|
||||
From your Mac:
|
||||
```bash
|
||||
ssh -L 8080:127.0.0.1:8080 root@193.105.234.35
|
||||
```
|
||||
Then open `http://localhost:8080`
|
||||
|
||||
### Full server health check
|
||||
```bash
|
||||
echo "=== CONTAINERS ===" && docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" && echo "" && echo "=== RESOURCES ===" && docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Firewall (UFW)
|
||||
|
||||
Only three ports are open:
|
||||
- **22** (SSH)
|
||||
- **80** (HTTP)
|
||||
- **443** (HTTPS)
|
||||
|
||||
All Docker container ports are bound to `127.0.0.1` — not publicly accessible. Nginx is the only public-facing service.
|
||||
|
||||
---
|
||||
|
||||
## 9. Known Issues & Gotchas
|
||||
|
||||
1. **git pull overwrites Dockerfile** — After pulling, always re-apply Iran-specific fixes (image mirrors, apk removal, pnpm config). Consider committing a `Dockerfile.prod` to the repo instead.
|
||||
2. **No swap configured** — With 3.8 GB RAM and ~1.8 GB used, there's ~2 GB headroom. Adding more apps may require adding swap or upgrading RAM.
|
||||
3. **DNS resolver on server is slow** — `dig` commands sometimes time out. This doesn't affect app operation, only manual DNS lookups from the server.
|
||||
4. **ArvanCloud CDN caching** — After any Nginx config change, always purge ArvanCloud cache and test in incognito.
|
||||
5. **Self-signed cert is shared** — `git.nodecloud.ir`, `manage.nodecloud.ir`, and `khanehbaan.ir` all use the same self-signed cert. This is fine because ArvanCloud handles public SSL.
|
||||
6. **Certbot auto-renewal** is active but will only renew certs for domains with direct DNS (not behind ArvanCloud CDN).
|
||||
7. **No automated backups** — Docker volumes for databases are not backed up. Consider setting up periodic `mysqldump` cron jobs.
|
||||
8. **Portainer times out** if admin account isn't created quickly after restart. Run `docker restart portainer` and immediately access the UI.
|
||||
Reference in New Issue
Block a user