first deployment of kikomiko with url photos

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
shayan khoshrou
2026-10-19 19:10:57 +02:00
co-authored by Cursor
parent 8d98304137
commit ae3ed7c7b7
159 changed files with 59509 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
Kikomiko Docker deploy (kikomiko.ir)
1) DNS (at your registrar)
A kikomiko.ir -> VPS IP
A www.kikomiko.ir -> VPS IP
A admin.kikomiko.ir -> VPS IP
2) Clone (important: trailing dot so files land IN /kikomiko)
mkdir -p /kikomiko
cd /kikomiko
git clone https://git.sambassari.ir/sam/kikomiko.git .
You should see: docker-compose.yml .env.example kikomiko/ docker/
If you only see a nested kikomiko/ folder, you cloned without the dot.
Fix:
cd /kikomiko/kikomiko
# work from here (where docker-compose.yml is)
# OR move up:
# shopt -s dotglob && mv /kikomiko/kikomiko/* /kikomiko/ && rmdir /kikomiko/kikomiko
3) Env
cp .env.example .env
nano .env # set ADMIN_PASS
# Caddy network on this VPS is usually: webserver_pro_web
4) Start
docker compose up -d --build
5) URLs
https://kikomiko.ir/
https://admin.kikomiko.ir/
fallback: http://VPS_IP:8080/ and http://VPS_IP:8090/
6) Updates
cd ~/kikomiko # (or nested folder where compose file lives)
git pull
docker compose up -d --build
Caddy notes
Labels use caddy-docker-proxy style (caddy: / caddy.reverse_proxy).
If your webserver_pro uses a hand-written Caddyfile instead of labels,
add something like:
kikomiko.ir, www.kikomiko.ir, admin.kikomiko.ir {
reverse_proxy kikomiko-web-1:80
}
(container name from: docker compose ps)
+24
View File
@@ -0,0 +1,24 @@
[Unit]
Description=Kikomiko Admin CMS
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/kikomiko/admin
Environment=ADMIN_USER=admin
# Set a strong password before first start, then remove this line after login
# and change password in the admin UI (Settings).
Environment=ADMIN_PASS=CHANGE_ME_TO_A_STRONG_PASSWORD
ExecStart=/usr/bin/python3 /var/www/kikomiko/admin/server.py --host 127.0.0.1 --port 8090
Restart=on-failure
RestartSec=3
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
ReadWritePaths=/var/www/kikomiko/admin/data /var/www/kikomiko/dist/data
[Install]
WantedBy=multi-user.target
+81
View File
@@ -0,0 +1,81 @@
# Storefront
server {
listen 80;
listen [::]:80;
server_name kikomiko.ir;
root /var/www/kikomiko/dist;
index index.html;
# Block access to anything outside the public storefront tree
location ~ /\. { deny all; }
location = /fa { return 301 /$is_args$args; }
location ~ ^/fa/(.*)$ { return 301 /$1$is_args$args; }
# One shared PDP template — every catalog slug (incl. future imports) hydrates here
location /products/ {
try_files $uri $uri/ /products/index.html;
add_header Cache-Control "no-cache";
}
location / {
try_files $uri $uri/ =404;
add_header Cache-Control "no-cache";
}
# Byte ranges for scroll-driven hero video
location /videos/ {
try_files $uri =404;
add_header Accept-Ranges bytes;
add_header Cache-Control "public, max-age=604800";
}
location /fonts/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=2592000, immutable";
}
location /css/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=604800";
}
location /js/ {
try_files $uri =404;
add_header Cache-Control "public, max-age=604800";
}
# Not implemented yet on this export
location /api/ { return 503; }
location /i/ { return 404; }
error_page 404 /404.html;
}
server {
listen 80;
listen [::]:80;
server_name www.kikomiko.ir;
return 301 http://kikomiko.ir$request_uri;
}
# Admin CMS (proxied to local Python; use HTTPS via certbot)
server {
listen 80;
listen [::]:80;
server_name admin.kikomiko.ir;
client_max_body_size 12m;
location / {
proxy_pass http://127.0.0.1:8090;
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 Cookie $http_cookie;
proxy_pass_header Set-Cookie;
}
}
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env bash
set -euo pipefail
# Usage: ./deploy/rsync-upload.sh user@server [/remote/path]
# Example: ./deploy/rsync-upload.sh root@203.0.113.10
if [[ $# -lt 1 ]]; then
echo "Usage: $0 user@host [remote_root]" >&2
exit 1
fi
HOST="$1"
REMOTE_ROOT="${2:-/var/www/kikomiko}"
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
echo "Uploading storefront -> ${HOST}:${REMOTE_ROOT}/dist/"
rsync -avz --delete \
"${ROOT}/dist/" \
"${HOST}:${REMOTE_ROOT}/dist/"
echo "Uploading admin -> ${HOST}:${REMOTE_ROOT}/admin/"
rsync -avz \
--exclude 'data/*.db' \
--exclude 'data/*.db-*' \
--exclude 'data/.admin-credentials' \
--exclude '__pycache__/' \
--exclude '*.pyc' \
"${ROOT}/admin/" \
"${HOST}:${REMOTE_ROOT}/admin/"
echo "Uploading deploy configs -> ${HOST}:${REMOTE_ROOT}/deploy/"
rsync -avz \
"${ROOT}/deploy/" \
"${HOST}:${REMOTE_ROOT}/deploy/"
ssh "${HOST}" "mkdir -p '${REMOTE_ROOT}/admin/data' '${REMOTE_ROOT}/dist/data' && chmod 750 '${REMOTE_ROOT}/admin/data'"
echo "Done. On the server, follow deploy/DEPLOY.txt for Nginx/systemd/certbot."