AstroSpace is a Flask application for hosting and organizing astrophotography posts on your own infrastructure. It combines image publishing, equipment tracking, plate-solving overlays, and guiding-log visualization in one self-hosted site.
You can see a public instance here: astro.space-js.de
The preferred way to run AstroSpace in production is with nginx/docker-compose.yml. That stack starts:
astrospace_app: the published AstroSpace image, which runs Gunicorn on internal port9000astrospace_nginx: the public entrypoint, which listens on port8181, serves static/uploaded files directly, and proxies app requests toastrospace_app
PostgreSQL is intentionally not included in this compose file. AstroSpace expects an existing database server, and you provide its connection details through environment variables.
nginx/docker-compose.yml uses ${...} placeholders for runtime settings. The simplest setup is:
cd nginx- create a
.envfile next todocker-compose.yml - run
docker compose ...from thatnginx/directory
Example nginx/.env:
SECRET_KEY=change-me
DB_NAME=astrospace
DB_USER=astrospace
DB_PASSWORD=change-me
DB_HOST=192.168.1.20
DB_PORT=5432
TITLE=AstroSpace
MAX_USERS=2What each setting is for:
SECRET_KEY: Flask session and CSRF signing key. Set this to a long random value.DB_NAME: PostgreSQL database name AstroSpace should use.DB_USER: PostgreSQL username.DB_PASSWORD: PostgreSQL password.DB_HOST: hostname or IP address of your PostgreSQL server. This is usually another machine or another container stack.DB_PORT: PostgreSQL port, usually5432.TITLE: site title shown in the UI.MAX_USERS: maximum allowed registered users.
UPLOAD_PATH is already fixed inside the compose file as /uploads. That path must match the mounted uploads volume, so you normally do not override it in .env.
The bind mounts in nginx/docker-compose.yml are important because both the app and nginx need access to specific files on the host:
/mnt/user/AstroSpaceUploads:/uploadsThis is the persistent data directory for uploaded preview images, thumbnails, FITS/XISF files, generated overlays, starless variants, and other user media. This path must survive container recreation./mnt/user/Astro/_web_/AstroSpace/AstroSpace/static:/staticThis exposes AstroSpace static assets to nginx so/static/...can be served directly instead of going through Flask. Keep this host directory in sync with the AstroSpace version you deploy./mnt/user/Astro/_web_/AstroSpace/nginx/nginx.conf:/etc/nginx/nginx.conf:roThis mounts the nginx configuration file into the nginx container as read-only.
Before first start, edit the host-side paths in nginx/docker-compose.yml so they match your machine. The left side of each mount is your host path; the right side is the fixed path used inside the container.
nginx/nginx.conf is the reverse-proxy layer in front of AstroSpace:
- listens on port
8181 - serves
/uploads/directly from the mounted uploads folder - serves
/static/directly from the mounted static folder - proxies all other requests to
http://astrospace_app:9000/ - forwards the original
Hostheader and visitor IP viaX-Real-IP - raises
client_max_body_sizeto2000Mso large astrophotography uploads are accepted - increases proxy/read/send timeouts so long-running requests are less likely to be cut off early
In short: nginx handles public HTTP traffic and file serving, while the AstroSpace app container focuses on Flask/Gunicorn.
Use these commands from nginx/:
docker compose pull
docker compose run --rm astrospace_app migrate
docker compose up -dWhat each command does:
docker compose pullDownloads the image versions referenced by the compose file.docker compose run --rm astrospace_app migrateRuns Alembic migrations before the web stack starts. On compatible older AstroSpace databases, this also auto-stamps the legacy schema before applying newer revisions.docker compose up -dStarts the app and nginx containers in the background.
Useful follow-up commands:
docker compose logs -f astrospace_app astrospace_nginx
docker compose downAfter startup, open http://YOUR_HOST:8181.
For updates, the normal sequence is the same:
docker compose pull
docker compose run --rm astrospace_app migrate
docker compose up -dIf you prefer to pin a specific image version instead of latest, change the image: line in nginx/docker-compose.yml to a concrete tag such as sharonshaji92/astrospace:1.3.8.
- User registration with a configurable user limit
- Rich post creation for astrophotography images and acquisition details
- Equipment inventory management for telescopes, cameras, filters, and accessories
- FITS/XISF-assisted plate solving and generated overlays
- PHD2 guiding log parsing and Plotly-based visualizations
- Public collection pages and per-image detail views
- Docker-friendly deployment
- Optional opt-in debug logging for local development and container runs
- Python 3.11+
- PostgreSQL
- Optional: Node.js if you want to rebuild Tailwind CSS assets
- Optional: Docker for containerized deployment
python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -e .[dev]AstroSpace reads configuration from:
- environment variables
- the file pointed to by
ASTROSPACE_SETTINGS instance/config.py
Required settings:
SECRET_KEYDB_NAMEDB_USERDB_PASSWORDDB_HOSTDB_PORTUPLOAD_PATH
Common optional settings:
TITLEMAX_USERSSESSION_COOKIE_SECURE
Example config file:
SECRET_KEY = "change-me"
DB_NAME = "astrospace"
DB_USER = "astrospace"
DB_PASSWORD = "change-me"
DB_HOST = "localhost"
DB_PORT = 5432
UPLOAD_PATH = r"C:\astrospace\uploads"
TITLE = "My AstroSpace"
MAX_USERS = 2Run migrations first:
python -m AstroSpace migrateset ASTROSPACE_SETTINGS=path\to\config.py
flask --app AstroSpace runThe app starts on http://127.0.0.1:5000 by default.
If you are upgrading an existing pre-Alembic AstroSpace database, this is usually enough:
python -m AstroSpace migratemigrate will auto-stamp a compatible legacy AstroSpace schema before applying newer revisions. The explicit stamp command is still available if you want to control that step yourself:
python -m AstroSpace stamp
python -m AstroSpace migrateAstroSpace includes opt-in runtime logging around the places most likely to block or fail: app startup, database bootstrapping, post creation, inventory updates, plate solving, and guide-log parsing.
Enable it in either of these ways:
flask --app AstroSpace run --debugset ASTROSPACE_DEBUG=1
flask --app AstroSpace runFor the Docker image, append --debug to the container command or set ASTROSPACE_DEBUG=1.
Build the image locally:
docker build -t astrospace .Run it:
docker run --rm ^
-e SECRET_KEY=change-me ^
-e DB_NAME=astrospace ^
-e DB_USER=astrospace ^
-e DB_PASSWORD=change-me ^
-e DB_HOST=host.docker.internal ^
-e DB_PORT=5432 ^
-e UPLOAD_PATH=/uploads ^
-v C:\astrospace\uploads:/uploads ^
astrospace migrateThen start the web container:
docker run ^
--name astrospace ^
-p 9000:9000 ^
-e SECRET_KEY=change-me ^
-e DB_NAME=astrospace ^
-e DB_USER=astrospace ^
-e DB_PASSWORD=change-me ^
-e DB_HOST=host.docker.internal ^
-e DB_PORT=5432 ^
-e TITLE=AstroSpace ^
-e MAX_USERS=2 ^
-e UPLOAD_PATH=/uploads ^
-v C:\astrospace\uploads:/uploads ^
astrospaceRun the same container in debug mode:
docker run ^
--name astrospace-debug ^
-p 9000:9000 ^
-e SECRET_KEY=change-me ^
-e DB_NAME=astrospace ^
-e DB_USER=astrospace ^
-e DB_PASSWORD=change-me ^
-e DB_HOST=host.docker.internal ^
-e DB_PORT=5432 ^
-e TITLE=AstroSpace ^
-e MAX_USERS=2 ^
-e UPLOAD_PATH=/uploads ^
-e ASTROSPACE_DEBUG=1 ^
-v C:\astrospace\uploads:/uploads ^
astrospace --debugThe image starts Gunicorn on 0.0.0.0:9000.
Run the test suite:
python -m pytest -qIf you update Tailwind sources:
cd AstroSpace
npm install
npx tailwindcss -i ./static/input.css -o ./static/styles.cssUseful first-run steps:
- Register the first user. The first account becomes admin.
- Open
My Profileand configure the site title and welcome message. - Create a new post with a preview image and optional FITS/XISF metadata.
- Add or normalize inventory entries from the profile page if needed.
Build and publish a wheel with Hatch:
python -m pip install hatch
python -m hatch build -t wheel
python -m hatch publishAstroSpace/: application packagedocs/: project documentationtests/: automated testsnginx/: example reverse-proxy and compose assets
This project is licensed under the GNU GPL-3.0 License.