> You have trust issues regarding the public key infrastructure? You can request a checksum authenticated version of the installer command from our team!
Our magical bash script `hack/tfw.sh` can handle everything for you. Just run it without any arguments to see usage information.
It is advisable to run the frontend locally while developing to avoid really looooong build times. The `hack/tfw.sh` script handles this for you automagically.
### Doing it manually
In case you **must** do it for some reason you can build & run manually.
Note that this is relatively painful and you should use the `hack/tfw.sh` script when possible.
Building without frontend – execute from project root:
This will create a Docker image without the frontend, which you can run locally. For procudtion builds exclude the argument `--build-arg NOFRONTEND=1` to include a frontend instance.
Running – execute:
`docker run --rm -p 8888:8888 -e AVATAO_SECRET=secret test-tutorial-framework`
In case of a frontendless build (with `--build-arg NOFRONTEND=1`) you will need to run `yarn start` from the `solvable/frontend` directory as well. This will serve the frontend on `http://localhost:4200`.
If you've created a production build (without `--build-arg NOFRONTEND=1`) you don't have to run the frontend locally and you can access the challenge on `http://localhost:8888`.
The repository of a tutorial-framework based challenge is quite similar to a regular challenge.
The project root should look something like this:
```
your_repo
├── solvable
│ └── [TFW based Docker image]
├── controller
│ └── [solution checking]
├── metadata
│ └── [challenge descriptions, writeups, etc.]
└── config.yml
```
The only notable difference is that the `solvable` Docker image is a child image of our baseimage: `solvable/Dockerfile` begins with `FROM eu.gcr.io/avatao-challengestore/tutorial-framework`.
From now on we are going to focus on the `solvable` image.
### Basics of a TFW based challenge
Let us take a closer look on `solvable`:
```
solvable
├── Dockerfile
├── nginx webserver configurations
├── supervisor process manager (init replacement)
├── frontend clone of the frontend-tutorial-framework repo with dependencies installed
└── src challenge source code
```
### nginx
All TFW based challenges expose a single port defined in the `TFW_PUBLIC_PORT` envvar which is set to `8888` by default.
This means that in order to listen on more than a single port we must use a reverse proxy.
Any `.conf` files in the `solvable/nginx/components` will be automatically included in the nginx configuration.
In case you want serve a website or service you must proxy it through `TFW_PUBLIC_PORT`.
This is really easy: just create a config file in `solvable/nginx/components` similar to this one:
```
location /yoururl {
proxy_pass http://127.0.0.1:3333;
}
```
After this you can access the service running on port `3333` at `http://localhost:8888/yoururl`
### supervisor
In most Docker conainers there is a single running process with `PID 1`.
Using TFW you can run as many processes as you want to using supervisord.
To run your own webservice for instance you need to create a config file in `solvable/supervisor/components` similar to this one:
```
[program:yourprogram]
user=user
directory=/home/user/example/
command=python3 server.py
autostart=true
```
This starts the `/home/user/example/server.py` script using `python3` after your container entered the running state (because of `autostart=true`).
### frontend
This is a clone of the `frontend-tutorial-framework` repository with dependencies installed in `solvable/frontend/node_modules`.
### src
This folder contains the source code of the challenge.