AppFlowy-IO / AppFlowy-Cloud

AppFlowy is an open-source alternative to Notion. You are in charge of your data and customizations. Built with Flutter and Rust.
GNU Affero General Public License v3.0
983 stars 207 forks source link

[FR] Provide a Production docker-compose.yml #252

Open bhelm opened 8 months ago

bhelm commented 8 months ago

1~3 main use cases of the proposed feature

what types of users can benefit from using your proposed feature Especially users that want to use the cloud on a public server. But also local LAN users should not expose unnecessary ports.

Additional context I feel that the docker compose file is very naive and the setup tutorial does not mention the risks or give any guidance to secure the installation. All services, even if only used locally, are binding ports to any ip, public or not. redis, pgadmin, postgres... everything listens on the public ip and is therefore reachable over the public internet when deployed on a cloud server. I expect there are basically no port binds needed and if, they should bind to 127.0.0.1 by default.

There is also no guide where to change all the default passwords, i hope they are all in the configuration yaml's, but as a new user, i have to figure it out.

I can see many appflowy cloud instances set up in that way that all services are reachable public and all the passwords are still default, because not everyone notices the problem or is able to solve it by him/herself. Its just so easy to follow the tutorial and have your appflowy cloud working... until someone logs into some service, encrypts everything and wants 0.01 BTC for it.

If you have the docker compose deployed on a public ip, you can go to http://domain.com/minio and login with minioadmin:minioadmin and do just everything with it, delete all buckets, you are admin. i have not tried it, but i expect that this works with other services too.

bhelm commented 8 months ago

I have got it working now. It seems to work... but i dont have the full picture of the application. Its possible that i broke some feature by doing it that way. (im new).

Changes i did:

docker-compose.yml:

.env file:

nginx.conf: commented out /gotrue and /minio.

I also changed the credentials in the configuration directory, but i guess thats not required when the .env are used right?

Suggestions:

On my setup specifically, i preferred to also remove the port bindings on nginx and setup traefik to handle the routing. The advantage of this is, that traefik can be easily configured to issue a valid ssl certificate by letsencrypt and takes care of its renewal. Its nice, but its an additional service and possibly out of scope of what the appflowy docker theployment should provide. Let me know if you want to see a config example.

speed2exe commented 8 months ago

@bhelm

Hello!

We really appreciate your effort to make self hosting more secure. The philosophy that we have is that the setup is super simple to get started. We expect that more experienced folks who are serious in using self-hosted AppFlowy have their own kind of custom setup, we're trying to be unopinionated as much as possible. It is difficult to reach a balance between ease of deployment, time to deploy (more texts in docs isn't necessary better), security and other factors. That being said, I believe we have rooms for improvement to make the self-hosting Docs better. We are planning to have separated docs and templates for different use cases.

Thank you for the suggestions, we'll keep that in mind. Let me address some of the points

add POSTGRES_PORT as .env and to docker-compose.yml (port is currently not configurable)

i have "disabled" the registration by enabling email confirmation without having a mail provider configured. Is there a different way to prevent random bots from registering on my cloud insance? If yes that should be mentioned in the documentation.

Add a warning to the documentation that users should change all the passwords, especially when running on a public server.

It will definitely be interesting to see another alternative router like traefik to replace nginx. Seems like it's also getting more popular these days. PRs are welcome, but's it's just not the priority at this time. However I do agree with the removal of the port bindings to host machine except for nginx. If you have more feedback or suggestions, will be happy to hear those.

Edit: Currently you can't directly select the listening port for postgres when it start via an environmental variable, you have to edit some config files to achieve that.

the admin_frontend is kinda on the edge as optional component. AppFlowy Cloud still run perfectly without it (if you got OAuth Setup). It's more of a convenience thing and for administrative purpose.

ThanatosDi commented 8 months ago

@speed2exe maybe we can add nginx.conf to .gitignore, then put a nginx.conf.example nginx.conf.example: An example configuration file for nginx adhering to the principle of minimalism to prevent inadvertent exposure of services by unaware users, so default is disable admin service like: Minio, PgAdmin and Portainer

before user build Appflowy-Cloud, then need to cp nginx.conf.example to nginx.conf

speed2exe commented 8 months ago

@ThanatosDi Thanks for the suggestion, I think nginx resolver will be better solution: https://nginx.org/en/docs/http/ngx_http_core_module.html#resolver This allow us to put an service and it will resolve the ip at run time. This also means that should a service restart, nginx can then resolve it again, without having to restart.

for the more docker-compose.yml, we'll be unexposing all the ports except for the nginx ones

barelyprofessional commented 3 months ago
* i have "disabled" the registration by enabling email confirmation without having a mail provider configured. Is there a different way to prevent random bots from registering on my cloud insance? If yes that should be mentioned in the documentation.

I found an undocumented environment variable GOTRUE_DISABLE_SIGNUP which fully disables registration but it causes the appflowy_cloud container to fail to start due to it also blocking the setup_admin_account function in application.rs. There appears to be no method to prevent setup_admin_account from running so I can't see any easy ways to disable registration fully until there's an option to skip admin account creation.

Here's the log

{"timestamp":"2024-06-08T11:26:44.887744Z","level":"INFO","fields":{"message":"Connecting to GoTrue with setting: GoTrueSetting { base_url: \"http://gotrue:9999\", ext_url: \"removed\", jwt_secret: Secret([REDACTED alloc::string::String]), admin_email: \"removed\", admin_password: Secret([REDACTED alloc::string::String]) }"},"target":"appflowy_cloud::application"}
{"timestamp":"2024-06-08T11:26:44.898800Z","level":"ERROR","fields":{"error":"code: 403, msg:Signups not allowed for this instance, error_id: None"},"target":"gotrue::api","span":{"name":"sign_up"},"spans":[{"name":"sign_up"}]}
Error: Failed to initialize application state: code: 403, msg:Signups not allowed for this instance, error_id: None

I'm running nginx in front of AppFlowy for handling TLS offloading so I've put in a couple rules to help keep the situation under control

    location /web-api/signup {
        return 403;
    }

This is only effective at stopping the Sign Up button from working.

    location /gotrue/verify {
        if ($args ~ type=signup) {
            return 403;
        }
        proxy_pass http://appflowyip:80;
    }

It's also possible for a new user to be created by attempting to login with a non existent user. The application creates a user out of thin air then either sends a magic link (if auto confirm is on) or sends a confirmation e-mail. This rule is intended to be used with auto confirm enabled and prevents the e-mail address from being confirmed.

You'll still end up with random users clogging up your database and e-mails going out, but they'll never be able to gain access as any subsequent logon attempt will just generate another confirmation e-mail that they cannot confirm.

So if the developers would please make it so GOTRUE_DISABLE_SIGNUP is usable by either checking for it when running setup_admin_account or making it possible to skip admin account creation on startup, I would really appreciate it.

almereyda commented 3 months ago

I have gotten AppFlowy Cloud to run without dependency on the external third-party service from OpenAI and documented some steps in:

It could be used as an inspiration to generate a production-ready compose.yml example for this repository.