A simple, self-hosted, encrypted notes application built with Flask.
- Secure: Note content is encrypted at rest.
- CRUD Operations: Create, view, edit, and delete notes through a clean web interface.
- Markdown Support: Notes are rendered from Markdown to HTML, with syntax highlighting for code blocks.
- Raw View: View the raw, unformatted text of any note.
- Authentication: Protected by simple HTTP Basic Authentication.
- Rate limiting per IP address
- CSRF protection for POST requests
- Configurable via environment variables
- Runs locally or in Docker
- Easy Setup: Automatically generates an encryption key on first run.
- Proxy Friendly: Designed to work behind a reverse proxy and correctly identify client IPs.
-
Clone the repository:
git clone https://github.com/teklynk/notes.git cd python_notes
-
Create a virtual environment:
python3 -m venv venv source venv/bin/activate
-
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables:
- Rename
sample.env
to.env
- Edit
.env
and set yourSECRET_KEY
,ALLOWED_DOMAIN
,HTTP_USER
, andHTTP_PASS
.
- Rename
-
Run the application:
python3 python_notes.py
-
Deactivate the virtual environment (optional):
deactivate
-
Configure environment variables:
- Rename
sample.docker-compose.yml
todocker-compose.yml
. - Edit
docker-compose.yml
and set yourSECRET_KEY
,ALLOWED_DOMAIN
,HTTP_USER
,HTTP_PASS
, andENCRYPTION_KEY
under theenvironment
section.
- Rename
-
Build and run the container:
docker-compose up --build -d
- On first local run, the app will generate an
ENCRYPTION_KEY
and save it to the.env
file if one does not already exist. - The
ENCRYPTION_KEY
must be a 32-byte, URL-safe, base64-encoded string. The app handles this for you, but it's good to know if you're setting it manually. - If using Docker, configure environment variables in
docker-compose.yml
. The.env
file is only used for local development. - Authentication is optional. If
HTTP_USER
andHTTP_PASS
are not set, the application will be publicly accessible. - The app is designed to work behind a reverse proxy (e.g., Nginx, Cloudflare) and uses the
CF-Connecting-IP
header to identify the real client IP for rate limiting.