第一个项目
This commit is contained in:
15
check_live.sh
Normal file
15
check_live.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
echo "=== 关键配置验证 ==="
|
||||||
|
echo "1. Socket文件权限:"
|
||||||
|
ls -l /home/xiaji/myproject/myproject.sock
|
||||||
|
echo -e "\n2. Nginx代理配置:"
|
||||||
|
sudo grep -A5 'location /' /etc/nginx/sites-available/family_rpa
|
||||||
|
echo -e "\n3. Gunicorn服务配置:"
|
||||||
|
sudo grep -E 'ExecStart|WorkingDirectory' /etc/systemd/system/family_rpa.service
|
||||||
|
echo -e "\n4. 实时错误日志:"
|
||||||
|
sudo tail -f /var/log/nginx/error.log
|
||||||
|
EOF
|
||||||
23
check_status.sh
Normal file
23
check_status.sh
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
echo "=== 网络连接检查 ==="
|
||||||
|
nc -zv $SERVER_IP 80
|
||||||
|
nc -zv $SERVER_IP 8000
|
||||||
|
|
||||||
|
echo -e "\n=== 服务状态检查 ==="
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
echo "## Nginx状态 ##"
|
||||||
|
sudo systemctl status nginx | head -n 5
|
||||||
|
|
||||||
|
echo -e "\n## Gunicorn服务状态 ##"
|
||||||
|
sudo systemctl status family_rpa.service | head -n 5
|
||||||
|
|
||||||
|
echo -e "\n## 端口监听情况 ##"
|
||||||
|
sudo netstat -tulpn | grep -E ':80|:8000'
|
||||||
|
|
||||||
|
echo -e "\n## 最近错误日志 ##"
|
||||||
|
sudo tail -n 20 /var/log/nginx/error.log
|
||||||
|
sudo journalctl -u family_rpa.service --since "5 minutes ago" | tail -n 10
|
||||||
|
EOF
|
||||||
40
deploy.sh
Normal file
40
deploy.sh
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
DEPLOY_DIR="/home/xiaji/deploy_$(date +%s)"
|
||||||
|
LOG_FILE="$DEPLOY_DIR/deploy.log"
|
||||||
|
|
||||||
|
# 上传公钥
|
||||||
|
ssh-copy-id -i ~/.ssh/id_rsa.pub $USER@$SERVER_IP
|
||||||
|
|
||||||
|
# 执行远程部署
|
||||||
|
ssh $USER@$SERVER_IP << EOF
|
||||||
|
set -e
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y python3-pip python3-venv nginx
|
||||||
|
|
||||||
|
mkdir -p $DEPLOY_DIR
|
||||||
|
tar -xzvf ~/family_rpa.tar.gz -C $DEPLOY_DIR
|
||||||
|
|
||||||
|
python3 -m venv $DEPLOY_DIR/venv
|
||||||
|
source $DEPLOY_DIR/venv/bin/activate
|
||||||
|
pip install -r $DEPLOY_DIR/family_rpa/requirements.txt
|
||||||
|
|
||||||
|
# 生产配置检查
|
||||||
|
if ! grep -q "DEBUG = False" $DEPLOY_DIR/family_rpa/family_rpa/settings.py; then
|
||||||
|
echo "ERROR: 未检测到生产环境配置" | tee -a $LOG_FILE
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 迁移数据库
|
||||||
|
python $DEPLOY_DIR/family_rpa/manage.py migrate
|
||||||
|
python $DEPLOY_DIR/family_rpa/manage.py collectstatic --noinput
|
||||||
|
|
||||||
|
# 切换部署版本
|
||||||
|
sudo systemctl stop family_rpa.service
|
||||||
|
sudo rm -rf /home/xiaji/myproject
|
||||||
|
mv $DEPLOY_DIR/family_rpa /home/xiaji/myproject
|
||||||
|
sudo systemctl start family_rpa.service
|
||||||
|
|
||||||
|
echo "部署成功!访问地址:http://$SERVER_IP" | tee -a $LOG_FILE
|
||||||
|
EOF
|
||||||
BIN
family_rpa.tar.gz
Normal file
BIN
family_rpa.tar.gz
Normal file
Binary file not shown.
BIN
family_rpa/db.sqlite3
Normal file
BIN
family_rpa/db.sqlite3
Normal file
Binary file not shown.
12
family_rpa/family_rpa.service
Normal file
12
family_rpa/family_rpa.service
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Gunicorn instance to serve family_rpa
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=xiaji
|
||||||
|
Group=www-data
|
||||||
|
WorkingDirectory=/project/family_rpa
|
||||||
|
ExecStart=/project/family_rpa/venv/bin/gunicorn --workers 3 --bind unix:/project/family_rpa/family_rpa.sock family_rpa.wsgi:application
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
0
family_rpa/family_rpa/__init__.py
Normal file
0
family_rpa/family_rpa/__init__.py
Normal file
BIN
family_rpa/family_rpa/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
family_rpa/family_rpa/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/family_rpa/__pycache__/settings.cpython-313.pyc
Normal file
BIN
family_rpa/family_rpa/__pycache__/settings.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/family_rpa/__pycache__/urls.cpython-313.pyc
Normal file
BIN
family_rpa/family_rpa/__pycache__/urls.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/family_rpa/__pycache__/wsgi.cpython-313.pyc
Normal file
BIN
family_rpa/family_rpa/__pycache__/wsgi.cpython-313.pyc
Normal file
Binary file not shown.
16
family_rpa/family_rpa/asgi.py
Normal file
16
family_rpa/family_rpa/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for family_rpa project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'family_rpa.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
||||||
152
family_rpa/family_rpa/settings.py
Normal file
152
family_rpa/family_rpa/settings.py
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
"""
|
||||||
|
Django settings for family_rpa project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 5.1.4.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
|
||||||
|
|
||||||
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
|
SECRET_KEY = 'django-insecure-+&-sio8(2$n#^@367@&w(ld5z024&%mamr5z$pf3kx!m^l+rxs'
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = True
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'django_crontab',
|
||||||
|
'main',
|
||||||
|
]
|
||||||
|
|
||||||
|
CRONJOBS = [
|
||||||
|
('0 0 * * *', 'main.management.commands.cleanup_messages')
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'family_rpa.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'family_rpa.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': BASE_DIR / 'db.sqlite3',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'zh-hans'
|
||||||
|
|
||||||
|
TIME_ZONE = 'Asia/Shanghai'
|
||||||
|
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/5.1/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = 'static/'
|
||||||
|
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'assets')]
|
||||||
|
|
||||||
|
MEDIA_URL = 'media/'
|
||||||
|
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
LOGIN_REDIRECT_URL = 'admin:index'
|
||||||
8
family_rpa/family_rpa/urls.py
Normal file
8
family_rpa/family_rpa/urls.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
path('', include('main.urls')),
|
||||||
|
path('accounts/', include('django.contrib.auth.urls')),
|
||||||
|
]
|
||||||
16
family_rpa/family_rpa/wsgi.py
Normal file
16
family_rpa/family_rpa/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for family_rpa project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'family_rpa.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
20
family_rpa/gunicorn_config.py
Normal file
20
family_rpa/gunicorn_config.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# 绑定的地址和端口
|
||||||
|
bind = '127.0.0.1:8000'
|
||||||
|
# 工作进程数量,通常设置为 CPU 核心数的 2 倍 + 1
|
||||||
|
workers = 3
|
||||||
|
# 工作模式,使用异步的 gevent 模式
|
||||||
|
worker_class = 'gevent'
|
||||||
|
# 每个工作进程处理的最大请求数,超过该数后工作进程会重启
|
||||||
|
max_requests = 1000
|
||||||
|
# 最大请求数的抖动值,避免所有工作进程同时重启
|
||||||
|
max_requests_jitter = 50
|
||||||
|
# 超时时间
|
||||||
|
timeout = 30
|
||||||
|
# 访问日志路径
|
||||||
|
accesslog = '/var/log/gunicorn/access.log'
|
||||||
|
# 错误日志路径
|
||||||
|
errorlog = '/var/log/gunicorn/error.log'
|
||||||
|
# 日志级别
|
||||||
|
loglevel = 'info'
|
||||||
|
# 后台运行
|
||||||
|
daemon = True
|
||||||
0
family_rpa/main/__init__.py
Normal file
0
family_rpa/main/__init__.py
Normal file
BIN
family_rpa/main/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/admin.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/admin.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/apps.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/apps.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/forms.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/forms.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/models.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/models.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/urls.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/urls.cpython-313.pyc
Normal file
Binary file not shown.
BIN
family_rpa/main/__pycache__/views.cpython-313.pyc
Normal file
BIN
family_rpa/main/__pycache__/views.cpython-313.pyc
Normal file
Binary file not shown.
16
family_rpa/main/admin.py
Normal file
16
family_rpa/main/admin.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import File, Message
|
||||||
|
|
||||||
|
@admin.register(File)
|
||||||
|
class FileAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('file', 'owner', 'created_at', 'is_public')
|
||||||
|
list_filter = ('is_public', 'created_at')
|
||||||
|
search_fields = ('file', 'description')
|
||||||
|
date_hierarchy = 'created_at'
|
||||||
|
|
||||||
|
@admin.register(Message)
|
||||||
|
class MessageAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('author', 'content', 'created_at', 'ip_address')
|
||||||
|
list_filter = ('created_at', 'ip_address')
|
||||||
|
search_fields = ('author', 'content')
|
||||||
|
date_hierarchy = 'created_at'
|
||||||
6
family_rpa/main/apps.py
Normal file
6
family_rpa/main/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class MainConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'main'
|
||||||
18
family_rpa/main/forms.py
Normal file
18
family_rpa/main/forms.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from django import forms
|
||||||
|
from .models import File, Message
|
||||||
|
|
||||||
|
class FileUploadForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = File
|
||||||
|
fields = ['file', 'description', 'is_public']
|
||||||
|
widgets = {
|
||||||
|
'description': forms.Textarea(attrs={'rows': 3}),
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Message
|
||||||
|
fields = ['author', 'content']
|
||||||
|
widgets = {
|
||||||
|
'content': forms.Textarea(attrs={'rows': 5}),
|
||||||
|
}
|
||||||
11
family_rpa/main/management/commands/cleanup_messages.py
Normal file
11
family_rpa/main/management/commands/cleanup_messages.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import timezone
|
||||||
|
from ...models import Message
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Clean up messages older than 7 days'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
one_week_ago = timezone.now() - timezone.timedelta(days=7)
|
||||||
|
deleted_count, _ = Message.objects.filter(created_at__lt=one_week_ago).delete()
|
||||||
|
self.stdout.write(self.style.SUCCESS(f'Successfully deleted {deleted_count} old messages'))
|
||||||
41
family_rpa/main/migrations/0001_initial.py
Normal file
41
family_rpa/main/migrations/0001_initial.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2025-02-15 13:07
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Message',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('author', models.CharField(max_length=100)),
|
||||||
|
('content', models.TextField()),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('ip_address', models.GenericIPAddressField(blank=True, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'ordering': ['-created_at'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='File',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('file', models.FileField(upload_to='uploads/')),
|
||||||
|
('description', models.TextField(blank=True)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('is_public', models.BooleanField(default=False)),
|
||||||
|
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
21
family_rpa/main/migrations/0002_alter_file_owner.py
Normal file
21
family_rpa/main/migrations/0002_alter_file_owner.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.1.4 on 2025-02-15 13:51
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0001_initial'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='file',
|
||||||
|
name='owner',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
family_rpa/main/migrations/__init__.py
Normal file
0
family_rpa/main/migrations/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
BIN
family_rpa/main/migrations/__pycache__/__init__.cpython-313.pyc
Normal file
BIN
family_rpa/main/migrations/__pycache__/__init__.cpython-313.pyc
Normal file
Binary file not shown.
25
family_rpa/main/models.py
Normal file
25
family_rpa/main/models.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
class File(models.Model):
|
||||||
|
owner = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
file = models.FileField(upload_to='uploads/')
|
||||||
|
description = models.TextField(blank=True)
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
is_public = models.BooleanField(default=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.file.name
|
||||||
|
|
||||||
|
class Message(models.Model):
|
||||||
|
author = models.CharField(max_length=100)
|
||||||
|
content = models.TextField()
|
||||||
|
created_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
ip_address = models.GenericIPAddressField(null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"来自 {self.author} 的留言"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['-created_at']
|
||||||
3
family_rpa/main/tests.py
Normal file
3
family_rpa/main/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
9
family_rpa/main/urls.py
Normal file
9
family_rpa/main/urls.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('', views.home, name='home'),
|
||||||
|
path('upload/', views.upload_file, name='upload'),
|
||||||
|
path('delete/<int:file_id>/', views.delete_file, name='delete'),
|
||||||
|
path('message/', views.post_message, name='message'),
|
||||||
|
]
|
||||||
53
family_rpa/main/views.py
Normal file
53
family_rpa/main/views.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.core.files.storage import default_storage
|
||||||
|
from django.core.paginator import Paginator
|
||||||
|
from .models import File, Message
|
||||||
|
from .forms import FileUploadForm, MessageForm
|
||||||
|
from django.utils.timezone import timedelta
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
# 获取最近一周的留言
|
||||||
|
one_week_ago = timezone.now() - timedelta(days=7)
|
||||||
|
messages = Message.objects.filter(created_at__gte=one_week_ago).order_by('-created_at')
|
||||||
|
|
||||||
|
# 获取公开文件
|
||||||
|
files = File.objects.filter(is_public=True).order_by('-created_at')
|
||||||
|
|
||||||
|
return render(request, 'main/home.html', {
|
||||||
|
'messages': messages,
|
||||||
|
'files': files
|
||||||
|
})
|
||||||
|
|
||||||
|
def upload_file(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = FileUploadForm(request.POST, request.FILES)
|
||||||
|
if form.is_valid():
|
||||||
|
file = form.save(commit=False)
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
file.owner = request.user
|
||||||
|
file.save()
|
||||||
|
return redirect('home')
|
||||||
|
else:
|
||||||
|
form = FileUploadForm()
|
||||||
|
return render(request, 'main/upload.html', {'form': form})
|
||||||
|
|
||||||
|
def delete_file(request, file_id):
|
||||||
|
file = get_object_or_404(File, id=file_id)
|
||||||
|
if request.user == file.owner:
|
||||||
|
file.file.delete()
|
||||||
|
file.delete()
|
||||||
|
return redirect('home')
|
||||||
|
|
||||||
|
def post_message(request):
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = MessageForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
message = form.save(commit=False)
|
||||||
|
message.ip_address = request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR'))
|
||||||
|
message.save()
|
||||||
|
return redirect('home')
|
||||||
|
else:
|
||||||
|
form = MessageForm()
|
||||||
|
return render(request, 'main/message.html', {'form': form})
|
||||||
22
family_rpa/manage.py
Normal file
22
family_rpa/manage.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'family_rpa.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
family_rpa/media/uploads/vac470lite.zip
Normal file
BIN
family_rpa/media/uploads/vac470lite.zip
Normal file
Binary file not shown.
BIN
family_rpa/media/uploads/vac470lite_0dVajUD.zip
Normal file
BIN
family_rpa/media/uploads/vac470lite_0dVajUD.zip
Normal file
Binary file not shown.
BIN
family_rpa/media/uploads/vac470lite_Tr7wrZb.zip
Normal file
BIN
family_rpa/media/uploads/vac470lite_Tr7wrZb.zip
Normal file
Binary file not shown.
BIN
family_rpa/media/uploads/vac470lite_cct4sWa.zip
Normal file
BIN
family_rpa/media/uploads/vac470lite_cct4sWa.zip
Normal file
Binary file not shown.
20
family_rpa/nginx.config
Normal file
20
family_rpa/nginx.config
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name 192.168.3.105;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://unix:/project/family_rpa/family_rpa.sock;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /static/ {
|
||||||
|
alias /project/family_rpa/static/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /media/ {
|
||||||
|
alias /project/family_rpa/media/;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
family_rpa/requirements.txt
Normal file
0
family_rpa/requirements.txt
Normal file
107
family_rpa/static/output.css
Normal file
107
family_rpa/static/output.css
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*! tailwindcss v4.0.6 | MIT License | https://tailwindcss.com */
|
||||||
|
.static {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.mx-auto {
|
||||||
|
margin-inline: auto;
|
||||||
|
}
|
||||||
|
.block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
.w-full {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.grid-cols-1 {
|
||||||
|
grid-template-columns: repeat(1, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
.items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.justify-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.border {
|
||||||
|
border-style: var(--tw-border-style);
|
||||||
|
border-width: 1px;
|
||||||
|
}
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.filter {
|
||||||
|
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
|
||||||
|
}
|
||||||
|
.\[w\:۵qzg\] {
|
||||||
|
w: ۵qzg;
|
||||||
|
}
|
||||||
|
@layer base {
|
||||||
|
:root {
|
||||||
|
--color-primary: 79 70 229;
|
||||||
|
--color-secondary: 99 102 241;
|
||||||
|
--color-accent: 249 115 22;
|
||||||
|
--color-success: 16 185 129;
|
||||||
|
--color-warning: 245 158 11;
|
||||||
|
--color-error: 239 68 68;
|
||||||
|
--color-surface: 255 255 255;
|
||||||
|
--color-background: 249 250 251;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
--color-primary: 99 102 241;
|
||||||
|
--color-secondary: 129 140 248;
|
||||||
|
--color-accent: 249 115 22;
|
||||||
|
--color-success: 16 185 129;
|
||||||
|
--color-warning: 245 158 11;
|
||||||
|
--color-error: 239 68 68;
|
||||||
|
--color-surface: 31 41 55;
|
||||||
|
--color-background: 17 24 39;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@property --tw-border-style {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
initial-value: solid;
|
||||||
|
}
|
||||||
|
@property --tw-blur {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-brightness {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-contrast {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-grayscale {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-hue-rotate {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-invert {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-opacity {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-saturate {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
|
@property --tw-sepia {
|
||||||
|
syntax: "*";
|
||||||
|
inherits: false;
|
||||||
|
}
|
||||||
BIN
family_rpa/tailwindcss-windows-x64.exe
Normal file
BIN
family_rpa/tailwindcss-windows-x64.exe
Normal file
Binary file not shown.
49
family_rpa/templates/base.html
Normal file
49
family_rpa/templates/base.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-hans">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>家庭RPA系统</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body class="bg-light">
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="{% url 'home' %}">首页</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'upload' %}">上传文件</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'message' %}">发布留言</a>
|
||||||
|
</li>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'admin:index' %}">管理后台</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'logout' %}">注销</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'login' %}">登录</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="container mt-4">
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
37
family_rpa/templates/main/home.html
Normal file
37
family_rpa/templates/main/home.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 class="h2 mb-4">最新留言</h2>
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<span class="fw-bold">{{ message.author }}</span>
|
||||||
|
<span class="text-muted small">{{ message.created_at|date:"Y-m-d H:i" }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">{{ message.content }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 class="h2 mb-4">公开文件</h2>
|
||||||
|
{% for file in files %}
|
||||||
|
<div class="card mb-3">
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
|
<a href="{{ file.file.url }}" class="fw-bold text-decoration-none">
|
||||||
|
{{ file.file.name }}
|
||||||
|
</a>
|
||||||
|
<span class="text-muted small">{{ file.created_at|date:"Y-m-d H:i" }}</span>
|
||||||
|
</div>
|
||||||
|
<p class="card-text">{{ file.description }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
20
family_rpa/templates/main/message.html
Normal file
20
family_rpa/templates/main/message.html
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h1 class="h2 mb-4">发布留言</h1>
|
||||||
|
<form method="post" class="card p-4">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
{{ form.as_p }}
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
发布留言
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
33
family_rpa/templates/main/upload.html
Normal file
33
family_rpa/templates/main/upload.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h1 class="h2 mb-4">上传文件</h1>
|
||||||
|
<form method="post" enctype="multipart/form-data" class="card p-4">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="{{ form.file.id_for_label }}" class="form-label">选择文件</label>
|
||||||
|
{{ form.file }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="{{ form.description.id_for_label }}" class="form-label">文件描述</label>
|
||||||
|
{{ form.description }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3 form-check">
|
||||||
|
{{ form.is_public }}
|
||||||
|
<label for="{{ form.is_public.id_for_label }}" class="form-check-label">
|
||||||
|
公开文件(勾选后文件将对所有人可见)
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
上传文件
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
15
family_rpa/templates/registration/logged_out.html
Normal file
15
family_rpa/templates/registration/logged_out.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 class="h2 mb-4">已注销</h2>
|
||||||
|
|
||||||
|
<p class="mb-4">您已成功注销。</p>
|
||||||
|
|
||||||
|
<a href="{% url 'login' %}" class="link-primary">重新登录</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
39
family_rpa/templates/registration/login.html
Normal file
39
family_rpa/templates/registration/login.html
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h2 class="h2 mb-4">登录</h2>
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class="alert alert-danger mb-4">
|
||||||
|
用户名或密码错误,请重试。
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">用户名</label>
|
||||||
|
{{ form.username }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">密码</label>
|
||||||
|
{{ form.password }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-primary w-100">
|
||||||
|
登录
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="mt-4 text-center">
|
||||||
|
<a href="#" class="link-primary">忘记密码?</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
25
final_fix.sh
Normal file
25
final_fix.sh
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
# 修复权限问题
|
||||||
|
sudo chown xiaji:www-data /home/xiaji/myproject/myproject.sock
|
||||||
|
sudo chmod 660 /home/xiaji/myproject/myproject.sock
|
||||||
|
|
||||||
|
# 确认配置有效性
|
||||||
|
sudo nginx -t && sudo systemctl reload nginx
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl restart family_rpa.service
|
||||||
|
|
||||||
|
# 验证服务状态
|
||||||
|
echo -e "\n=== 最终服务状态 ==="
|
||||||
|
sudo systemctl status family_rpa.service --no-pager | head -n 10
|
||||||
|
sudo ss -nltp | grep -E ':80|.sock'
|
||||||
|
|
||||||
|
# 开放防火墙
|
||||||
|
sudo ufw allow 80/tcp
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 本地验证
|
||||||
|
curl -v --connect-timeout 10 http://$SERVER_IP
|
||||||
21
final_validate.sh
Normal file
21
final_validate.sh
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
echo "=== 最终状态验证 ==="
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
echo "1. 服务运行状态:"
|
||||||
|
sudo systemctl is-active family_rpa.service nginx
|
||||||
|
|
||||||
|
echo -e "\n2. 端口监听情况:"
|
||||||
|
sudo netstat -tulpn | grep -E ':80|.sock'
|
||||||
|
|
||||||
|
echo -e "\n3. 最新访问日志:"
|
||||||
|
sudo tail -n 5 /var/log/nginx/access.log
|
||||||
|
|
||||||
|
echo -e "\n4. 资源使用情况:"
|
||||||
|
free -h && df -h
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "\n=== 本地访问测试 ==="
|
||||||
|
curl -sS -o /dev/null -w "HTTP状态码: %{http_code}\n响应时间: %{time_total}s\n" http://$SERVER_IP
|
||||||
23
fix_services.sh
Normal file
23
fix_services.sh
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
# 修正Nginx配置
|
||||||
|
sudo sed -i "s/proxy_pass http:\/\/127.0.0.1:8000;/proxy_pass http:\/\/unix:\/home\/xiaji\/myproject\/myproject.sock;/g" /etc/nginx/sites-available/family_rpa
|
||||||
|
|
||||||
|
# 修正Gunicorn绑定方式
|
||||||
|
sudo sed -i "s/--bind 0.0.0.0:8000/--bind unix:\/home\/xiaji\/myproject\/myproject.sock/g" /etc/systemd/system/family_rpa.service
|
||||||
|
|
||||||
|
# 设置socket权限
|
||||||
|
echo "UMASK=007" | sudo tee -a /etc/systemd/system/family_rpa.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
|
||||||
|
# 重启服务
|
||||||
|
sudo systemctl restart family_rpa.service
|
||||||
|
sudo systemctl restart nginx
|
||||||
|
|
||||||
|
# 验证配置
|
||||||
|
sudo nginx -t
|
||||||
|
sudo ss -alnpt | grep -E '80|.sock'
|
||||||
|
EOF
|
||||||
30
full_diagnose.sh
Normal file
30
full_diagnose.sh
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SERVER_IP="192.168.3.105"
|
||||||
|
USER="xiaji"
|
||||||
|
|
||||||
|
echo "=== 服务状态深度检查 ==="
|
||||||
|
ssh $USER@$SERVER_IP << 'EOF'
|
||||||
|
echo "1. Gunicorn服务状态:"
|
||||||
|
sudo systemctl status family_rpa.service --no-pager
|
||||||
|
|
||||||
|
echo -e "\n2. Nginx服务状态:"
|
||||||
|
sudo systemctl status nginx --no-pager
|
||||||
|
|
||||||
|
echo -e "\n3. Socket文件检查:"
|
||||||
|
ls -l /home/xiaji/myproject/myproject.sock
|
||||||
|
stat /home/xiaji/myproject/myproject.sock
|
||||||
|
|
||||||
|
echo -e "\n4. 进程关联验证:"
|
||||||
|
sudo lsof -U | grep myproject.sock
|
||||||
|
|
||||||
|
echo -e "\n5. 权限配置检查:"
|
||||||
|
groups www-data
|
||||||
|
getent group www-data
|
||||||
|
|
||||||
|
echo -e "\n6. 最新错误日志:"
|
||||||
|
sudo tail -30 /var/log/nginx/error.log
|
||||||
|
sudo journalctl -u family_rpa.service --since "5 minutes ago" --no-pager
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo -e "\n=== 本地网络验证 ==="
|
||||||
|
curl -v --connect-timeout 10 http://$SERVER_IP
|
||||||
BIN
tailwindcss-windows-x64.exe
Normal file
BIN
tailwindcss-windows-x64.exe
Normal file
Binary file not shown.
10
upload_commands.txt
Normal file
10
upload_commands.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
sudo rm -rf /project
|
||||||
|
sudo mkdir -p /project
|
||||||
|
sudo chown -R xiaji:xiaji /project
|
||||||
|
rsync -avz --progress family_rpa xiaji@192.168.3.105:/project/
|
||||||
|
sudo cp /project/family_rpa/nginx.config /etc/nginx/sites-available/family_rpa
|
||||||
|
sudo cp /project/family_rpa/family_rpa.service /etc/systemd/system/
|
||||||
|
sudo ln -sf /etc/nginx/sites-available/family_rpa /etc/nginx/sites-enabled/
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl restart nginx
|
||||||
|
sudo systemctl start family_rpa
|
||||||
Reference in New Issue
Block a user