2024-01-12
29 阅读
原本简单部署后,日志里发现了好多漏扫以及各种报错,然后跟着AI折腾了大半天,终于重新部署完成,记录下。
1. UWSGI 参考配置文件
# UWSGI.INI 参考配置文件
[uwsgi]
# --- 用户权限 ---
uid = www-data
gid = www-data
# Django 项目配置
chdir = /srv/www/codenotes/
# Django 的 WSGI 入口文件
module = codenotes.wsgi
# 虚拟环境路径
virtualenv = /srv/work_env/codenotes_env/
# python 插件
plugin = python3
# 指定插件文件绝对路径
# plugin = /usr/lib/uwsgi/plugins/python311_plugin.so
# 主进程
master = true
# 工作进程数量:通常设置为 CPU 核心数
processes = 2
# 每个进程的线程数
threads = 2
# 显式启用线程支持
enable-threads = true
# --- 通信配置 (Unix Socket 高性能)---
socket = /var/run/uwsgi/codenotes.sock
# 设置 socket 权限,确保 Nginx 用户(通常是 www-data)可以读取
chmod-socket = 660
# 兜底权限
chown-socket = www-data:www-data
# 当 uwsgi 停止时,删除 socket 文件
vacuum = true
# --- 资源限制与稳定性 (防止内存泄漏) ---
# 每个工作进程在处理指定数量的请求后自动重启
max-requests = 5000
# 重启进程时的平滑过渡,避免请求丢失
max-requests-delta = 500
# 如果单个请求超过 60 秒,杀死该进程
harakiri = 90
# 内存超1024MB自动重启
reload-on-rss = 1024
# 防止请求队列堆积导致 OOM
listen = 100
# --- 日志配置 ---
# 日志文件路径
logto = /srv/log/uwsgi.log
# 日志轮转大小 30M,防止日志文件无限增长
log-maxsize = 31457280
# 日志级别
log-level = warning
# 记录客户端IP
log-x-forwarded-for = true
# 建议:开启日志轮转时的信号处理,平滑切割
log-reopen = true
# --- 其他性能优化 ---
# 主进程加载应用,节省内存
lazy-apps = true
buffer-size = 32768
# 静态文件转发缓冲区
post-buffering = 65536
ignore-sigpipe = true
ignore-write-errors = true
# 指定uwsgi临时文件目录
tmpdir = /tmp/
# 优雅退出
die-on-term = true
disable-logging = false
# 【新增】优雅处理中断
thunder-lock = true
2. UWSGI 配置文件链接
# 配置文件链接至 etc/uwsgi/apps-enabled/ 目录
ln -s /srv/www/codenotes/uwsgi.ini /etc/uwsgi/apps-enabled/uwsgi.ini
3. 配置 UWSGI 自启动服务, 文件目录: /etc/systemd/system/codenotes.service 创建并配置完成后,重新加载下: systemctl daemon-reload
参考配置如下:
[Unit]
Description=uWSGI Emperor for CodeNotes Django Project
Documentation=man:uwsgi(1)
# 确保在网络就绪后启动,且必须在 Nginx 之前启动
After=network.target network-online.target syslog.target
Wants=network-online.target
[Service]
# 强制服务以 root 启动 (这样 ExecStartPre 和主进程都有权限)
User=root
Group=root
# 允许写入 /var/run
ReadWritePaths=/var/run/
# 预执行命令
ExecStartPre=/bin/mkdir -p /var/run/uwsgi/
ExecStartPre=/bin/chown -R www-data:www-data /var/run/uwsgi/
ExecStartPre=/bin/chmod 755 /var/run/uwsgi/
# --- 启动命令 ---
# 有链接配置文件到 /etc/uwsgi/apps-enabled 目录时,可以不需要下面方式,要不然会多启动一个。
# 方式 A: 直接指定 ini 文件路径 (推荐)
# ExecStart=/srv/work_env/codenotes_env/bin/uwsgi --ini /srv/www/codenotes/uwsgi.ini
# 方式 B: 如果使用全局安装的 uwsgi (非虚拟环境),则改为:
# ExecStart=/usr/bin/uwsgi --ini /srv/www/codenotes/uwsgi.ini
# 注意:请确保 ExecStart 指向的是真实的 uwsgi 二进制文件路径。
# 如果不确定,可以在终端运行 'which uwsgi' 或激活虚拟环境后运行 'which uwsgi' 查看路径。
# --- 重启策略 ---
# 当进程意外退出时自动重启
Restart=always
RestartSec=5s
# --- 环境变量 (可选) ---
# 如果 Django 需要特定的环境变量,可以在这里添加
Environment="DJANGO_SETTINGS_MODULE=codenotes.settings"
Environment="PATH=/srv/work_env/codenotes_env/bin/"
# --- 资源限制 (可选,防止内存泄漏拖垮系统) ---
# LimitNOFILE=65535
# LimitNPROC=65535
# --- 日志处理 ---
# 将输出发送到 systemd journal (可以通过 journalctl -u uwsgi-codenotes 查看)
StandardOutput=journal
StandardError=journal
# 如果你更倾向于 uwsgi.ini 中配置的 logto 文件,可以注释掉上面两行,或者保留它们作为备份
# --- 安全加固 ---
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
# 允许写入日志目录和 socket 目录 (需要根据实际路径调整 ReadWritePaths)
ReadWritePaths=/srv/log/ /var/run/uwsgi/ /srv/www/codenotes/
[Install]
# 开机自启目标
WantedBy=multi-user.target
4. Nginx 参考配置
# --------------------------
# 全局上游定义 (Upstream)
# --------------------------
upstream django_codenotes {
# 修改为 Unix Socket 路径
# 必须与你 uwsgi.ini 中的 socket 路径完全一致
server unix:/var/run/uwsgi/codenotes.sock;
}
# 定义恶意路径匹配规则 (大小写不敏感)
# 如果 URI 匹配到以下任意正则,$block_scanner 变为 1,否则为 0
map $request_uri $block_scanner {
default 0;
# 常见后台/管理路径
~*^/(wp-admin|wp-login|administrator|phpmyadmin|pma|mysql|webadmin|shell|cmd|console|manager|login|signin|auth|api) 1;
# 常见敏感文件/备份
~*^/.(php|git|svn|htaccess|htpasswd|env|config|bak|backup|sql|tar|gz|zip|rar|7z) 1;
# 常见漏洞利用路径
~*^/(solr|actuator|eureka|swagger|api-docs) 1;
~*^/(cgi-bin|scripts|bin|tmp) 1;
~*\.(asp|aspx|jsp|jspx|php5|phtml|pl|py|rb|sh|exe|bat|cmd)$ 1;
# 特定漏洞探测字符串
~*\$(\{|%24\{) 1; # Log4j JNDI 特征
~*union.*select 1; # 基础 SQL 注入探测
~*(\.\.\/|\.\.%2f|\%2e\%2e\/|\%2e\%2e\%2f) 1; # 目录遍历
}
# --------------------------
# 1. HTTP 80 端口:强制跳转 HTTPS + 去除 www
# --------------------------
server {
listen 80;
listen [::]:80;
server_name codenotes.cn www.codenotes.cn ;
# 逻辑:
# 1. 如果是 www,跳转到非 www 的 https
# 2. 如果不是 www,直接跳转到 https
if ($host = www.codenotes.cn) { return 301 https://$host$request_uri; } # managed by Certbot
if ($host = codenotes.cn) { return 301 https://$host$request_uri; } # managed by Certbot
# 关闭日志(跳转请求无需记录)
access_log off;
log_not_found off;
}
# --------------------------
# HTTPS: codenotes.cn
# --------------------------
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name codenotes.cn;
# 拦截恶意扫描路径
if ($block_scanner) {
return 444; # 444表示直接关闭连接,不返回任何响应
}
# 限制 HTTP 方法 (只允许常用方法)
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|DELETE|PATCH)$) {
return 405;
}
# SSL 证书
ssl_certificate /etc/letsencrypt/live/codenotes.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/codenotes.cn/privkey.pem; # managed by Certbot
# 引入通用 SSL 优化配置 (也可写在里面)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
# OpenSSL 3.0 兼容的加密套件(优先 TLS1.3 套件,兼顾 TLS1.2)
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# 曲线名
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 安全隐藏版本号
server_tokens off;
# --- 性能优化:静态资源处理 ---
# 开启零拷贝
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 开启 Gzip 压缩 (显著减少传输体积)
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;
# 静态文件 (Static)
location /static/ {
alias /srv/www/codenotes/static/;
expires 30d;
add_header Cache-Control "public, max-age=2592000" always;
add_header X-Content-Type-Options nosniff always;
access_log off; # 静态文件不记录日志,提升 IO 性能
}
# 媒体文件 (Media)
location /media/ {
alias /srv/www/codenotes/media/;
expires 30d;
add_header Cache-Control "public, max-age=2592000" always;
access_log off;
}
# 动态请求 (Django/uWSGI)
location / {
# 使用 uWSGI 协议
uwsgi_pass django_codenotes;
include uwsgi_params;
# uWSGI 专用参数设置 (比 proxy_set_header 更准确)
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $scheme;
# 优化 Buffer,避免大请求写入临时文件
uwsgi_buffer_size 128k;
uwsgi_buffers 8 256k;
uwsgi_busy_buffers_size 512k;
# 超时设置 (根据业务调整,防止长任务被切断)
uwsgi_read_timeout 60s;
uwsgi_send_timeout 60s;
uwsgi_connect_timeout 60s;
}
# 基础配置
client_max_body_size 5M; # 适当增大上传限制
charset utf-8;
access_log /srv/log/codenotes.access.log main if=$block_scanner=0;
error_log /srv/log/codenotes.error.log warn;
}
# --------------------------
# HTTPS: www 子域名跳转
# --------------------------
# www.codenotes.cn -> codenotes.cn
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.codenotes.cn;
# 拦截恶意扫描路径
if ($block_scanner) {
return 444; # 444表示直接关闭连接,不返回任何响应
}
# 限制 HTTP 方法 (只允许常用方法)
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS|PUT|DELETE|PATCH)$) {
return 405;
}
# 必须加载 codenotes 的证书,否则浏览器会报证书不安全,无法完成跳转
ssl_protocols TLSv1.2 TLSv1.3;
ssl_certificate /etc/letsencrypt/live/codenotes.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/codenotes.cn/privkey.pem; # managed by Certbot
# 301 永久跳转到非 www
return 301 https://codenotes.cn$request_uri;
}
请一定注意各文件及文件夹的用户及权限,尤其像 /var/run/、/tmp/ 日志文件及文件夹等等,在这块折腾了好久…
发现 /var/share/uwsgi/conf/ 下还有个default.ini ,依据上述配置,会把这个也起来,删除后,需要把自启动服务里的 # ExecStart=/usr/bin/uwsgi --ini /srv/www/codenotes/uwsgi.ini 备注取消!!要不然会异常!!
验证各服务后完成部署。
2023-12-30
44 阅读
Django项目下有三个应用:blog、work、yuge,然后有三个域名,codenotes.cn、 yugemetal.com 和 yugemetal.cn,希望blog对应codenotes.cn,work对应codenotes.cn/work/,yuge对应yugemetal.com和yugemetal.cn。
参考各种资料及踩坑后,完成相应配置,大致操作记录如下。
1. 安装 django-hosts
pip install django-hosts
2. 添加应用及配置参数
# 非完整代码,仅参考
# codenotes/settings.py
# 增加应用
INSTALLED_APPS = [
# ... 内置应用等
'django_hosts', # 新增
'blog',
'work',
'yuge',
]
# 增加 django_hosts 中间件
# 'django_hosts.middleware.HostsRequestMiddleware' 必须在所有中间件最前面
# 'django_hosts.middleware.HostsResponseMiddleware' 必须在所有中间件最后面
MIDDLEWARE = [
'django_hosts.middleware.HostsRequestMiddleware', # <--- 放在最前面
# ... 其他常规中间件 (Security, Session, Common, Csrf, Auth, Message, Clickjacking等)
'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',
'django_hosts.middleware.HostsResponseMiddleware', # <--- 放在最后面
]
# 配置 django-hosts
ROOT_HOSTCONF = 'codenotes.hosts' # 指向创建的 hosts.py 文件
DEFAULT_HOST = 'blog' # 默认主机名
3. 创建 hosts 文件
# codenotes/hosts.py
from django_hosts import patterns, host
# 域名与应用路由的映射
host_patterns = patterns(
'',
# codenotes.cn 绑定 blog 应用的 urls
host(r'^codenotes\.cn$', 'codenotes.urls', name='blog'),
# yugemetal.com 绑定 yuge 应用的 urls,注意,此处需新增一个 urls_yuge.py 文件
host('^yugemetal\.com$', 'yuge.urls_yuge', name='yuge_com'),
host('^yugemetal\.cn$', 'yuge.urls_yuge', name='yuge_cn'),
)
4. codenotes/urls.py
# 非完整代码,仅参考
# codenotes/urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('work/', include(('work.urls', 'work'), namespace='work')),
path('', include(('blog.urls', 'blog'), namespace='blog')),
]
5. blog/urls.py
# 非完整代码,仅参考
# blog/urls.py
# 必须添加app_name
app_name = 'blog'
urlpatterns = [
path('about/', views.about, name='about'),
path('timeline/', views.timeline, name='timeline'),
path('article/<int:article_id>', views.article, name='article'),
path('', views.index, name='index'),
]
6. work/urls.py
# 非完整代码,仅参考
# work/urls.py
app_name = 'work'
urlpatterns = [
path('condition/core/', views.monitor_core, name='monitor_core'),
]
7. yuge/urls.py
# 非完整代码,仅参考
# yuge/urls.py
app_name = 'yuge'
urlpatterns = [
path('', views.index, name='index'),
]
8. 新增 yuge/urls_yuge.py
# yuge/urls_yuge.py
from django.urls import path, include
urlpatterns = [
# yugemetal.com/ 根路径对应yuge应用
path('', include(('yuge.urls', 'yuge'), namespace='yuge')),
]
9. templates 中使用
<!-- templates/app/xxx.html -->
<!-- 页面模板中使用时,必须先加载 hosts -->
{% load hosts %}
<ul class="nav-menu" id="navMenu">
<!-- 用 host_url 替换默认的 url,参数照常放,在最后面增加 host 对应名称 -->
<li><a href="{% host_url 'yuge:index' host 'yuge' %}#home" class="nav-link active">首页</a></li>
<li><a href="{% host_url 'blog:tag' tag.id host 'blog' %}" class="tag"></li>
</ul>
<!-- 之前只有个 .com 域名 ,后来增加了 .cn,然后上面的实现就比较局限了,修改如下 -->
<ul class="nav-menu" id="navMenu">
<li><a href="https://{{ request.get_host }}#home" class="nav-link active">首页</a></li>
<li><a href="https://{{ request.get_host }}/tag/{{ tag.id }} %}" class="tag"></li>
</ul>
10. nginx 正常配置
# 动态请求 (Django/uWSGI)
location / {
# 使用 uWSGI 协议
uwsgi_pass django_codenotes;
include uwsgi_params;
# uWSGI 专用参数设置 (比 proxy_set_header 更准确)
uwsgi_param Host $host; # !!留意此条,根据域名区分!!
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $scheme;
}
OVER…
其中折腾最久的是页面提示 NoReverseMatch, 一开始是 hosts 中的 blog 的 url 未对应正确,对应到应用 blog 下的 urls.py 去了,实际需要对应项目的 urls.py,即 codenotes/urls.py;然后 yuge 用现有的 urls.py 无法正常显示页面,一直提示 NoReverseMatch,新建了 yuge/yuge_ursl.py 并配置相关内容后,页面及相关链接全部显示正常。
至此,目标达成。
https://codenotes.cn 正常显示博客,
https://codenotes.cn/work/ 正常显示 work 相关内容
https://yugemetal.com https://yugemetal.cn 都正常显示宇格金属,且能正常交互。
2023-12-25
38 阅读
Django默认登录只有用户名密码,存在一定安全隐患,想着提高下,用 django-simple-captcha 实现。
1. 安装 django-simple-captcha
# 如无 pillow,需安装才可正常使用
# pip install pillow
pip install django-simple-captcha
2. 添加应用及配置
# settings
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 添加应用
'captcha',
]
# 验证码图片宽度/高度
CAPTCHA_IMAGE_SIZE = (100, 40)
# 验证码字符长度(数学公式时不生效)
CAPTCHA_LENGTH = 4
# 验证码字符类型:字母数字混合(可选值:'numeric'纯数字 / 'alphabetic'纯字母 / 'alphanumeric'混合)
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
# 数学公式验证码(替代上述字符验证码)
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
# 验证码过期时间(秒)
CAPTCHA_TIMEOUT = 5 * 60 # 5分钟
# 干扰线数量(0=无干扰线,数值越大干扰越强)
CAPTCHA_NOISE_FUNCTIONS = (
'captcha.helpers.noise_arcs', # 弧形干扰线
'captcha.helpers.noise_dots', # 点状干扰
)
# 验证码背景色(RGB)
CAPTCHA_BACKGROUND_COLOR = '#ffffff'
# 验证码文字颜色(RGB)
CAPTCHA_FOREGROUND_COLOR = '#001100'
3. 执行 python manage.py migrate
4. 新增验证码表单
# 新建 project/forms.py
from django import forms
from django.contrib.admin.forms import AdminAuthenticationForm
from captcha.fields import CaptchaField
class AdminCaptchaAuthenticationForm(AdminAuthenticationForm):
# 新增验证码字段,label 可自定义显示文本
captcha = CaptchaField(label='验证码')
# 保留原有的 admin 登录验证逻辑,仅新增验证码校验
def clean(self):
# 先执行父类的 clean 方法(验证用户名密码)
cleaned_data = super().clean()
# 验证码的校验由 CaptchaField 自动完成,无需额外处理
return cleaned_data
5. 新增视图
# 新建 project/views.py
from django.contrib.admin.sites import AdminSite
from django.contrib.auth.views import LoginView
from .captcha_forms import AdminCaptchaAuthenticationForm
class AdminCaptchaLoginView(LoginView):
# 指定自定义表单
form_class = AdminCaptchaAuthenticationForm
# 复用 admin 登录模板
template_name = 'admin/login.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
admin_site = AdminSite()
context.update({
'site_title': admin_site.site_title,
'site_header': admin_site.site_header,
'site_url': admin_site.site_url,
'title': '管理员登录',
})
return context
6. 新增有验证码的 login.html 替换默认登录页面
# 新建 project/codenotes/templates/admin.py
<!-- templates/admin/login.html -->
{% extends "admin/base_site.html" %}
{% load i18n static %}
{% block extrastyle %}{{ block.super }}
<link rel="stylesheet" href="{% static "admin/css/login.css" %}">
{{ form.media }} <!-- 新增:加载验证码所需的静态资源 -->
<style>
/* 控制验证码图片垂直对齐,与输入框居中 */
.captcha {
vertical-align: middle;
margin-bottom: 3px;
border: none;
}
/* 调整验证码输入框的高度,与图片更匹配 */
input[name="captcha_1"] {
height: 25px;
}
</style>
{% endblock %}
{% block bodyclass %}{{ block.super }} login{% endblock %}
{% block nav-breadcrumbs %}{% endblock %}
{% block content_title %}{% endblock %}
{% block content %}
{% if form.errors and not form.non_field_errors %}
<p class="errornote">
{% blocktranslate count counter=form.errors.items|length %}Please correct the error below.{% plural %}Please
correct the errors below.{% endblocktranslate %}
</p>
{% endif %}
{% if form.non_field_errors %}
{% for error in form.non_field_errors %}
<p class="errornote">
{{ error }}
</p>
{% endfor %}
{% endif %}
<div id="content-main">
{% if user.is_authenticated %}
<p class="errornote">
{% blocktranslate trimmed %}
You are authenticated as {{ username }}, but are not authorized to access this page.
Would you like to login to a different account?
{% endblocktranslate %}
</p>
{% endif %}
<form action="{{ app_path }}" method="post" id="login-form">{% csrf_token %}
<div class="form-row">
{{ form.username.errors }}
{{ form.username.label_tag }} {{ form.username }}
</div>
<div class="form-row">
{{ form.password.errors }}
{{ form.password.label_tag }} {{ form.password }}
<input type="hidden" name="next" value="{{ next }}">
</div>
<!-- 新增:验证码字段渲染 -->
<div class="form-row">
{{ form.captcha.errors }} <!-- 验证码错误提示 -->
{{ form.captcha.label_tag }} {{ form.captcha }} <!-- 验证码标签 + 输入框 + 图片 -->
</div>
{% url 'admin_password_reset' as password_reset_url %}
{% if password_reset_url %}
<div class="password-reset-link">
<a href="{{ password_reset_url }}">{% translate 'Forgotten your password or username?' %}</a>
</div>
{% endif %}
<div class="submit-row">
<input type="submit" value="{% translate 'Log in' %}">
</div>
</form>
</div>
{% endblock %}
7. 添加路由
# urls
urlpatterns = [
# 增加路由
path('captcha/', include('captcha.urls')),
]
完成测试看是否成功。
2023-12-23
43 阅读
习惯使用Django-CKeditor实现博客后台的富文本输入,但发现少个代码高亮功能,几经查找,发现其有内置的代码块功能:codesnippet,用此插件就可以实现代码高亮功能,且自带不少常见主题,原理为通过highlight.js实现。
1. 参考配置参数,调出代码按钮
CKEDITOR_CONFIGS = {
'default': {
"skin": "moono-lisa",
"toolbar_Basic": [["Source", "-", "Bold", "Italic"]],
"toolbar_Full": [
["Styles", "Format", "Bold", "Italic", "Underline", "Strike"],
["Blockquote", "Link", "Unlink"],
["Image", "Table", "HorizontalRule"],
["NumberedList", "BulletedList", "JustifyLeft", "JustifyCenter", "JustifyRight", "JustifyBlock"],
["TextColor", "BGColor", ],
["CodeSnippet", "Source"],
],
"toolbar": "Full",
"height": 500,
"width": 860,
"filebrowserWindowWidth": 940,
"filebrowserWindowHeight": 725,
'extraPlugins': 'codesnippet',
'tabSpaces': 4,
'allowedContent': True,
# 配置后台语法高亮主题
'codeSnippet_theme': 'monokai',
# 配置后台显示支持语言,格式:{语言标识: 显示名称}
'codeSnippet_languages': {
'bash': 'Bash',
'css': 'CSS',
'html': 'HTML',
'ini': 'INI',
'javascript': 'JavaScript',
'json': 'JSON',
'nginx': 'Nginx',
'python': 'Python',
'sql': 'SQL',
},
}
}
2. 前台使用
<!-- django-ckeditor 自带的highlight版本比较低,推荐用highlightjs官网最新的js -->
<!-- 喜欢的高亮主题 -->
<link href="{% static 'blog/css/atom-one-dark.min.css' %}" rel="stylesheet">
<!-- highlight.js文件 -->
<script src="{% static 'blog/js/highlight.min.js' %}"></script>
<!-- 调用highlight -->
<script>hljs.highlightAll();</script>
3. 补充
部分超长代码不会自动换行问题,可以在.css文件中添加white-space: pre-wrap; 可实现正常显示自动换行。
.hljs {
border-radius: 0.5rem; # 代码框圆角
white-space: pre-wrap; # 代码超长自动换行
}