[{"data":1,"prerenderedAt":195},["ShallowReactive",2],{"seo-verification":3,"blog-self-host-marimo-vps-python-notebooks-en":6},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-self-host-marimo-vps-python-notebooks-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":28,"featuredImage":30,"bgImage":31,"posterImage":32,"relatedSolution":33,"intro":36,"sections":37,"ctaTitle":131,"ctaBody":132,"ctaButton":133,"ctaUrl":134,"relatedPosts":135},552,"self-host-marimo-vps-python-notebooks",{"fr":12,"en":10,"ar":13,"es":14},"self-host-marimo-vps","استضافة-marimo-على-vps-دفاتر-python","autoalojar-marimo-vps-notebooks-python","marimo on a VPS: self-hosted reactive Python notebooks","Install marimo on a VPS: reactive Python notebooks saved as .py files, a password-protected web editor, pandas and polars included.",8,0,false,"2026-11-01T00:00:00+00:00","2026-11-01T14:14:31+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},7,"Self-hosting","self-hosting","bg-indigo-500\u002F10 text-indigo-400","cloud",[29],{"id":23,"name":24,"slug":25,"color":26,"icon":27},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fself-host-marimo-vps-poster.svg",{"categorySlug":34,"appSlug":35},"development","marimo","A Jupyter notebook that has been running all afternoon often ends up lying: one cell edited, another never re-run, and the chart on screen no longer matches the code. marimo fixes this at the root. This open-source Python notebook (Apache-2.0 licensed) saves every notebook as a plain .py file and automatically re-runs the cells that depend on the one you change. This guide installs it with Docker Compose on a VPS, protects the editor with a password, publishes it over HTTPS behind nginx, then shows how to turn a notebook into a small app.",[38,42,52,84,87,103,107,110,113,116,119,122,125,128],{"type":39,"title":40,"body":41},"h2","Why a reactive notebook on your own server","In Jupyter, execution order depends on your clicks: a variable redefined further down, a forgotten cell, and the displayed results no longer match the code. The .ipynb file, JSON loaded with outputs, is hard to review and creates Git conflicts on every run.\n\nmarimo analyses the dependencies between cells. When a cell changes, every cell that depends on it re-runs, and only those. The notebook is an ordinary Python file: `git diff` reads it, `python notebook.py` runs it.\n\nHosting it on your VPS keeps the data on a server you control, gives the whole team the same environment from a browser, and lets you pick the memory and CPU your computations need.",{"type":43,"title":44,"items":45},"ul","What marimo brings",[46,47,48,49,50,51],"**Reactive execution** — an edited cell re-runs the cells that depend on it, with no hidden state.","**.py files** — readable notebooks, versioned in Git and runnable as scripts.","**UI elements** — sliders, dropdowns, tables and charts wired to Python variables.","**Notebook to app** — `marimo run` serves a notebook read-only with the code hidden.","**Migration from Jupyter** — `marimo convert` transforms an .ipynb file.","**Official \"data\" image** — pandas, polars, numpy and altair preinstalled.",{"type":53,"title":54,"headers":55,"rows":58},"comparison","marimo, Jupyter and code-server",[5,35,56,57],"JupyterLab","code-server",[59,64,69,74,79],[60,61,62,63],"Notebook format",".py file",".ipynb file (JSON)","Project files",[65,66,67,68],"Execution order","Reactive, by dependencies","Manual, on click","Whatever script you run",[70,71,72,73],"Review in Git","Readable Python diff","JSON diff with outputs","Code diff",[75,76,77,78],"Publish as an app","Yes, `marimo run`","Third-party extensions","No",[80,81,82,83],"Best for","Analysis and internal tools in Python","Wide range of kernels","Full software development",{"type":39,"title":85,"body":86},"Prerequisites","An Ubuntu 24.04 VPS with 2 GB of RAM and 20 GB of disk (plan more memory if you load large datasets), Docker and the Compose plugin installed, and root SSH access. A subdomain (for example notebooks.example.com) pointing to the VPS is useful for HTTPS access, but not required: an SSH tunnel is enough when you work alone.",{"type":88,"title":89,"steps":90},"steps","Install marimo with Docker Compose",[91,94,97,100],{"title":92,"body":93},"Prepare the directory and the password","Create the application directory and a `.env` file holding the editor password.\n```bash\nmkdir -p \u002Fopt\u002Fmarimo && cd \u002Fopt\u002Fmarimo\necho \"ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '\u002F+=')\" > .env\nchmod 600 .env\n```",{"title":95,"body":96},"Write the compose file","Create `compose.yaml`. The official \"data\" image already contains the analysis libraries. The port is published on the loopback interface only, and the password is passed through a file rather than on the command line.\n```yaml\nservices:\n  marimo:\n    image: ghcr.io\u002Fmarimo-team\u002Fmarimo:0.25.2-data\n    restart: unless-stopped\n    ports:\n      - \"127.0.0.1:2718:8080\"\n    environment:\n      ADMIN_PASSWORD: ${ADMIN_PASSWORD:?ADMIN_PASSWORD requis}\n    command:\n      - sh\n      - -c\n      - umask 077 && printf %s \"$$ADMIN_PASSWORD\" > \u002Ftmp\u002Fmarimo-password && exec marimo edit --headless --skip-update-check --host 0.0.0.0 -p 8080 --token-password-file \u002Ftmp\u002Fmarimo-password \u002Fapp\n    volumes:\n      - marimo-data:\u002Fapp\nvolumes:\n  marimo-data: {}\n```",{"title":98,"body":99},"Start and check","Start the stack, then query the health probe: it should answer 200.\n```bash\ndocker compose up -d\ndocker compose ps\ncurl -s -o \u002Fdev\u002Fnull -w '%{http_code}\\n' http:\u002F\u002F127.0.0.1:2718\u002Fhealth\n```",{"title":101,"body":102},"Publish the editor over HTTPS","marimo talks to the browser over WebSocket: the nginx vhost must forward the `Upgrade` and `Connection` headers, otherwise the editor loads but cells never run.\n```nginx\nserver {\n    server_name notebooks.example.com;\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:2718;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header Host $host;\n        proxy_read_timeout 3600s;\n    }\n}\n```\n\n```bash\ncertbot --nginx -d notebooks.example.com\n```",{"type":104,"title":105,"body":106},"tip","No domain? Use an SSH tunnel","The editor runs Python code with the container's privileges: never expose it without a password. When you work alone there is no need to publish it — an SSH tunnel opens the editor on http:\u002F\u002Flocalhost:2718 from your machine.\n```bash\nssh -L 2718:127.0.0.1:2718 root@\u003Cvps-ip>\n```",{"type":39,"title":108,"body":109},"Secure the editor","An open marimo editor lets anyone who gets in run Python on your server: that is its purpose, and it is why a few simple rules apply.\n\n**A long, unique password.** The one in the `.env` file is random; do not replace it with a password you use elsewhere, and change it when a collaborator who knows it leaves the project (edit `.env`, then `docker compose up -d`).\n\n**A port that stays local.** The compose file publishes the port on `127.0.0.1` only: from the Internet, only nginx over HTTPS reaches it. Never replace that address with `0.0.0.0`.\n\n**No plain-text secrets in notebooks.** A notebook is a versioned Python file: an API key typed into a cell ends up in the Git history. Read it from an environment variable added to the compose file, or from a file outside the repository.\n\n**Logs to watch.** On startup, marimo prints its access address in `docker compose logs`, password included: the log stays on your VPS, but do not paste it as is into a ticket or a chat.",{"type":39,"title":111,"body":112},"Your first reactive notebook","Log in with the password from the `.env` file. The editor opens the `\u002Fapp` folder, which already holds the official tutorials. Create a notebook with two cells: the first defines a slider, the second filters a CSV file with its value. Move the slider: the second cell re-runs by itself.\n\n```python\nimport marimo as mo\nimport polars as pl\n\nthreshold = mo.ui.slider(0, 1000, value=100, label=\"Minimum amount\")\nthreshold\n```\n\n```python\nsales = pl.read_csv(\"data\u002Fsales.csv\")\nsales.filter(pl.col(\"amount\") >= threshold.value)\n```",{"type":39,"title":114,"body":115},"Read your data: CSV, Parquet and APIs","The \"data\" image covers most analysis work without installing anything. pandas reads CSV, Excel and JSON files; polars reads CSV and Parquet very fast and can process files larger than memory in lazy mode; altair draws interactive charts displayed right under the cell.\n\nDrop your files into the volume's `\u002Fapp\u002Fdata` folder, with `scp` to the VPS then `docker compose cp`, or upload them from the editor's file panel. For an API, Python's standard library is enough to download JSON, which pandas or polars then turn into a table.\n\nEvery cell result is a live object: a DataFrame shows as a sortable, filterable table, and a selection made in a table or chart can feed the next cell. This mechanism is what turns an exploration into a reusable tool.",{"type":39,"title":117,"body":118},"Turn a notebook into an app","A notebook with UI elements is already an app. `marimo run` serves it read-only: visitors play with the sliders and dropdowns without seeing or editing the code. Publish this second port behind its own vhost, protected like the editor.\n\n```bash\ndocker compose exec marimo marimo run \u002Fapp\u002Frapport.py --host 0.0.0.0 -p 8081\n```\n\nYour existing Jupyter notebooks convert in one command; then review the cells that redefined the same variable, which marimo rejects by design.\n\n```bash\ndocker compose exec marimo marimo convert \u002Fapp\u002Fold.ipynb -o \u002Fapp\u002Fnew.py\n```",{"type":39,"title":120,"body":121},"Working together on the same notebooks","A marimo server is a shared editor: everyone with the password sees the same files. For a small team, the simplest rule is one notebook per person and per topic, plus a Git repository in `\u002Fapp` to keep the history.\n\nBecause every notebook is a .py file, the usual developer tools apply: `git diff` shows exactly which cell changed, a pull request reads like code, and a Python linter or formatter runs on it unchanged. A notebook can even be imported as a module or run as a script from a scheduled job, to produce the same report every night.",{"type":39,"title":123,"body":124},"Sizing the VPS","marimo itself is light; your data sets the server size. Plan 2 GB of RAM to explore files of a few hundred megabytes with pandas, and move to 4 or 8 GB if you load larger datasets or if several people work at the same time. CPU matters mostly for heavy computations: polars uses every available core. Finally, keep enough disk for the image (about 400 MB) and for your data files, which grow faster than the notebooks.",{"type":39,"title":126,"body":127},"Backup and updates","Notebooks live in the `marimo-data` volume. The safest option is to version `\u002Fapp` in a Git repository; otherwise, archive the volume regularly.\n\n```bash\ndocker run --rm -v marimo_marimo-data:\u002Fdata -v \"$PWD\":\u002Fbackup alpine \\\n  tar czf \u002Fbackup\u002Fmarimo-$(date +%F).tar.gz -C \u002Fdata .\n```\n\nTo update, change the image tag in `compose.yaml` after reading the project's release notes, then run `docker compose pull && docker compose up -d`. The notebooks, plain .py files, are left untouched.",{"type":39,"title":129,"body":130},"One-click install from the ServOrbit Marketplace","On a ServOrbit VPS, marimo installs from the Marketplace in your client area: the script deploys the official container, generates the editor password and creates the notebooks volume. The password is shown in your client area. Attach a subdomain of one of your domains, or the VPS's free subdomain, to open the editor over HTTPS; without a domain, the SSH tunnel described above works as is, with the port shown in your client area.","Your Python notebooks, on your VPS","A ServOrbit Ubuntu 24.04 VPS with 2 GB of RAM is enough for marimo. One-click install from the Marketplace, password generated for you, HTTPS on your domain or on the VPS's free subdomain.","Discover marimo","\u002Fmarketplace\u002Fdevelopment\u002Fmarimo",[136,158,177],{"id":137,"slug":138,"slugs":139,"title":143,"excerpt":144,"readTime":145,"views":23,"isPinned":19,"publishedAt":146,"updatedAt":147,"category":148,"categories":154,"featuredImage":30,"bgImage":31,"posterImage":156,"relatedSolution":157},301,"install-code-server-vps",{"fr":140,"en":138,"ar":141,"es":142},"installer-code-server-vps","تثبيت-code-server-vps","instalar-code-server-vps","Code Server on VPS: VS Code in Your Browser, Self-Hosted","Code Server (MIT, 79 k stars): run VS Code in your browser on your VPS — persistent workspace, password-protected, no local IDE setup needed.",3,"2026-08-24T00:00:00+00:00","2026-09-07T11:26:10+00:00",{"id":149,"name":150,"slug":151,"color":152,"icon":153},4,"Development","developpement","bg-warning\u002F10 text-warning","dev",[155],{"id":149,"name":150,"slug":151,"color":152,"icon":153},"\u002Fblog\u002Fcovers\u002Finstaller-code-server-vps-poster.svg",{"categorySlug":34,"appSlug":57},{"id":159,"slug":160,"slugs":161,"title":165,"excerpt":166,"readTime":167,"views":149,"isPinned":19,"publishedAt":168,"updatedAt":169,"category":170,"categories":171,"featuredImage":30,"bgImage":31,"posterImage":173,"relatedSolution":174},168,"how-to-self-host-metabase-on-a-vps-open-source-bi-dashboards",{"fr":162,"en":160,"ar":163,"es":164},"self-host-metabase-vps","استضافة-metabase-على-vps-لوحات-ذكاء-أعمال-مفتوحة-المصدر","alojar-metabase-en-un-vps","How to Self-Host Metabase on a VPS: Open-Source BI Dashboards","Deploy Metabase on your VPS: connect any SQL database and build dashboards and charts in the browser, with a companion Postgres, on infrastructure you control.",9,"2026-07-06T00:00:00+00:00","2026-10-20T23:18:08+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":27},[172],{"id":23,"name":24,"slug":25,"color":26,"icon":27},"\u002Fblog\u002Fcovers\u002Fself-host-metabase-vps-poster.svg",{"categorySlug":175,"appSlug":176},"databases","metabase",{"id":178,"slug":179,"slugs":180,"title":184,"excerpt":185,"readTime":186,"views":149,"isPinned":19,"publishedAt":187,"updatedAt":188,"category":189,"categories":190,"featuredImage":30,"bgImage":31,"posterImage":192,"relatedSolution":193},45,"deploy-a-fastapi-application-on-a-vps",{"fr":181,"en":179,"ar":182,"es":183},"deployer-fastapi-vps","نشر-تطبيق-fastapi-على-vps","desplegar-una-aplicacion-fastapi-en-un-vps","Deploy FastAPI on a VPS: the complete production guide","Deploy FastAPI on a VPS with multi-stage Docker, Gunicorn, PostgreSQL, GitHub Actions CI\u002FCD and monitoring. Complete Python production guide 2025.",10,"2026-05-06T00:00:00+00:00","2026-10-07T23:07:24+00:00",{"id":149,"name":150,"slug":151,"color":152,"icon":153},[191],{"id":149,"name":150,"slug":151,"color":152,"icon":153},"\u002Fblog\u002Fcovers\u002Fdeployer-fastapi-vps-poster.svg",{"categorySlug":34,"appSlug":194},"fastapi",1793543018294]