[{"data":1,"prerenderedAt":1635},["ShallowReactive",2],{"docs-nav":3,"/docs/installation/vps":60},[4],{"title":5,"path":6,"stem":7,"children":8,"page":59},"Docs","/docs","docs",[9,27,45],{"title":10,"path":11,"stem":12,"children":13,"page":-1},"Premiers pas","/docs/getting-started","docs/1.getting-started/index",[14,15,19,23],{"title":10,"path":11,"stem":12},{"title":16,"path":17,"stem":18},"Introduction","/docs/getting-started/introduction","docs/1.getting-started/1.introduction",{"title":20,"path":21,"stem":22},"Claim, Adopt, Fork","/docs/getting-started/concepts","docs/1.getting-started/2.concepts",{"title":24,"path":25,"stem":26},"Architecture","/docs/getting-started/architecture","docs/1.getting-started/3.architecture",{"title":28,"path":29,"stem":30,"children":31,"page":-1},"Installation","/docs/installation","docs/2.installation/index",[32,33,37,41],{"title":28,"path":29,"stem":30},{"title":34,"path":35,"stem":36},"Déploiement Docker","/docs/installation/docker","docs/2.installation/1.docker",{"title":38,"path":39,"stem":40},"Déploiement VPS","/docs/installation/vps","docs/2.installation/2.vps",{"title":42,"path":43,"stem":44},"Déploiement Alwaysdata","/docs/installation/alwaysdata","docs/2.installation/3.alwaysdata",{"title":46,"path":47,"stem":48,"children":49,"page":-1},"Administration","/docs/administration","docs/3.administration/index",[50,51,55],{"title":46,"path":47,"stem":48},{"title":52,"path":53,"stem":54},"Configuration","/docs/administration/configuration","docs/3.administration/1.configuration",{"title":56,"path":57,"stem":58},"Maintenance","/docs/administration/maintenance","docs/3.administration/2.maintenance",false,{"id":61,"title":38,"body":62,"description":1630,"extension":1631,"meta":1632,"navigation":159,"path":39,"seo":1633,"stem":40,"__hash__":1634},"docs/docs/2.installation/2.vps.md",{"type":63,"value":64,"toc":1613},"minimark",[65,69,85,90,106,109,113,297,299,303,353,355,359,424,432,451,506,534,538,595,598,600,604,813,815,819,1094,1096,1100,1121,1124,1126,1130,1133,1171,1177,1192,1194,1198,1201,1213,1402,1411,1413,1417,1494,1496,1500,1609],[66,67,38],"h1",{"id":68},"déploiement-vps",[70,71,72,76,77,80,81,84],"p",{},[73,74,75],"strong",{},"Difficulté"," : Intermédiaire | ",[73,78,79],{},"Temps"," : 1–2 h | ",[73,82,83],{},"Coût"," : 5–20 €/mois",[86,87,89],"h2",{"id":88},"prérequis","Prérequis",[91,92,93,97,100,103],"ul",{},[94,95,96],"li",{},"VPS Debian 12+ ou Ubuntu 22.04+",[94,98,99],{},"Accès root ou sudo",[94,101,102],{},"Domaine pointant vers l'IP du VPS",[94,104,105],{},"Ports 80 et 443 ouverts",[107,108],"hr",{},[86,110,112],{"id":111},"_1-préparation-du-serveur","1. Préparation du serveur",[114,115,120],"pre",{"className":116,"code":117,"language":118,"meta":119,"style":119},"language-bash shiki shiki-themes github-light github-dark","sudo apt update && sudo apt upgrade -y\n\nsudo apt install -y \\\n    python3.12 python3.12-venv python3.12-dev \\\n    postgresql postgresql-contrib \\\n    nginx \\\n    git \\\n    certbot python3-certbot-nginx \\\n    build-essential libpq-dev\n\n# Créer l'utilisateur applicatif\nsudo useradd -m -s /bin/bash suddenly\nsudo mkdir -p /opt/suddenly\nsudo chown suddenly:suddenly /opt/suddenly\n","bash","",[121,122,123,154,161,177,191,202,210,218,229,238,243,250,270,284],"code",{"__ignoreMap":119},[124,125,128,132,136,139,143,145,147,150],"span",{"class":126,"line":127},"line",1,[124,129,131],{"class":130},"sScJk","sudo",[124,133,135],{"class":134},"sZZnC"," apt",[124,137,138],{"class":134}," update",[124,140,142],{"class":141},"sVt8B"," && ",[124,144,131],{"class":130},[124,146,135],{"class":134},[124,148,149],{"class":134}," upgrade",[124,151,153],{"class":152},"sj4cs"," -y\n",[124,155,157],{"class":126,"line":156},2,[124,158,160],{"emptyLinePlaceholder":159},true,"\n",[124,162,164,166,168,171,174],{"class":126,"line":163},3,[124,165,131],{"class":130},[124,167,135],{"class":134},[124,169,170],{"class":134}," install",[124,172,173],{"class":152}," -y",[124,175,176],{"class":152}," \\\n",[124,178,180,183,186,189],{"class":126,"line":179},4,[124,181,182],{"class":134},"    python3.12",[124,184,185],{"class":134}," python3.12-venv",[124,187,188],{"class":134}," python3.12-dev",[124,190,176],{"class":152},[124,192,194,197,200],{"class":126,"line":193},5,[124,195,196],{"class":134},"    postgresql",[124,198,199],{"class":134}," postgresql-contrib",[124,201,176],{"class":152},[124,203,205,208],{"class":126,"line":204},6,[124,206,207],{"class":134},"    nginx",[124,209,176],{"class":152},[124,211,213,216],{"class":126,"line":212},7,[124,214,215],{"class":134},"    git",[124,217,176],{"class":152},[124,219,221,224,227],{"class":126,"line":220},8,[124,222,223],{"class":134},"    certbot",[124,225,226],{"class":134}," python3-certbot-nginx",[124,228,176],{"class":152},[124,230,232,235],{"class":126,"line":231},9,[124,233,234],{"class":134},"    build-essential",[124,236,237],{"class":134}," libpq-dev\n",[124,239,241],{"class":126,"line":240},10,[124,242,160],{"emptyLinePlaceholder":159},[124,244,246],{"class":126,"line":245},11,[124,247,249],{"class":248},"sJ8bj","# Créer l'utilisateur applicatif\n",[124,251,253,255,258,261,264,267],{"class":126,"line":252},12,[124,254,131],{"class":130},[124,256,257],{"class":134}," useradd",[124,259,260],{"class":152}," -m",[124,262,263],{"class":152}," -s",[124,265,266],{"class":134}," /bin/bash",[124,268,269],{"class":134}," suddenly\n",[124,271,273,275,278,281],{"class":126,"line":272},13,[124,274,131],{"class":130},[124,276,277],{"class":134}," mkdir",[124,279,280],{"class":152}," -p",[124,282,283],{"class":134}," /opt/suddenly\n",[124,285,287,289,292,295],{"class":126,"line":286},14,[124,288,131],{"class":130},[124,290,291],{"class":134}," chown",[124,293,294],{"class":134}," suddenly:suddenly",[124,296,283],{"class":134},[107,298],{},[86,300,302],{"id":301},"_2-base-de-données-postgresql","2. Base de données PostgreSQL",[114,304,306],{"className":116,"code":305,"language":118,"meta":119,"style":119},"sudo -u postgres psql \u003C\u003C 'EOF'\nCREATE USER suddenly WITH PASSWORD 'motdepasse-securise';\nCREATE DATABASE suddenly OWNER suddenly;\nGRANT ALL PRIVILEGES ON DATABASE suddenly TO suddenly;\n\\q\nEOF\n",[121,307,308,328,333,338,343,348],{"__ignoreMap":119},[124,309,310,312,315,318,321,325],{"class":126,"line":127},[124,311,131],{"class":130},[124,313,314],{"class":152}," -u",[124,316,317],{"class":134}," postgres",[124,319,320],{"class":134}," psql",[124,322,324],{"class":323},"szBVR"," \u003C\u003C",[124,326,327],{"class":134}," 'EOF'\n",[124,329,330],{"class":126,"line":156},[124,331,332],{"class":134},"CREATE USER suddenly WITH PASSWORD 'motdepasse-securise';\n",[124,334,335],{"class":126,"line":163},[124,336,337],{"class":134},"CREATE DATABASE suddenly OWNER suddenly;\n",[124,339,340],{"class":126,"line":179},[124,341,342],{"class":134},"GRANT ALL PRIVILEGES ON DATABASE suddenly TO suddenly;\n",[124,344,345],{"class":126,"line":193},[124,346,347],{"class":134},"\\q\n",[124,349,350],{"class":126,"line":204},[124,351,352],{"class":134},"EOF\n",[107,354],{},[86,356,358],{"id":357},"_3-application","3. Application",[114,360,362],{"className":116,"code":361,"language":118,"meta":119,"style":119},"sudo -u suddenly bash \u003C\u003C 'EOF'\ncd /opt/suddenly\ngit clone https://github.com/RebelliousSmile/suddenly.git app\ncd app\npython3.12 -m venv venv\nsource venv/bin/activate\npip install --upgrade pip\npip install -e \".[federation]\"\npip install gunicorn\nEOF\n",[121,363,364,380,385,390,395,400,405,410,415,420],{"__ignoreMap":119},[124,365,366,368,370,373,376,378],{"class":126,"line":127},[124,367,131],{"class":130},[124,369,314],{"class":152},[124,371,372],{"class":134}," suddenly",[124,374,375],{"class":134}," bash",[124,377,324],{"class":323},[124,379,327],{"class":134},[124,381,382],{"class":126,"line":156},[124,383,384],{"class":134},"cd /opt/suddenly\n",[124,386,387],{"class":126,"line":163},[124,388,389],{"class":134},"git clone https://github.com/RebelliousSmile/suddenly.git app\n",[124,391,392],{"class":126,"line":179},[124,393,394],{"class":134},"cd app\n",[124,396,397],{"class":126,"line":193},[124,398,399],{"class":134},"python3.12 -m venv venv\n",[124,401,402],{"class":126,"line":204},[124,403,404],{"class":134},"source venv/bin/activate\n",[124,406,407],{"class":126,"line":212},[124,408,409],{"class":134},"pip install --upgrade pip\n",[124,411,412],{"class":126,"line":220},[124,413,414],{"class":134},"pip install -e \".[federation]\"\n",[124,416,417],{"class":126,"line":231},[124,418,419],{"class":134},"pip install gunicorn\n",[124,421,422],{"class":126,"line":240},[124,423,352],{"class":134},[425,426,428,429],"h3",{"id":427},"configuration-env","Configuration ",[121,430,431],{},".env",[114,433,435],{"className":116,"code":434,"language":118,"meta":119,"style":119},"sudo -u suddenly nano /opt/suddenly/app/.env\n",[121,436,437],{"__ignoreMap":119},[124,438,439,441,443,445,448],{"class":126,"line":127},[124,440,131],{"class":130},[124,442,314],{"class":152},[124,444,372],{"class":134},[124,446,447],{"class":134}," nano",[124,449,450],{"class":134}," /opt/suddenly/app/.env\n",[114,452,454],{"className":116,"code":453,"language":118,"meta":119,"style":119},"DJANGO_SETTINGS_MODULE=config.settings.production\nSECRET_KEY=votre-cle-secrete-longue\nDOMAIN=votre-domaine.com\nALLOWED_HOSTS=votre-domaine.com\nDATABASE_URL=postgres://suddenly:motdepasse-securise@localhost:5432/suddenly\n",[121,455,456,467,477,487,496],{"__ignoreMap":119},[124,457,458,461,464],{"class":126,"line":127},[124,459,460],{"class":141},"DJANGO_SETTINGS_MODULE",[124,462,463],{"class":323},"=",[124,465,466],{"class":134},"config.settings.production\n",[124,468,469,472,474],{"class":126,"line":156},[124,470,471],{"class":141},"SECRET_KEY",[124,473,463],{"class":323},[124,475,476],{"class":134},"votre-cle-secrete-longue\n",[124,478,479,482,484],{"class":126,"line":163},[124,480,481],{"class":141},"DOMAIN",[124,483,463],{"class":323},[124,485,486],{"class":134},"votre-domaine.com\n",[124,488,489,492,494],{"class":126,"line":179},[124,490,491],{"class":141},"ALLOWED_HOSTS",[124,493,463],{"class":323},[124,495,486],{"class":134},[124,497,498,501,503],{"class":126,"line":193},[124,499,500],{"class":141},"DATABASE_URL",[124,502,463],{"class":323},[124,504,505],{"class":134},"postgres://suddenly:motdepasse-securise@localhost:5432/suddenly\n",[507,508,509],"blockquote",{},[70,510,511,513,514,517,518,521,522,525,526,529,530,533],{},[121,512,460],{}," est indispensable : ",[121,515,516],{},"manage.py"," pointe par défaut sur les settings de ",[73,519,520],{},"développement",". Sans cette ligne, vos migrations s'appliqueraient avec ",[121,523,524],{},"DEBUG=True"," et la mauvaise base. Les cookies ",[121,527,528],{},"Secure",", HSTS et ",[121,531,532],{},"DEBUG=False"," viennent du module de production — il n'y a pas de variable à poser pour ça.",[425,535,537],{"id":536},"initialisation","Initialisation",[114,539,541],{"className":116,"code":540,"language":118,"meta":119,"style":119},"sudo -u suddenly bash \u003C\u003C 'EOF'\ncd /opt/suddenly/app\nsource venv/bin/activate\nset -a; source .env; set +a\npython manage.py migrate\npython manage.py createcachetable\npython manage.py collectstatic --noinput\npython manage.py createsuperuser\nEOF\n",[121,542,543,557,562,566,571,576,581,586,591],{"__ignoreMap":119},[124,544,545,547,549,551,553,555],{"class":126,"line":127},[124,546,131],{"class":130},[124,548,314],{"class":152},[124,550,372],{"class":134},[124,552,375],{"class":134},[124,554,324],{"class":323},[124,556,327],{"class":134},[124,558,559],{"class":126,"line":156},[124,560,561],{"class":134},"cd /opt/suddenly/app\n",[124,563,564],{"class":126,"line":163},[124,565,404],{"class":134},[124,567,568],{"class":126,"line":179},[124,569,570],{"class":134},"set -a; source .env; set +a\n",[124,572,573],{"class":126,"line":193},[124,574,575],{"class":134},"python manage.py migrate\n",[124,577,578],{"class":126,"line":204},[124,579,580],{"class":134},"python manage.py createcachetable\n",[124,582,583],{"class":126,"line":212},[124,584,585],{"class":134},"python manage.py collectstatic --noinput\n",[124,587,588],{"class":126,"line":220},[124,589,590],{"class":134},"python manage.py createsuperuser\n",[124,592,593],{"class":126,"line":231},[124,594,352],{"class":134},[70,596,597],{},"Les clés RSA de fédération ne se génèrent pas à la main : Suddenly crée les clés d'instance au premier besoin, et une paire par acteur à sa création.",[107,599],{},[86,601,603],{"id":602},"_4-service-systemd-gunicorn","4. Service systemd (Gunicorn)",[114,605,607],{"className":116,"code":606,"language":118,"meta":119,"style":119},"sudo mkdir -p /var/log/suddenly\nsudo chown suddenly:suddenly /var/log/suddenly\n\nsudo tee /etc/systemd/system/suddenly.service \u003C\u003C 'EOF'\n[Unit]\nDescription=Suddenly Gunicorn Daemon\nAfter=network.target postgresql.service\n\n[Service]\nUser=suddenly\nGroup=suddenly\nWorkingDirectory=/opt/suddenly/app\nEnvironment=\"PATH=/opt/suddenly/app/venv/bin\"\nEnvironmentFile=/opt/suddenly/app/.env\nExecStart=/opt/suddenly/app/venv/bin/gunicorn \\\n    --workers 3 \\\n    --bind unix:/opt/suddenly/suddenly.sock \\\n    --access-logfile /var/log/suddenly/access.log \\\n    --error-logfile /var/log/suddenly/error.log \\\n    suddenly.wsgi:application\nExecReload=/bin/kill -s HUP $MAINPID\nRestart=on-failure\nRestartSec=5\n\n[Install]\nWantedBy=multi-user.target\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl enable suddenly\nsudo systemctl start suddenly\n",[121,608,609,620,630,634,648,653,658,663,667,672,677,682,687,692,697,703,709,715,721,727,733,739,745,751,756,762,768,773,778,789,801],{"__ignoreMap":119},[124,610,611,613,615,617],{"class":126,"line":127},[124,612,131],{"class":130},[124,614,277],{"class":134},[124,616,280],{"class":152},[124,618,619],{"class":134}," /var/log/suddenly\n",[124,621,622,624,626,628],{"class":126,"line":156},[124,623,131],{"class":130},[124,625,291],{"class":134},[124,627,294],{"class":134},[124,629,619],{"class":134},[124,631,632],{"class":126,"line":163},[124,633,160],{"emptyLinePlaceholder":159},[124,635,636,638,641,644,646],{"class":126,"line":179},[124,637,131],{"class":130},[124,639,640],{"class":134}," tee",[124,642,643],{"class":134}," /etc/systemd/system/suddenly.service",[124,645,324],{"class":323},[124,647,327],{"class":134},[124,649,650],{"class":126,"line":193},[124,651,652],{"class":134},"[Unit]\n",[124,654,655],{"class":126,"line":204},[124,656,657],{"class":134},"Description=Suddenly Gunicorn Daemon\n",[124,659,660],{"class":126,"line":212},[124,661,662],{"class":134},"After=network.target postgresql.service\n",[124,664,665],{"class":126,"line":220},[124,666,160],{"emptyLinePlaceholder":159},[124,668,669],{"class":126,"line":231},[124,670,671],{"class":134},"[Service]\n",[124,673,674],{"class":126,"line":240},[124,675,676],{"class":134},"User=suddenly\n",[124,678,679],{"class":126,"line":245},[124,680,681],{"class":134},"Group=suddenly\n",[124,683,684],{"class":126,"line":252},[124,685,686],{"class":134},"WorkingDirectory=/opt/suddenly/app\n",[124,688,689],{"class":126,"line":272},[124,690,691],{"class":134},"Environment=\"PATH=/opt/suddenly/app/venv/bin\"\n",[124,693,694],{"class":126,"line":286},[124,695,696],{"class":134},"EnvironmentFile=/opt/suddenly/app/.env\n",[124,698,700],{"class":126,"line":699},15,[124,701,702],{"class":134},"ExecStart=/opt/suddenly/app/venv/bin/gunicorn \\\n",[124,704,706],{"class":126,"line":705},16,[124,707,708],{"class":134},"    --workers 3 \\\n",[124,710,712],{"class":126,"line":711},17,[124,713,714],{"class":134},"    --bind unix:/opt/suddenly/suddenly.sock \\\n",[124,716,718],{"class":126,"line":717},18,[124,719,720],{"class":134},"    --access-logfile /var/log/suddenly/access.log \\\n",[124,722,724],{"class":126,"line":723},19,[124,725,726],{"class":134},"    --error-logfile /var/log/suddenly/error.log \\\n",[124,728,730],{"class":126,"line":729},20,[124,731,732],{"class":134},"    suddenly.wsgi:application\n",[124,734,736],{"class":126,"line":735},21,[124,737,738],{"class":134},"ExecReload=/bin/kill -s HUP $MAINPID\n",[124,740,742],{"class":126,"line":741},22,[124,743,744],{"class":134},"Restart=on-failure\n",[124,746,748],{"class":126,"line":747},23,[124,749,750],{"class":134},"RestartSec=5\n",[124,752,754],{"class":126,"line":753},24,[124,755,160],{"emptyLinePlaceholder":159},[124,757,759],{"class":126,"line":758},25,[124,760,761],{"class":134},"[Install]\n",[124,763,765],{"class":126,"line":764},26,[124,766,767],{"class":134},"WantedBy=multi-user.target\n",[124,769,771],{"class":126,"line":770},27,[124,772,352],{"class":134},[124,774,776],{"class":126,"line":775},28,[124,777,160],{"emptyLinePlaceholder":159},[124,779,781,783,786],{"class":126,"line":780},29,[124,782,131],{"class":130},[124,784,785],{"class":134}," systemctl",[124,787,788],{"class":134}," daemon-reload\n",[124,790,792,794,796,799],{"class":126,"line":791},30,[124,793,131],{"class":130},[124,795,785],{"class":134},[124,797,798],{"class":134}," enable",[124,800,269],{"class":134},[124,802,804,806,808,811],{"class":126,"line":803},31,[124,805,131],{"class":130},[124,807,785],{"class":134},[124,809,810],{"class":134}," start",[124,812,269],{"class":134},[107,814],{},[86,816,818],{"id":817},"_5-nginx","5. Nginx",[114,820,822],{"className":116,"code":821,"language":118,"meta":119,"style":119},"sudo tee /etc/nginx/sites-available/suddenly \u003C\u003C 'EOF'\nupstream suddenly {\n    server unix:/opt/suddenly/suddenly.sock fail_timeout=0;\n}\n\nserver {\n    listen 80;\n    server_name votre-domaine.com;\n    return 301 https://$host$request_uri;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name votre-domaine.com;\n\n    add_header X-Frame-Options \"SAMEORIGIN\" always;\n    add_header X-Content-Type-Options \"nosniff\" always;\n    add_header Strict-Transport-Security \"max-age=31536000\" always;\n\n    access_log /var/log/nginx/suddenly_access.log;\n    error_log  /var/log/nginx/suddenly_error.log;\n\n    client_max_body_size 10M;\n\n    location /static/ {\n        alias /opt/suddenly/app/staticfiles/;\n        expires 30d;\n        add_header Cache-Control \"public, immutable\";\n    }\n\n    location /media/ {\n        alias /opt/suddenly/app/media/;\n        expires 7d;\n    }\n\n    location / {\n        proxy_pass http://suddenly;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n    }\n}\nEOF\n\nsudo ln -s /etc/nginx/sites-available/suddenly /etc/nginx/sites-enabled/\nsudo nginx -t\nsudo systemctl reload nginx\n",[121,823,824,837,842,847,852,856,861,866,871,876,880,884,888,893,897,901,906,911,916,920,925,930,934,939,943,948,953,958,963,968,972,977,983,989,994,999,1005,1011,1017,1023,1029,1035,1040,1045,1050,1055,1070,1081],{"__ignoreMap":119},[124,825,826,828,830,833,835],{"class":126,"line":127},[124,827,131],{"class":130},[124,829,640],{"class":134},[124,831,832],{"class":134}," /etc/nginx/sites-available/suddenly",[124,834,324],{"class":323},[124,836,327],{"class":134},[124,838,839],{"class":126,"line":156},[124,840,841],{"class":134},"upstream suddenly {\n",[124,843,844],{"class":126,"line":163},[124,845,846],{"class":134},"    server unix:/opt/suddenly/suddenly.sock fail_timeout=0;\n",[124,848,849],{"class":126,"line":179},[124,850,851],{"class":134},"}\n",[124,853,854],{"class":126,"line":193},[124,855,160],{"emptyLinePlaceholder":159},[124,857,858],{"class":126,"line":204},[124,859,860],{"class":134},"server {\n",[124,862,863],{"class":126,"line":212},[124,864,865],{"class":134},"    listen 80;\n",[124,867,868],{"class":126,"line":220},[124,869,870],{"class":134},"    server_name votre-domaine.com;\n",[124,872,873],{"class":126,"line":231},[124,874,875],{"class":134},"    return 301 https://$host$request_uri;\n",[124,877,878],{"class":126,"line":240},[124,879,851],{"class":134},[124,881,882],{"class":126,"line":245},[124,883,160],{"emptyLinePlaceholder":159},[124,885,886],{"class":126,"line":252},[124,887,860],{"class":134},[124,889,890],{"class":126,"line":272},[124,891,892],{"class":134},"    listen 443 ssl http2;\n",[124,894,895],{"class":126,"line":286},[124,896,870],{"class":134},[124,898,899],{"class":126,"line":699},[124,900,160],{"emptyLinePlaceholder":159},[124,902,903],{"class":126,"line":705},[124,904,905],{"class":134},"    add_header X-Frame-Options \"SAMEORIGIN\" always;\n",[124,907,908],{"class":126,"line":711},[124,909,910],{"class":134},"    add_header X-Content-Type-Options \"nosniff\" always;\n",[124,912,913],{"class":126,"line":717},[124,914,915],{"class":134},"    add_header Strict-Transport-Security \"max-age=31536000\" always;\n",[124,917,918],{"class":126,"line":723},[124,919,160],{"emptyLinePlaceholder":159},[124,921,922],{"class":126,"line":729},[124,923,924],{"class":134},"    access_log /var/log/nginx/suddenly_access.log;\n",[124,926,927],{"class":126,"line":735},[124,928,929],{"class":134},"    error_log  /var/log/nginx/suddenly_error.log;\n",[124,931,932],{"class":126,"line":741},[124,933,160],{"emptyLinePlaceholder":159},[124,935,936],{"class":126,"line":747},[124,937,938],{"class":134},"    client_max_body_size 10M;\n",[124,940,941],{"class":126,"line":753},[124,942,160],{"emptyLinePlaceholder":159},[124,944,945],{"class":126,"line":758},[124,946,947],{"class":134},"    location /static/ {\n",[124,949,950],{"class":126,"line":764},[124,951,952],{"class":134},"        alias /opt/suddenly/app/staticfiles/;\n",[124,954,955],{"class":126,"line":770},[124,956,957],{"class":134},"        expires 30d;\n",[124,959,960],{"class":126,"line":775},[124,961,962],{"class":134},"        add_header Cache-Control \"public, immutable\";\n",[124,964,965],{"class":126,"line":780},[124,966,967],{"class":134},"    }\n",[124,969,970],{"class":126,"line":791},[124,971,160],{"emptyLinePlaceholder":159},[124,973,974],{"class":126,"line":803},[124,975,976],{"class":134},"    location /media/ {\n",[124,978,980],{"class":126,"line":979},32,[124,981,982],{"class":134},"        alias /opt/suddenly/app/media/;\n",[124,984,986],{"class":126,"line":985},33,[124,987,988],{"class":134},"        expires 7d;\n",[124,990,992],{"class":126,"line":991},34,[124,993,967],{"class":134},[124,995,997],{"class":126,"line":996},35,[124,998,160],{"emptyLinePlaceholder":159},[124,1000,1002],{"class":126,"line":1001},36,[124,1003,1004],{"class":134},"    location / {\n",[124,1006,1008],{"class":126,"line":1007},37,[124,1009,1010],{"class":134},"        proxy_pass http://suddenly;\n",[124,1012,1014],{"class":126,"line":1013},38,[124,1015,1016],{"class":134},"        proxy_set_header Host $host;\n",[124,1018,1020],{"class":126,"line":1019},39,[124,1021,1022],{"class":134},"        proxy_set_header X-Real-IP $remote_addr;\n",[124,1024,1026],{"class":126,"line":1025},40,[124,1027,1028],{"class":134},"        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n",[124,1030,1032],{"class":126,"line":1031},41,[124,1033,1034],{"class":134},"        proxy_set_header X-Forwarded-Proto $scheme;\n",[124,1036,1038],{"class":126,"line":1037},42,[124,1039,967],{"class":134},[124,1041,1043],{"class":126,"line":1042},43,[124,1044,851],{"class":134},[124,1046,1048],{"class":126,"line":1047},44,[124,1049,352],{"class":134},[124,1051,1053],{"class":126,"line":1052},45,[124,1054,160],{"emptyLinePlaceholder":159},[124,1056,1058,1060,1063,1065,1067],{"class":126,"line":1057},46,[124,1059,131],{"class":130},[124,1061,1062],{"class":134}," ln",[124,1064,263],{"class":152},[124,1066,832],{"class":134},[124,1068,1069],{"class":134}," /etc/nginx/sites-enabled/\n",[124,1071,1073,1075,1078],{"class":126,"line":1072},47,[124,1074,131],{"class":130},[124,1076,1077],{"class":134}," nginx",[124,1079,1080],{"class":152}," -t\n",[124,1082,1084,1086,1088,1091],{"class":126,"line":1083},48,[124,1085,131],{"class":130},[124,1087,785],{"class":134},[124,1089,1090],{"class":134}," reload",[124,1092,1093],{"class":134}," nginx\n",[107,1095],{},[86,1097,1099],{"id":1098},"_6-ssl-lets-encrypt","6. SSL (Let's Encrypt)",[114,1101,1103],{"className":116,"code":1102,"language":118,"meta":119,"style":119},"sudo certbot --nginx -d votre-domaine.com\n",[121,1104,1105],{"__ignoreMap":119},[124,1106,1107,1109,1112,1115,1118],{"class":126,"line":127},[124,1108,131],{"class":130},[124,1110,1111],{"class":134}," certbot",[124,1113,1114],{"class":152}," --nginx",[124,1116,1117],{"class":152}," -d",[124,1119,1120],{"class":134}," votre-domaine.com\n",[70,1122,1123],{},"Certbot configure Nginx et met en place le renouvellement automatique.",[107,1125],{},[86,1127,1129],{"id":1128},"_7-redis-optionnel","7. Redis (optionnel)",[70,1131,1132],{},"Recommandé pour les instances de 50+ utilisateurs.",[114,1134,1136],{"className":116,"code":1135,"language":118,"meta":119,"style":119},"sudo apt install -y redis-server\nsudo systemctl enable redis-server\nsudo systemctl start redis-server\n",[121,1137,1138,1151,1161],{"__ignoreMap":119},[124,1139,1140,1142,1144,1146,1148],{"class":126,"line":127},[124,1141,131],{"class":130},[124,1143,135],{"class":134},[124,1145,170],{"class":134},[124,1147,173],{"class":152},[124,1149,1150],{"class":134}," redis-server\n",[124,1152,1153,1155,1157,1159],{"class":126,"line":156},[124,1154,131],{"class":130},[124,1156,785],{"class":134},[124,1158,798],{"class":134},[124,1160,1150],{"class":134},[124,1162,1163,1165,1167,1169],{"class":126,"line":163},[124,1164,131],{"class":130},[124,1166,785],{"class":134},[124,1168,810],{"class":134},[124,1170,1150],{"class":134},[70,1172,1173,1174,1176],{},"Ajouter dans ",[121,1175,431],{}," :",[114,1178,1180],{"className":116,"code":1179,"language":118,"meta":119,"style":119},"REDIS_URL=redis://localhost:6379/0\n",[121,1181,1182],{"__ignoreMap":119},[124,1183,1184,1187,1189],{"class":126,"line":127},[124,1185,1186],{"class":141},"REDIS_URL",[124,1188,463],{"class":323},[124,1190,1191],{"class":134},"redis://localhost:6379/0\n",[107,1193],{},[86,1195,1197],{"id":1196},"_8-celery-optionnel","8. Celery (optionnel)",[70,1199,1200],{},"Nécessaire pour la livraison fédérée asynchrone sur les instances de 500+ utilisateurs, ou si Redis est activé.",[70,1202,1203,1204,1208,1209,1212],{},"Deux services : le ",[1205,1206,1207],"em",{},"worker"," (qui exécute les tâches) et ",[1205,1210,1211],{},"beat"," (qui les planifie — purge des citations éphémères toutes les heures, rafraîchissement des acteurs distants une fois par jour).",[114,1214,1216],{"className":116,"code":1215,"language":118,"meta":119,"style":119},"sudo tee /etc/systemd/system/suddenly-celery.service \u003C\u003C 'EOF'\n[Unit]\nDescription=Suddenly Celery Worker\nAfter=network.target redis.service\n\n[Service]\nUser=suddenly\nWorkingDirectory=/opt/suddenly/app\nEnvironment=\"PATH=/opt/suddenly/app/venv/bin\"\nEnvironmentFile=/opt/suddenly/app/.env\nExecStart=/opt/suddenly/app/venv/bin/celery \\\n    -A suddenly worker --loglevel=info \\\n    --logfile=/var/log/suddenly/celery.log\nRestart=on-failure\nEOF\n\nsudo tee /etc/systemd/system/suddenly-celery-beat.service \u003C\u003C 'EOF'\n[Unit]\nDescription=Suddenly Celery Beat\nAfter=network.target redis.service\n\n[Service]\nUser=suddenly\nWorkingDirectory=/opt/suddenly/app\nEnvironment=\"PATH=/opt/suddenly/app/venv/bin\"\nEnvironmentFile=/opt/suddenly/app/.env\nExecStart=/opt/suddenly/app/venv/bin/celery \\\n    -A suddenly beat --loglevel=info \\\n    --scheduler django_celery_beat.schedulers:DatabaseScheduler \\\n    --logfile=/var/log/suddenly/celery-beat.log\nRestart=on-failure\nEOF\n\nsudo systemctl daemon-reload\nsudo systemctl enable --now suddenly-celery suddenly-celery-beat\n",[121,1217,1218,1231,1235,1240,1245,1249,1253,1257,1261,1265,1269,1274,1279,1284,1288,1292,1296,1309,1313,1318,1322,1326,1330,1334,1338,1342,1346,1350,1355,1360,1365,1369,1373,1377,1385],{"__ignoreMap":119},[124,1219,1220,1222,1224,1227,1229],{"class":126,"line":127},[124,1221,131],{"class":130},[124,1223,640],{"class":134},[124,1225,1226],{"class":134}," /etc/systemd/system/suddenly-celery.service",[124,1228,324],{"class":323},[124,1230,327],{"class":134},[124,1232,1233],{"class":126,"line":156},[124,1234,652],{"class":134},[124,1236,1237],{"class":126,"line":163},[124,1238,1239],{"class":134},"Description=Suddenly Celery Worker\n",[124,1241,1242],{"class":126,"line":179},[124,1243,1244],{"class":134},"After=network.target redis.service\n",[124,1246,1247],{"class":126,"line":193},[124,1248,160],{"emptyLinePlaceholder":159},[124,1250,1251],{"class":126,"line":204},[124,1252,671],{"class":134},[124,1254,1255],{"class":126,"line":212},[124,1256,676],{"class":134},[124,1258,1259],{"class":126,"line":220},[124,1260,686],{"class":134},[124,1262,1263],{"class":126,"line":231},[124,1264,691],{"class":134},[124,1266,1267],{"class":126,"line":240},[124,1268,696],{"class":134},[124,1270,1271],{"class":126,"line":245},[124,1272,1273],{"class":134},"ExecStart=/opt/suddenly/app/venv/bin/celery \\\n",[124,1275,1276],{"class":126,"line":252},[124,1277,1278],{"class":134},"    -A suddenly worker --loglevel=info \\\n",[124,1280,1281],{"class":126,"line":272},[124,1282,1283],{"class":134},"    --logfile=/var/log/suddenly/celery.log\n",[124,1285,1286],{"class":126,"line":286},[124,1287,744],{"class":134},[124,1289,1290],{"class":126,"line":699},[124,1291,352],{"class":134},[124,1293,1294],{"class":126,"line":705},[124,1295,160],{"emptyLinePlaceholder":159},[124,1297,1298,1300,1302,1305,1307],{"class":126,"line":711},[124,1299,131],{"class":130},[124,1301,640],{"class":134},[124,1303,1304],{"class":134}," /etc/systemd/system/suddenly-celery-beat.service",[124,1306,324],{"class":323},[124,1308,327],{"class":134},[124,1310,1311],{"class":126,"line":717},[124,1312,652],{"class":134},[124,1314,1315],{"class":126,"line":723},[124,1316,1317],{"class":134},"Description=Suddenly Celery Beat\n",[124,1319,1320],{"class":126,"line":729},[124,1321,1244],{"class":134},[124,1323,1324],{"class":126,"line":735},[124,1325,160],{"emptyLinePlaceholder":159},[124,1327,1328],{"class":126,"line":741},[124,1329,671],{"class":134},[124,1331,1332],{"class":126,"line":747},[124,1333,676],{"class":134},[124,1335,1336],{"class":126,"line":753},[124,1337,686],{"class":134},[124,1339,1340],{"class":126,"line":758},[124,1341,691],{"class":134},[124,1343,1344],{"class":126,"line":764},[124,1345,696],{"class":134},[124,1347,1348],{"class":126,"line":770},[124,1349,1273],{"class":134},[124,1351,1352],{"class":126,"line":775},[124,1353,1354],{"class":134},"    -A suddenly beat --loglevel=info \\\n",[124,1356,1357],{"class":126,"line":780},[124,1358,1359],{"class":134},"    --scheduler django_celery_beat.schedulers:DatabaseScheduler \\\n",[124,1361,1362],{"class":126,"line":791},[124,1363,1364],{"class":134},"    --logfile=/var/log/suddenly/celery-beat.log\n",[124,1366,1367],{"class":126,"line":803},[124,1368,744],{"class":134},[124,1370,1371],{"class":126,"line":979},[124,1372,352],{"class":134},[124,1374,1375],{"class":126,"line":985},[124,1376,160],{"emptyLinePlaceholder":159},[124,1378,1379,1381,1383],{"class":126,"line":991},[124,1380,131],{"class":130},[124,1382,785],{"class":134},[124,1384,788],{"class":134},[124,1386,1387,1389,1391,1393,1396,1399],{"class":126,"line":996},[124,1388,131],{"class":130},[124,1390,785],{"class":134},[124,1392,798],{"class":134},[124,1394,1395],{"class":152}," --now",[124,1397,1398],{"class":134}," suddenly-celery",[124,1400,1401],{"class":134}," suddenly-celery-beat\n",[507,1403,1404],{},[70,1405,1406,1407,1410],{},"Sans Celery, ces deux tâches périodiques ne tournent pas : les citations éphémères ne seront jamais purgées. Sur une petite instance, planifiez-les en cron (voir ",[1408,1409,56],"a",{"href":57},").",[107,1412],{},[86,1414,1416],{"id":1415},"mise-à-jour","Mise à jour",[114,1418,1420],{"className":116,"code":1419,"language":118,"meta":119,"style":119},"sudo -u suddenly bash \u003C\u003C 'EOF'\ncd /opt/suddenly/app\ngit pull origin main\nsource venv/bin/activate\npip install --upgrade pip && pip install -e \".[federation]\"\npython manage.py migrate\npython manage.py collectstatic --noinput\nEOF\n\nsudo systemctl restart suddenly\nsudo systemctl restart suddenly-celery  # si Celery activé\n",[121,1421,1422,1436,1440,1445,1449,1454,1458,1462,1466,1470,1481],{"__ignoreMap":119},[124,1423,1424,1426,1428,1430,1432,1434],{"class":126,"line":127},[124,1425,131],{"class":130},[124,1427,314],{"class":152},[124,1429,372],{"class":134},[124,1431,375],{"class":134},[124,1433,324],{"class":323},[124,1435,327],{"class":134},[124,1437,1438],{"class":126,"line":156},[124,1439,561],{"class":134},[124,1441,1442],{"class":126,"line":163},[124,1443,1444],{"class":134},"git pull origin main\n",[124,1446,1447],{"class":126,"line":179},[124,1448,404],{"class":134},[124,1450,1451],{"class":126,"line":193},[124,1452,1453],{"class":134},"pip install --upgrade pip && pip install -e \".[federation]\"\n",[124,1455,1456],{"class":126,"line":204},[124,1457,575],{"class":134},[124,1459,1460],{"class":126,"line":212},[124,1461,585],{"class":134},[124,1463,1464],{"class":126,"line":220},[124,1465,352],{"class":134},[124,1467,1468],{"class":126,"line":231},[124,1469,160],{"emptyLinePlaceholder":159},[124,1471,1472,1474,1476,1479],{"class":126,"line":240},[124,1473,131],{"class":130},[124,1475,785],{"class":134},[124,1477,1478],{"class":134}," restart",[124,1480,269],{"class":134},[124,1482,1483,1485,1487,1489,1491],{"class":126,"line":245},[124,1484,131],{"class":130},[124,1486,785],{"class":134},[124,1488,1478],{"class":134},[124,1490,1398],{"class":134},[124,1492,1493],{"class":248},"  # si Celery activé\n",[107,1495],{},[86,1497,1499],{"id":1498},"dépannage","Dépannage",[114,1501,1503],{"className":116,"code":1502,"language":118,"meta":119,"style":119},"# Statut et logs de l'application\nsudo systemctl status suddenly\nsudo journalctl -u suddenly -n 50\n\n# Logs Nginx\nsudo tail -f /var/log/nginx/error.log\n\n# Test de connexion à la base\nsudo -u suddenly psql -d suddenly -c \"SELECT 1;\"\n\n# Erreur 502 — vérifier le socket\nls -la /opt/suddenly/suddenly.sock\n",[121,1504,1505,1510,1521,1538,1542,1547,1560,1564,1569,1589,1593,1598],{"__ignoreMap":119},[124,1506,1507],{"class":126,"line":127},[124,1508,1509],{"class":248},"# Statut et logs de l'application\n",[124,1511,1512,1514,1516,1519],{"class":126,"line":156},[124,1513,131],{"class":130},[124,1515,785],{"class":134},[124,1517,1518],{"class":134}," status",[124,1520,269],{"class":134},[124,1522,1523,1525,1528,1530,1532,1535],{"class":126,"line":163},[124,1524,131],{"class":130},[124,1526,1527],{"class":134}," journalctl",[124,1529,314],{"class":152},[124,1531,372],{"class":134},[124,1533,1534],{"class":152}," -n",[124,1536,1537],{"class":152}," 50\n",[124,1539,1540],{"class":126,"line":179},[124,1541,160],{"emptyLinePlaceholder":159},[124,1543,1544],{"class":126,"line":193},[124,1545,1546],{"class":248},"# Logs Nginx\n",[124,1548,1549,1551,1554,1557],{"class":126,"line":204},[124,1550,131],{"class":130},[124,1552,1553],{"class":134}," tail",[124,1555,1556],{"class":152}," -f",[124,1558,1559],{"class":134}," /var/log/nginx/error.log\n",[124,1561,1562],{"class":126,"line":212},[124,1563,160],{"emptyLinePlaceholder":159},[124,1565,1566],{"class":126,"line":220},[124,1567,1568],{"class":248},"# Test de connexion à la base\n",[124,1570,1571,1573,1575,1577,1579,1581,1583,1586],{"class":126,"line":231},[124,1572,131],{"class":130},[124,1574,314],{"class":152},[124,1576,372],{"class":134},[124,1578,320],{"class":134},[124,1580,1117],{"class":152},[124,1582,372],{"class":134},[124,1584,1585],{"class":152}," -c",[124,1587,1588],{"class":134}," \"SELECT 1;\"\n",[124,1590,1591],{"class":126,"line":240},[124,1592,160],{"emptyLinePlaceholder":159},[124,1594,1595],{"class":126,"line":245},[124,1596,1597],{"class":248},"# Erreur 502 — vérifier le socket\n",[124,1599,1600,1603,1606],{"class":126,"line":252},[124,1601,1602],{"class":130},"ls",[124,1604,1605],{"class":152}," -la",[124,1607,1608],{"class":134}," /opt/suddenly/suddenly.sock\n",[1610,1611,1612],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":119,"searchDepth":156,"depth":156,"links":1614},[1615,1616,1617,1618,1623,1624,1625,1626,1627,1628,1629],{"id":88,"depth":156,"text":89},{"id":111,"depth":156,"text":112},{"id":301,"depth":156,"text":302},{"id":357,"depth":156,"text":358,"children":1619},[1620,1622],{"id":427,"depth":163,"text":1621},"Configuration .env",{"id":536,"depth":163,"text":537},{"id":602,"depth":156,"text":603},{"id":817,"depth":156,"text":818},{"id":1098,"depth":156,"text":1099},{"id":1128,"depth":156,"text":1129},{"id":1196,"depth":156,"text":1197},{"id":1415,"depth":156,"text":1416},{"id":1498,"depth":156,"text":1499},"Déployer Suddenly sur un VPS Debian/Ubuntu sans Docker.","md",{},{"title":38,"description":1630},"wnwObcyvcjS3HF6wYnSs9HDPYbd7mTe2Zx4ECDtCbEY",1784021864437]